Sparklines in JavaScript

You may have seen tiny line graphs embedded in tables of data. They are called sparklines and in this post I will write some simple code to create them as SVG images from an array of data and insert them into an HTML element.

This is a screenshot of the finished demo page.

Most of the table is hard coded but the sparklines are generated by iterating fictitious data, dynamically creating and inserting the SVG images on the fly.

All the source code for this project can be downloaded as a ZIP, or you can clone the Github repository if you prefer.

Source Code Links

ZIP File
GitHub

Let's look first at the sparkline.js file which is at the heart of this project.

sparkline.js

function createSparkline(data, spacing, height, color, elementid)
{
    const min = Math.min(...data);
    const max = Math.max(...data);
    const range = max - min;
    const pixelsperunit = height / range;
    let x = 0;
    let y1 = 0;
    let y2 = 0;

    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");

    svg.setAttributeNS(null, "width", spacing * (data.length - 1));
    svg.setAttributeNS(null, "height", height);

    for(let i = 0, l = data.length - 1; i < l; i++)
    {
        y1 = height - ((data[i] - min) * pixelsperunit);
        y2 = height - ((data[i+1] - min) * pixelsperunit);
        drawLine(svg, x, y1, x + spacing, y2, color);
        x += spacing;
    }

    document.getElementById(elementid).appendChild(svg);
}

function drawLine(element, x1, y1, x2, y2, color)
{
    const line = document.createElementNS("http://www.w3.org/2000/svg", "line");

    line.setAttributeNS(null, "x1", x1);
    line.setAttributeNS(null, "y1", y1);
    line.setAttributeNS(null, "x2", x2);
    line.setAttributeNS(null, "y2", y2);

    line.setAttributeNS(null, "stroke", color);
    line.setAttributeNS(null, "stroke-width", 1);

    element.appendChild(line);
}

The createSparkline function takes the following arguments:

  • data - a numeric array
  • spacing - the distance between data points in pixels
  • height - the height of the graph in pixels
  • color - in an SVG compatible format, eg. "#FF0000"
  • elementid - the ID of the element where the sparkline is to be inserted

Firstly we need to find the minimum and maximum data values, which is done with Math.min and Math.max. These are variadic functions which take any number of individual values so we need to spread the data array. Next we calculate the range and finally use this to calculate a variable called pixelsperunit which is the scaling factor from actual data values to pixels. There are also some coordinate variables declared here for use further down.

Next we create an SVG element and set its height and width. The height is specified by the calling code but the width is calculated from the spacing and number of data points.

We then iterate the data. Note that within the loop we use the current and next value to draw a line between the two, therefore we only need to loop to the last item but one.

After calculating the y coordinates for the two neighbouring values we draw a line between the two points using the separate drawLine function before incrementing the x coordinate by the spacing.

As the end point of one line is the starting point of the next most y coordinates are calculated twice. As sparklines are typically only used on very small datasets this shouldn't be a problem and saves the slightly fiddly code needed to preserve the second y coordinate through iterations.

Finally we just need to stick the SVG element into the specified element.

The drawLine function is very straightforward, creating a line and setting its properties from the function arguments before adding it to its parent.

Now let's look at the code for sparklinedemo.js.

sparklinedemo.js

window.onload = function()
{
    const prices = getPrices();

    for(price of prices)
    {
        createSparkline(price.prices, 16, 16, "#FF0000", price.code);
    }
}


function getPrices()
{
    const prices = [{code: "gs", prices: [401.5, 443.9, 422.2, 432.7, 483.1, 501.8, 538.4, 522.7]},
                    {code: "nm", prices: [187.5, 162.9, 151.0, 188.1, 224.4, 218.9, 201.5, 192.6]},
                    {code: "ca", prices: [855.3, 841.0, 801.5, 818.9, 832.3, 850.7, 880.6, 895.2]},
                    {code: "os", prices: [255.5, 285.9, 310.8, 322.4, 305.1, 276.7, 260.0, 292.4]},
                    {code: "ta", prices: [390.4, 485.9, 466.7, 380.2, 360.7, 420.8, 441.4, 475.9]},
                    {code: "xs", prices: [62.4, 52.9, 44.2, 64.8, 74.0, 75.2, 95.5, 102.7]}];

    return prices;
}

The data is hard-coded into an array of objects. Each object has a code property which is the same as the id of the <td> element of the table where we want the sparkline inserted. The prices property is simply an array of numeric data.

Within window.onload we get the raw data and iterate it, calling createSparkline for each company. As I mentioned price.code is also the element ID.

That's it! Open sparklinedemo.htm in your browser to see the results.

This project achieves my original objective of creating the simplest possible graph, which can be comprehended at a glance despite its diminutive size. I have seen a few sparklines which attempt to include more detail which clearly isn't wise and contravenes any minimalist philosophy which you might care to attach to the sparkline concept.

However, I have also see sparkline-sized bar graphs and pie charts which, as long as they are kept simple, can be just as intuitive and easy to comprehend so maybe I will extend this solution to include one or two more types.