Canvas sparklines

I like sparklines a lot. Tufte describes a sparkline as:

…a small intense, simple, word-sized graphic with typographic resolution.

Four years ago, I added sparklines to Huffduffer using Google’s chart API. That API comes in two flavours: a JavaScript API for client-side creation of graphs, and image charts for server-side rendering of charts as PNGs.

The image API is really useful: there’s no reliance on JavaScript, it works in every browser capable of displaying images, and it’s really flexible and customisable. Therefore it is, of course, being deprecated.

The death warrant for Google image charts sets the execution date for 2015. Time to start looking for an alternative.

I couldn’t find a direct equivalent to the functionality that Google provides i.e. generating the images dynamically on the server. There are, however, plenty of client-side alternatives, many of them using canvas.

Most of the implementations I found were a little heavy-handed for my taste: they either required jQuery or Processing or both. I just wanted a quick little script for generating sparklines from a dataset of numbers. So I wrote my own.

I’ve put my code up on Github as Canvas Sparkline.

Here’s the JavaScript. You create a canvas element with the dimensions you want for the sparkline, then pass the ID of that element (along with your dataset) into the sparkline function:

sparkline ('canvasID', [12, 18, 13, 12, 11, 15, 17, 20, 15, 12, 8, 7, 9, 11], true);

(that final Boolean value at the end just indicates whether you want a red dot at the end of the sparkline).

The script takes care of normalising the values, so it doesn’t matter how many numbers are in the dataset or whether the range of the numbers is in the tens, hundreds, thousands, or hundreds of thousands.

There’s plenty of room for improvement:

  • The colour of the sparkline is hardcoded (50% transparent black) but it could be passed in as a value.
  • All the values should probably be passed in as an array of options rather than individual parameters.

Feel free to fork, adapt, and improve.

The sparklines are working quite nicely, but I can’t help but feel that this isn’t the right tool for the job. Ideally, I’d like to keep using a server-side solution like Google’s image charts. But if I am going to use a client-side solution, I’m not sure that canvas is the right element. This should really be SVG: canvas is great for dynamic images and animations that need to update quite quickly, but sparklines are generally pretty static. If anyone fancies making a lightweight SVG solution for sparklines, that would be lovely.

In the meantime, you can see Canvas Sparkline in action on the member profiles at The Session, like here, here, here, or here.

Update: Ask and thou shalt receive. Check out this fantastic lightweight SVG solution from Stuart—bloody brilliant!

Have you published a response to this? :


Jeremy Keith calls out for “a lightweight SVG solution for sparklines”, which seems like it would be a nice thing to have.

Like this, kinda:

Just grab and then use it in your pages* like this:

<embed src=",8,1,8,1,8" width=100 height=15>

This works by having the SVG itself contain JavaScript which parses its own querystring. Therefore, you need to use <embed>, not <img>, because embedded script doesn’t run in SVGs used as images.

# Sunday, December 30th, 2012 at 8:18pm

Jeremy Keith calls out for “a lightweight SVG solution for sparklines”, which seems like it would be a nice thing to have. Like this, kinda:

Just grab and then use it in your pages* like this:

<embed src=",8,1,8,1,8" width=100 height=15>

This works by having the SVG itself contain JavaScript which parses its own querystring. Therefore, you need to use <embed>, not <img>, because embedded script doesn’t run in SVGs used as images.

# Saturday, November 22nd, 2014 at 5:05pm

At IndieWebCamp Nürnberg this weekend, Jeremy added sparklines for his site’s posting frequency. To do this he used Stuart’s SVG sparkline generator (improving on previous efforts). Here’s an example:

A 100-point sparkline.

I’m enough of an SVG fan to have made to share them, so I was intrigued by this. I like the clarity of the data points being in the URL, but looking at the generated SVG, that clarity had gone. The point sequence 59,80,80,100 becomes instead

<line x1="0.49504950495049505%" x2="0.49504950495049505%" y1="39.1578947368421%" y2="39.1578947368421%" stroke="rgba(0,0,0,0.5)" stroke-width="1"/> <line x1="0.49504950495049505%" x2="1.4455445544554455%" y1="39.1578947368421%" y2="17.05263157894737%" stroke="rgba(0,0,0,0.5)" stroke-width="1"/> <line x1="1.4455445544554455%" x2="2.396039603960396%" y1="17.05263157894737%" y2="17.05263157894737%" stroke="rgba(0,0,0,0.5)" stroke-width="1"/> <line x1="2.396039603960396%" x2="3.3465346534653464%" y1="17.05263157894737%" y2="-4%" stroke="rgba(0,0,0,0.5)" stroke-width="1"/>

You can see that the original data has been transformed with high precision into percentages, and that each datapoint occurs twice as the start and end of a line. This made me wonder if the SVG could use the datapoints directly, as it is after all a sequence of co-ordinates. So I adapted the code to generate a polyline directly, giving:

The same 100 points in a sparkline.

Now the points 59,80,80,100 becomes a clearer

<polyline points="0,59 1,80 2,80 3,100" stroke="rgba(0,0,0,1)" stroke-width=".5%" fill="none" transform="matrix(1 0 0 -1 0 105)" />

Indeed, the whole line now looks like this:

<polyline points="0,59 1,80 2,80 3,100 4,68 5,62 6,87 7,72 8,42 9,49 10,58 11,53 12,57 13,51 14,42 15,32 16,37 17,30 18,24 19,38 20,57 21,29 22,18 23,32 24,38 25,24 26,24 27,24 28,20 29,21 30,29 31,32 32,26 33,18 34,32 35,36 36,30 37,36 38,29 39,32 40,29 41,28 42,41 43,20 44,28 45,58 46,18 47,24 48,16 49,17 50,22 51,17 52,22 53,21 54,12 55,22 56,14 57,13 58,11 59,20 60,16 61,16 62,18 63,12 64,28 65,28 66,32 67,16 68,16 69,24 70,16 71,20 72,14 73,18 74,12 75,26 76,17 77,11 78,30 79,16 80,9 81,20 82,42 83,13 84,13 85,24 86,17 87,13 88,20 89,12 90,14 91,13 92,14 93,71 94,82 95,20 96,16 97,20 98,22 99,17 100,5" stroke="rgba(0,0,0,1)" stroke-width=".5%" fill="none" transform="matrix(1 0 0 -1 0 105)" />

With the datapoints directly readable, and not changed to arbitrary precision.

To make this work, I had to do a little bit of mathematical trickery. I set the viewBox of the SVG to the bounding box of the co-ordinates (in this case viewBox="0 5 100 95" where 0 is the lowest x value, 5 the lowest y value, 100 the width and 95 the height) and set the stroke-width as a percentage of the viewport, so it isn’t dependent on the scale of the datapoints.

So far so good, except that SVG co-ordinates go down the page, not up, so the sparkline is upside down. I need to invert the y axis. But if I do that, the line is outside the bounding box. So we need to move the line back into the frame by adding the height plus twice the lowest y value. Here’s the javascript that does that:

var height = mx-mn; var width = x-1;
var offset = height+mn2; // flip co-ordinates and move back into frame
ln.setAttribute("transform","matrix(1 0 0 -1 0 " + offset +")");
svgRoot.setAttribute("viewBox","0 " + mn +" "+ width + " " + height);

Now, I could just set the y value of the viewBox to -(height+mn2) but I think that this is clearer.

Like Stuart’s original, to use these dynamically you need to use <embed&gt: rather than <img&gt: eg

<embed src=",0,1,1,4,6,9,6,5,0,1,2,5,2,2,3,4,5,2,2,2,3,6,3,5,3,7,6,5,2,3,2," width="200" height="15">
See IndieNews (function () { var sn = document.createElement(“script”), s = document.getElementsByTagName(“script”)[0], url; url = document.querySelectorAll ? document.querySelectorAll(“link[rel~=canonical]”) : false; url = url && url[0] ? url[0].href : false; sn.type = “text/javascript”; sn.async = true; sn.src = “//” + encodeURIComponent(url || window.location); s.parentNode.insertBefore(sn, s); }());

# Monday, April 18th, 2016 at 12:00am

Added @adactio’s Canvas Sparklines to my site, to further visually demonstrate the vast spaces of time between my posts! Next step: create less vast spaces of time between my posts (read: publish more).

# Tuesday, May 15th, 2018 at 9:03am

Previously on this day

10 years ago I wrote The change you want to see

Make the poop or get off the pot.

19 years ago I wrote West Pier collapses

I leave Brighton for one week and look what happens.

20 years ago I wrote 8" Star Trek Plate Wesley Crusher

Come on, admit it: you’d love to find a commemorative plate of yourself on eBay, bid on it and win.

20 years ago I wrote Stranger In A Strange Land

Here is an excellent article by Christopher Hitchens about "The dismay of an honorable man of the left".

20 years ago I wrote Gorey Movie

Here’s something interesting I stumbled upon while browsing through a bunch of "home movies" that people have posted up at