DEV Community

Brandon Weaver
Brandon Weaver

Posted on

Graphing Data to a Canvas

Let's say we have a data structure similar to the following, and we want to graph each set of data for a visual comparison.

const dataSets = [
    {
        color: "#00f",
        data: [5,10,25,15,20]
    },
    {
        color: "#f00",
        data: [0,20,15,25,10]
    }
];
Enter fullscreen mode Exit fullscreen mode

I'll assume we have a reference to a canvas and context throughout this example. If you want to learn more about this, you can take a look at my previous entry here.

What will we need in order to create a visual representation of these two sets?

First, we'll need to find the highest and lowest value among all sets.

let yHigh = Number.MIN_VALUE;
let yLow = Number.MAX_VALUE;
for (const dataSet of dataSets) {
    for (const datum of dataset.data) {
        if (datum > yHigh) yHigh = datum;
        if (datum < yLow) yLow = datum;
    }
}
Enter fullscreen mode Exit fullscreen mode

Next, we'll need to iterate over each set and figure out the x, and y-axis of each initial value as it relates to our canvas.

The x-axis is easy enough, as it's simply 0. We will, however, also need to divide the canvas width by one less than our set length (since the first value of x will be 0), and add this value to x as we draw the set.

for (const dataSet of dataSets) {
    let x = 0;
    const xStep = canvas.width / (dataSet.data.length - 1);

    ...
Enter fullscreen mode Exit fullscreen mode

Now, we need to figure out the y value; this involves finding the percentage of each value between the highest and lowest values, and setting y to the value of that percentage relative to our canvas height.

    ...

    let yPercentage = (dataSet.data[0] - yLow) / (yHigh - yLow) * 100;
    let y = canvas.height - canvas.height / 100 * yPercentage;

    ...
Enter fullscreen mode Exit fullscreen mode

Notice that we're also subtracting the value of yLow from the datum before calculating the percentage; this ensures that, if our lowest value is 10, and our canvas height is 100, our lowest value will be drawn to 100 on the canvas, rather than 90. Without this subtraction our data will be drawn to the canvas as if the lowest value is 0. We also subtract our y value from the canvas height to prevent our graph from being inverted since we're drawing the low datum on what is technically high on the canvas.

We'll set strokeStyle of our context to the sets color, and call beginPath to prevent our lines from being redrawn using the last stroke style.

    ...

    context.strokeStyle = dataSet.color;
    context.beginPath();

    ...
Enter fullscreen mode Exit fullscreen mode

Next, we simply iterate over the data, starting from the second index (since we already have the first point), stepping along the x-axis by adding the value of xStep to x, and finding y for each datum just as we did with the first.

    ...

    for (let i = 1; i < dataSet.data.length; i++) {
        context.moveTo(x, y);
        x += xStep;

        yPercentage = (dataSet.data[i] - yLow) / (yHigh - yLow) * 100;
        y = canvas.height - canvas.height / 100 * yPercentage;

        context.lineTo(x, y);
        context.stroke();
    }
}
Enter fullscreen mode Exit fullscreen mode

Below is a nearly identical example I made, which uses the resize event of the window to allow the canvas to fill its container by setting the width and height to the offset width and height, and redrawing the data.

Top comments (0)