<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ian Webster</title>
    <description>The latest articles on DEV Community by Ian Webster (@iwebst).</description>
    <link>https://dev.to/iwebst</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F145680%2F94e7a325-9b99-4536-9e9b-ed45539f0e38.jpeg</url>
      <title>DEV Community: Ian Webster</title>
      <link>https://dev.to/iwebst</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iwebst"/>
    <language>en</language>
    <item>
      <title>Building a Replacement for Google Image Charts</title>
      <dc:creator>Ian Webster</dc:creator>
      <pubDate>Fri, 15 Mar 2019 21:18:13 +0000</pubDate>
      <link>https://dev.to/iwebst/building-a-replacement-for-google-image-charts-153e</link>
      <guid>https://dev.to/iwebst/building-a-replacement-for-google-image-charts-153e</guid>
      <description>&lt;p&gt;A couple weeks ago I learned that &lt;a href="https://developers.google.com/chart/image/" rel="noopener noreferrer"&gt;Google Image Charts&lt;/a&gt; is shutting down, leaving a lot of people in the lurch.  Although the API has been deprecated for many years, many developers had not made the switch.&lt;/p&gt;

&lt;p&gt;Why do &lt;em&gt;Image Charts&lt;/em&gt; matter?  There are plenty of graphing libraries like Chart.js, plotly, d3, and so on.  The difference is that these libraries require Javascript, but Image Charts are necessary for embeddable, non-Javascript environments such as email, SMS, and certain types of reports.&lt;/p&gt;

&lt;p&gt;This post describes the process of creating an open source image chart offering called QuickChart.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you don't want to read the whole thing, skip to the final result: the &lt;a href="https://quickchart.io/" rel="noopener noreferrer"&gt;image chart web service&lt;/a&gt; (called QuickChart) and &lt;a href="https://github.com/typpo/quickchart" rel="noopener noreferrer"&gt;source code&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: What's the best way to define a chart?
&lt;/h3&gt;

&lt;p&gt;The old Google Image Charts API was arcane, built for a time when browsers couldn't support long URLs.  &lt;/p&gt;

&lt;p&gt;This meant that you had to sacrifice readability and also learn a custom format.  For example, the following URL:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

https://chart.googleapis.com/chart?cht=bvg&amp;amp;chs=250x150&amp;amp;chd=t:5,30,30,50,80,200&amp;amp;chxt=x,y&amp;amp;chxs=0,ff0000,12,0,lt|1,0000ff,10,1,lt


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Produces this graph:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfggf87hk17h4ish2fbr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfggf87hk17h4ish2fbr.png" alt="Google Image Charts graph example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It gets more complicated from here.  The API supported a "simple encoding format" that allowed users to encode integer values between 0 and 61 as single characters.  Characters A-Z would encode integers 0 through 25, a-z encodes 26 through 51, and the digits 0-9 encode the remaining values through 61.  You'd wind up with URLs like &lt;code&gt;?chd=s:BTb19_,Mn5tzb&lt;/code&gt; that encode a handful of two-digit numbers.&lt;/p&gt;

&lt;p&gt;There is an "extended encoding format" that include punctuation.  For example, &lt;code&gt;-.&lt;/code&gt; is equivalent to the number 4,031.  Easy, right?&lt;/p&gt;

&lt;p&gt;I decided this was bad.  Imagine coming across this URL in code and trying to figure out what it meant.  Imagine writing your own number encoding script, only to find that your data contains a number larger than 61 and having to rewrite your encoder.&lt;/p&gt;

&lt;p&gt;The Image Charts API was built in the early 2000s.  Nowadays browsers can do much better.  For this reason I decided to use &lt;a href="https://www.chartjs.org/" rel="noopener noreferrer"&gt;Chart.js&lt;/a&gt; as inspiration.  Chart.js is very popular and has a clear API for defining charts:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
  type: 'bar',
  data: {
    labels: [0,1,2,3,4,5],
    datasets: [{
      data: [5,30,30,50,80,200]
    }]
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 2: Putting it together
&lt;/h3&gt;

&lt;p&gt;We're using Chart.js, but that library produces charts dynamically via Javascript instead of images.  That's a showstopper because most users will want to embed static images in email.&lt;/p&gt;

&lt;p&gt;The good news is that Chart.js uses HTML5 Canvas, and canvas can be converted into an image.  &lt;/p&gt;

&lt;p&gt;The invention of Node made it much easier to run Javascript on the server side.  A server side canvas implementation called &lt;a href="https://github.com/Automattic/node-canvas" rel="noopener noreferrer"&gt;node-canvas&lt;/a&gt; followed.  I evaluated a couple server-side Chart.js wrapper that used node-canvas to render the image and settled on &lt;a href="https://github.com/SeanSobey/ChartjsNodeCanvas" rel="noopener noreferrer"&gt;chartjs-node-canvas&lt;/a&gt; with some modifications to make it more memory efficient.&lt;/p&gt;

&lt;p&gt;This meant that I could take a Chart.js config like the one above and render it on the server side.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Building the web service
&lt;/h3&gt;

&lt;p&gt;The web service is fairly straightforward.  It's just an &lt;code&gt;express&lt;/code&gt; app that hooks into my patched &lt;code&gt;chartjs-node-canvas&lt;/code&gt; library.&lt;/p&gt;

&lt;p&gt;Upon implementation, I realized there were some default Chart.js options that I would like to apply.  For example, line and bar chart axes should start at 0 by default.  I also added a nice color palette and a Chart.js plugin that added the option for data labels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The result is a single endpoint, &lt;code&gt;https://quickchart.io/chart?c=&lt;/code&gt;, that takes a Chart.js configuration and renders it as a PNG image.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's take our simple chart JSON above and send it into the endpoint:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quickchart.io/chart?c={type:'bar',data:{labels:[0,1,2,3,4,5],datasets:[{data:[5,30,30,50,80,200]}]}}" rel="noopener noreferrer"&gt;https://quickchart.io/chart?c={type:'bar',data:{labels:[0,1,2,3,4,5],datasets:[{data:[5,30,30,50,80,200]}]}}&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This URL loads the following image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkzs9b649ozkpg1loo9fq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkzs9b649ozkpg1loo9fq.png" alt="QuickChart image chart example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perfect!&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Getting more creative
&lt;/h3&gt;

&lt;p&gt;It's relatively straightforward to build customized charts based on the Chart.js documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpaisabo0vxuaczs8tbve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpaisabo0vxuaczs8tbve.png" alt="Customized image chart with QuickChart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point we're limited only by the Chart.js API, which is very flexible. &lt;br&gt;
 This chart uses custom background colors, title styling, legend position, stacked series, axes labels, and data labels:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
  type: 'bar',
  data: {
    labels: ['January', 'February', 'March', 'April', 'May'],
    datasets: [{
      label: 'Dogs',
      backgroundColor: 'chartreuse',
      data: [ 50, 60, 70, 180, 190 ]
    }, {
      label: 'Cats',
      backgroundColor: 'gold',
      data: [ 100, 200, 300, 400, 500 ]
    }]
  },
  options: {
    title: {
      display: true,
      text: 'Total Revenue (billions)',
      fontColor: 'hotpink',
      fontSize: 24,
    },
    legend: {
      position: 'bottom',
    },
    scales: {
      xAxes: [{stacked: true}],
      yAxes: [{stacked: true}],
    },
    plugins: {
      datalabels: {
        display: true,
        font: {
          style: 'bold',
        },
      },
    },
  },
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's quite a bit more JSON than our simple example, but the specification is &lt;a href="https://www.chartjs.org/docs/latest/configuration/" rel="noopener noreferrer"&gt;well-documented&lt;/a&gt; and uses a widespread standard.  Note that for more complex configurations, we need to URL-encode the JSON object before passing it to the API (e.g. by using Javascript's &lt;code&gt;encodeURIComponent&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We can also use any of the chart types provided by Chart.js.  For example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quickchart.io/chart?c={type:'pie',data:{labels:['January','February','March','April',%20'May'],%20datasets:[{data:[50,60,70,180,190]}]}}" rel="noopener noreferrer"&gt;https://quickchart.io/chart?c={type:'pie',data:{labels:['January','February','March','April', 'May'], datasets:[{data:[50,60,70,180,190]}]}}&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above URL yields:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fquickchart.io%2Fchart%3Fbkg%3Dwhite%26c%3D%7Btype%3A%2527pie%2527%2Cdata%3A%7Blabels%3A%5B%2527January%2527%2C%2527February%2527%2C%2527March%2527%2C%2527April%2527%2C%2520%2527May%2527%5D%2Cdatasets%3A%5B%7Bdata%3A%5B50%2C60%2C70%2C180%2C190%5D%7D%5D%7D%7D" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fquickchart.io%2Fchart%3Fbkg%3Dwhite%26c%3D%7Btype%3A%2527pie%2527%2Cdata%3A%7Blabels%3A%5B%2527January%2527%2C%2527February%2527%2C%2527March%2527%2C%2527April%2527%2C%2520%2527May%2527%5D%2Cdatasets%3A%5B%7Bdata%3A%5B50%2C60%2C70%2C180%2C190%5D%7D%5D%7D%7D" alt="Pie image chart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Making it open source
&lt;/h3&gt;

&lt;p&gt;I named this web service QuickChart and put it online at &lt;a href="https://quickchart.io/" rel="noopener noreferrer"&gt;QuickChart.io&lt;/a&gt;.  It's very cheap to run so I've made the image chart generation service available for free with no limitations.&lt;/p&gt;

&lt;p&gt;Separately, I've open-sourced the project over on &lt;a href="https://github.com/typpo/quickchart" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.  I would welcome involvement and contributions from the rest of the community!&lt;/p&gt;

&lt;p&gt;Here are some thoughts on where we can take this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a library of useful chart templates&lt;/li&gt;
&lt;li&gt;Create a "short url" feature that maps complex configurations to a simple URL&lt;/li&gt;
&lt;li&gt;Support other kinds of charts - perhaps even maps or other more advanced visualizations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a strong base for a flexible and reliable image chart generation service. &lt;br&gt;
 There are lots of possibilities and I'm excited to continue building!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>visualization</category>
      <category>api</category>
    </item>
  </channel>
</rss>
