Join Now! It's FREE. Get full access and benefit from this site
Friday, 05 June 2009 12:05
Combine the versatile canvas element with the robust jQuery library to create a bar graphing plugin. In this first part, we are going to code the core logic of the plugin as a standalone version.
Today, we are going to create a bar graphing plugin. Not an ordinary plugin, mind you. We’ll show some jQuery love to the canvas element to create a very robust plugin.
In this two-part article, we will start from the beginning by implementing the logic of the plugin as a standalone script, refactoring it into a plugin and then finally adding all the additional eye candy on top of the plugin code. In this first part, we are going to deal solely with implementing the core logic.
Need an example before we get started? Here you go!

Satisfied? Interested yet? Let’s start.
Our plugin needs to accomplish some basic things whilst not doing some other things. Let me elucidate:
As we are delving into the world of cutting-edge, still not fully specified, technology, we do have some dependencies. For the canvas element to work, most modern browsers are sufficient. But since we make use of the new text rendering API, we need newer builds. Browsers utilizing the Webkit engine r433xx and above or the Gecko engine 1.9.1 and above should be excellent platforms for the plugin. I recommend grabbing a nightly build of Chromium or Firefox.
I’d like to mention that our plugin is purely for learning purposes. This plugin is in no way meant to replace other full-fledged graphing plugins like Flot, Plotr and such. Also the code is going to be as verbose as possible. You could write far, far more efficient code but for the sake of learning, everything is going to be as uncomplicated as possible. Feel free to refactor it in favor of efficiency in your production code.
<!DOCTYPE html> <html lang="en-GB"> <head> <title>OMG WTF HAX</title> </head> <body> <table width="200" border="0" id="data"> <tr> <th>Year</th> <th>Sales</th> </tr> <tr> <td>2009</td> <td>130</td> </tr> <tr> <td>2008</td> <td>200</td> </tr> <tr> <td>2007</td> <td>145</td> </tr> <tr> <td>2006</td> <td>140</td> </tr> <tr> <td>2005</td> <td>210</td> </tr> <tr> <td>2004</td> <td>250</td> </tr> <tr> <td>2003</td> <td>170</td> </tr> <tr> <td>2002</td> <td>215</td> </tr> <tr> <td>2001</td> <td>115</td> </tr> <tr> <td>2000</td> <td>135</td> </tr> <tr> <td>1999</td> <td>110</td> </tr> <tr> <td>1998</td> <td>180</td> </tr> <tr> <td>1997</td> <td>105</td> </tr> </table> <canvas id="graph" width="550" height="220"></canvas> <script type="text/javascript" src="/jquery.js"></script> <script type="text/javascript" src="/mocha.js"></script> </body> </html>
Nothing special about the markup. I’ll do a quick overview anyway.
Before we start the Javascript, let me explain the canvas coordinate system. The top-left corner acts as the origin i.e. (0, 0). Points are then measured with respect to the origin with x increasing along the right and y increasing along the left. For the mathematically inclined, we are effectively working in the 4th quadrant except that we take the absolute value of y instead of its negative value. If you have worked with graphics in other languages you should be at home here.

Canvas’ rectangle rendering routine will be used extensively through out the article to render the bars, the grid and some other elements. With that in mind, let’s take a short look at those routines.
Of the three routines available, we will be using the fillRect and strokeRect methods. The fillRect method actually fills the rendered rectangle while the strokeRect method only strokes the rectangles. Other than that, both the methods take the same parameters.

As always, I highly recommend you to download the source code and have it on the side for reference. It’s easier to look at the big picture and parse each function one by one than look at each function individually and then create the big picture in your mind.
var
barSpacing = 20,
barWidth = 20,
cvHeight = 220,
numYlabels = 8,
xOffset = 20,
gWidth=550,
gHeight=200;
var maxVal,
gValues = [],
xLabels = [],
yLabels = [];
var cv, ctx;
These variables hold hard coded values to aid us in positioning and layout of the graph and the individual bars.

With jQuery’s strong selector engine it becomes very easy for us to get the data we need. Here we have a number of ways to access the necessary elements. Let me explain a few below:
$("tr").children("td:odd").each(function(){
//code here
});
The simplest way to access the necessary rows. Looks for a tr element and then accesses every other td element. Fails miserably when you have more than one table on your page.
$("#data").find("td:odd").each(function(){
//code here
});
A much more straight forward way. We pass in the ID of the table and then access every other row.
$("#data tr td:odd").each(function(){
//code here
});
Same as above except that we just use CSS style selector syntax.
$("#data tr td:nth-child(2)").each(function(){
//code here
});
The version we are going to use today. This way is a lot better if we need to grab data from a different row or, if needed, multiple rows.
The final version looks like so:
function grabValues ()
{
// Access the required table cell, extract and add its value to the values array.
$("#data tr td:nth-child(2)").each(function(){
gValues.push($(this).text());
});
// Access the required table cell, extract and add its value to the xLabels array.
$("#data tr td:nth-child(1)").each(function(){
xLabels.push($(this).text());
});
}
Nothing complicated here. We use the snippet of code mentioned above to add the value of the table cell to the gValues array. Next, we do the same except that we access the first table cell in order to extract the requisite label for the x axis. We’ve encapsulated the data extraction logic to its own function for code reusability and readability.
function initCanvas ()
{
// Try to access the canvas element and throw an error if it isn't available
cv = $("#graph").get(0);
if (!cv)
{ return; }
// Try to get a 2D context for the canvas and throw an error if unable to
ctx = cv.getContext('2d');
if (!ctx)
{ return; }
}
Routine canvas initialization. First we try to access the canvas element itself. We throw an error if unable to. Next up, we try to obtain a reference to the 2d rendering context through the getContext method and throw an error if we’re unable to do so.
Before we step into the actual rendering of the graph itself, we need to look at a number of utility functions which aid us greatly in the process. Each of them are tiny by themselves, but will be used extensively throughout our code.
function maxValues (arr)
{
maxVal=0;
for(i=0; i<arr.length; i++)
{
if (maxVal<parseInt(arr[i]))
{
maxVal=parseInt(arr[i]);
}
}
maxVal*= 1.1;
}
A small function which iterates through the passed array and updates the maxVal variable. Do note that we inflate the maximum value by 10% for special purposes. If the maximum value is left as it is, then the bar representing the topmost value will touch the edge of the canvas element which we do not want. With that in mind, a 10% increment is issued.
function scale (param)
{
return Math.round((param/maxVal)*gHeight);
}
A small function to normalize the extracted value with respect to the height of the canvas element. This function is used extensively in other functions and directly in our code to express the value as a function of the height of the canvas. Takes a single parameter.
function x (param)
{
return (param*barWidth)+((param+1)*barSpacing)+xOffset;
}
Returns the x ordinate to the fillRect to aid us in the positioning of each individual bar. I’ll explain this a bit more in detail when it is used.
function y (param)
{
return gHeight - scale (param) ;
}
Returns the y ordinate to the fillRect method to aid us in the positioning of each individual bar. More explanations a bit later.
function width ()
{
return barWidth;
}
Returns the width of each individual bar.
function height (param)
{
return scale(param);
}
Returns the height of the bar to be drawn. Uses the scale function to normalize the value and then returns it to the caller.
function drawXlabels ()
{
ctx.save();
ctx.font = "10px 'arial'";
ctx.fillStyle = "#000";
for(index=0; index<gValues.length; index++)
{
ctx.fillText(xLabels[index], x(index), gHeight+17);
}
ctx.restore();
}
A simple function to render the labels of the x axis. We first save the current state of the canvas including all the rendering settings so that anything we do inside the functions never leaks out. Then we set the size and font of the labels. Next, we iterate through the xLabels array and call the fillText method each time to render the label. We use the x function to aid us in the positioning of the labels.
function drawYlabels()
{
ctx.save();
for(index=0; index<numYlabels; index++)
{
yLabels.push(Math.round(maxVal/numYlabels*(index+1)));
ctx.fillStyle = "#000";
ctx.fillText(yLabels[index], xOffset, y(yLabels[index])+10);
}
ctx.fillText("0", xOffset, gHeight+7);
ctx.restore();
}
A slightly more verbose function. We first save the current state of the canvas and then proceed. Next we divide maxVal’s value into n elements where the variable numYlabels dictates n. These values are then added to the yLabels array. Now, as shown above, the fillText method is called to draw the individual labels with the y function aiding us in the positioning of each individual label.
We render a zero at the bottom of the canvas to finish drawing the Y labels.
function drawGraph ()
{
for(index=0; index<gValues.length; index++)
{
ctx.save();
ctx.fillStyle = "#B7B7B7";
ctx.fillRect( x(index), y(gValues[index]), width(), height(gValues[index]));
ctx.restore();
}
}

The function which draws the actual bars in the bar graph. Iterates through the gValues array and renders each individual bar. We use the fillRect method to draw the bars. As explained above, the method takes four parameters, each of which is taken care of by our utility functions. The current index of the loop is passed to our functions as parameters along with the actual value held in the array, as needed.
The x function returns the x co-ordinate of the bar. Each time, it is incremented by the value of the sum of barWidth and barSpacing variables.
The y function calculates the difference between the height of the canvas element and the normalized data and returns it. I know this sounds a bit topsy turvy, but this is due to the fact that the y values on the canvas grid increase on moving down while in our graph the y values increase on moving up. Thus, we have to do a little work to make it function the way we wish.
The width function returns the width of the individual bars themselves.
The height function just returns the normalized value which is going to be used as the height of the bar to be drawn.
In this first part, we’ve implemented the base logic of our plug-in as a standalone version with bare bones looks and features. We reviewed the canvas coordinate system, the rectangle rendering methods, some nifty data extraction using jQuery’s innate awesomeness [Have I mentioned how much I like jQuery?], looked at how the labels are drawn, and finally looked at the logic behind the rendering of the graph itself.
At the end of this article, the output should look like so.

Our current implementation is rather lacking really. It looks bland, can’t create multiple graphs on the same page, and let’s face it, is rather spartan on the features front. We are going to tackle all of that next week. In the next article we will:
Questions? Criticisms? Praises? Feel free to hit the comments. Thanks for reading and stay tuned for the next part!