Draw a Line Graph Using HTML5 Canvas

Posted on June 19th, 2011 in category: Tutorials

The canvas element is one of the new hot features of HTML5, supported by the newer web browsers such as Internet Explorer 9, Firefox 3.6+, Safari 4+ and Chrome etc. Since a lot of people out there is still in the Internet Explorer 7 and 8 era canvas might not be too useful yet. But still it’s really fun to play around with

In this tutorial I will walk through how to create a quite simple yet good looking scalable line graph. Demo and download link can be found at the bottom of the article.

Step 1. Creating the HTML

We start of by creating the HTML, there’s really not much new here so I won’t describe it very closely. The interesting part here is the canvas element, this is where we’re going to draw out line graph, the height and width attributes sets the canvas and graph size.

<!DOCTYPE html>
<html>
    <head>
        <title>My Line Graph</title>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.min.js"></script>
        <script>
        </script>
    </head>
    <body>
        <canvas id="graph" width="300" height="200">   
        </canvas> 
    </body>
</html>

The rest of the coding will be done inside the empty script tag.

Step 2. JavaScript Variables

We’re going to use a few global JavaScript variables. One to save our graph object. Two variables which will define our X and Y paddings, the X and Y paddings are the space that is not usable by the graph itself, this space contains the X and Y axises and the labels. And the last variable contains our graph data in a JSON object.

var graph;
var xPadding = 30;
var yPadding = 30;

var data = { values:[
        { X: "Jan", Y: 12 },
        { X: "Feb", Y: 28 },
        { X: "Mar", Y: 18 },
        { X: "Apr", Y: 34 },
        { X: "May", Y: 40 },
]};

Step 3. Support Functions

Before starting to draw we will need some JavaScript functions to make the drawing simple. One to determine the max Y value in our data variable, this function loops through our data to find the highest Y value, it the rounds the value to the upper ten based value.

The other two functions will help us to find out the position of the X and Y values depending on padding, max Y value and number of values, There’s some math in these functions, but since this tutorial is more about drawing using the canvas I won’t explain them further.

function getMaxY() {
    var max = 0;
    
    for(var i = 0; i < data.values.length; i ++) {
        if(data.values[i].Y > max) {
            max = data.values[i].Y;
        }
    }
    
    max += 10 - max % 10;
    return max;
}

function getXPixel(val) {
    return ((graph.width() - xPadding) / data.values.length) * val + (xPadding * 1.5);
}

function getYPixel(val) {
    return graph.height() - (((graph.height() - yPadding) / getMaxY()) * val) - yPadding;
}

Step 4. Drawing The Graph

Well, all the boring preparations is done, now we can start drawing our graph.

The first thing we need to do is getting the canvas context, this is the interface to our canvas which we’ll use to draw our graph. Note that we’re using graph[0] instead of just graph, this is because you can’t get the context from a jQuery object. You need to use the standard JavaScript object, graph[0] returns the same object as if we would use document.GetElementById(‘graph’).

$(document).ready(function() {
    graph = $('#graph');
    var c = graph[0].getContext('2d');
});

The rest of our coding will be inside the ready event. This makes sure were not trying to draw our graph until our document has fully loaded.

Next we set some of the properties to our context, such as the width and the color of the lines we want to draw and the font and text align to use.

c.lineWidth = 2;
c.strokeStyle = '#333';
c.font = 'italic 8pt sans-serif';
c.textAlign = "center";

Now let’s draw the X and Y axises. We will draw the using a path which is essentially a number of lines after each other.

First we move to the top and 30px (the xPadding) from the left of our graph. Then we draw a line straight down to the bottom of our graph but leaves 30px (the Y padding) of free space in the bottom, This will form our Y axis. Then we draw a line straight to the right to form our X axis. The stroke function tells the context to stroke out the line in our canvas.

c.beginPath();
c.moveTo(xPadding, 0);
c.lineTo(xPadding, graph.height() - yPadding);
c.lineTo(graph.width(), graph.height() - yPadding);
c.stroke();

If you test it in your browser you should see something like this:

Next we’ll draw our texts along the X axis. To do this we use the fillText function to do this, the first parameter is the string from our data list. The second is the X position, now we need to use one of our support functions to find our where the X values will be positioned. Last we have the Y position, this is 20px below the X axis.

for(var i = 0; i < data.values.length; i ++) {
    c.fillText(data.values[i].X, getXPixel(i), graph.height() - yPadding + 20);
}

Now the graph looks like this:

To draw the Y axis values we’re need to change some text properties. We set the text align to right and the textBaseLine to middle this will vertically align the text to the middle.

Then we draw the every tenth Y value in a for loop until we get to the max Y value present in the graph.

c.textAlign = "right"
c.textBaseline = "middle";

for(var i = 0; i < getMaxY(); i += 10) {
    c.fillText(i, xPadding - 10, getYPixel(i));
}

Now the graph looks like this:

The tingletangle is drawn, let’s start drawing the actual graph. We start by changing the strokeStyle since I want the line to be red. Then we tell the context that we want to begin a path and move to the first point in our data list.

Next we draw the line to all the points in the data list and lastly we tell the context to stroke out our path. The getXPixel and getYPixel helps us to find out were the points are located.

c.strokeStyle = '#f00';
c.beginPath();
c.moveTo(getXPixel(0), getYPixel(data.values[0].Y));

for(var i = 1; i < data.values.length; i ++) {
    c.lineTo(getXPixel(i), getYPixel(data.values[i].Y));
}
c.stroke();

And now the graph looks almost finished:

The last thing to do is to draw the small black dots at each value point. Since we’re going to fill and not stroke the points we need to set the fillStyle, I’m going for a dark grey color.

Next we loop through our data list yet again. For each item in the list we begin a new path. Then we draw a circled arc, the two first parameters are the X and Y values of the center point, the third paramter is the radius, the fourth and fifth parameter is the starting and ending angle, the last parameter tells the context to draw clockwise or counterclockwise which doesn’t matter in this case. Lastly we call the fill function to tell the context to fill our arc which makes it a dot.

c.fillStyle = '#333';

for(var i = 0; i < data.values.length; i ++) {  
    c.beginPath();
    c.arc(getXPixel(i), getYPixel(data.values[i].Y), 4, 0, Math.PI * 2, true);
    c.fill();
}

If you think it is too small or maybe even too big just change the width and height attribute of the canvas tag and the graph will scale to fit it.

That’s all about the canvas element for now, your finished graph should look like this:

Demo

Try out the example here: Demo

Download

Download the source from here: Download

Comments

  • Nasim Saifi, January 28th, 2012

    Use Graph. According to given value the graph will change and the points are also drag gable according to that the value of the textbox also change (Vise-Versa) .

  • Ron, May 21st, 2012

    I’m creating a graph for swimming times which are very small in difference but obviously important. So all the values are like: 36.37, 36.42, 37.01, etc. To show the real difference in time I would like to start the Y axis at the minimum number (ie. 36 – or maybe one second below) instead of zero.

    I’m thinking I need to create a variation of the getMaxY function like so (have no idea if this correct):

    // Returns the min Y value in our data list
    function getMinY() {
    var min = 0;

    for(var i = 0; i min) {
    min = data.values[i].Y;
    }
    }

    min += 10 – min % 10;
    return min;
    }

    and insert getMinY() into the script where??

    Thanks!

  • Ron, May 21st, 2012

    Sorry, one more thing – I’m trying to have the label on the x axis have 2 lines (Time on the 1st line and date on the 2nd line) but can’t seem to get it right. Have tried “\r”, “\n”, , etc. Is there a trick to this?

  • Angelos, December 24th, 2012

    I am trying to draw a second line. How can I do it?

  • Salvatore Capolupo, February 21st, 2014

    Very useful, thanks very much :)

  • Thulasi, March 10th, 2014

    Very useful, Searching for the same.. thanks

  • Diego, April 16th, 2014

    Thanks very much, God bless you

  • Brian, May 29th, 2014

    Awesome, thanks!

  • Nidhi, October 20th, 2014

    Thank, just what I needed for a website!

  • mullboy, October 20th, 2014

    Is there any jquery in this code.

Trackbacks

5 − = four