The HTML5 canvas element certainly opens a lot of possibilities for web developers. Inspired by Arne @ 23inch.de’s JS1K.com submission I thought I would explore the canvas elements capabilities by creating a simple javascript function that generates a pie chart.
The Canvas
First we need a canvas element.
<canvas id="c"> Your browser does not support the canvas element. </canvas>
Next we need the script that will draw the Pie Chart. I decided to use two functions; one for the wedge and the other to to loop through the data.
The Wedge Function
I adapted Arne’s function for drawing arcs to draw wedges.
function W(x,y,r,u,v) { if(r) { a.beginPath(); a.moveTo(x,y); a.arc(x, y , r, (u||0)/50*Math.PI, (v||7)/50*Math.PI, 0); a.lineTo(x,y); a.fill(); } else { a.fillStyle = '#'+'a000b4bbff95'.substr(x,3); } return W; }
x and y are the coordinates of the charts center. r is the radius of the chart. u is the startAngle and v is the stopAngle in percent. Wedge color aka fillStyle is set by x when r is missing. The colors available are interlaced. The function returns itself so that it can be call likeĀ W(0)(100,100,50,0,25);
The Chart
Next I needed a function that would use the wedge function the draw each wedge of the pie chart.
function pie(r,b,n) { c.width=3.5*r; c.height=2.5*r; x=y=c.height/2; a.font="bold 12pt Arial"; var u = 0; var v = 0; for (i=0;i < b.length;i++) { v+=b[i]; W(i)(x,y,r,u,v); u=v; a.fillText(n[i],x+r+10,y-r/2+i*18); } }
Again r is the radius and is used to calculate the canvas’ height and width and variables x and y. b is an array of the percents and n is an array of the names used for the charts key. The function loops through the elements of the array, drawing each wedge and key. It is assumed that the elements of b total 100.
Bringing the pieces together
Lastly, create the needed arrays and call the pie function which in turn calls the wedge function.
var n = ['RED','BLACK','BLUE','GREEN','PINK']; //key names for each wedge var b = [20,25,15,10,30]; //percents, needs to total 100 pie(100,b,n);
Again it is assumed that b’s elements total 100 and that n and b have the same number of elements.
What it looks like
So if you are using an HTML5 compliant browser you get this:
For any developer that consider readability and maintainability important I refactored the code:
function pieChart(canvas, radius, percentages, labels, colors) {
var canvas = document.getElementById(canvas)
var context = canvas.getContext("2d");
canvas.width = 3.5*radius;
canvas.height = 2.5*radius;
var cx, cy;
cx = cy = canvas.height/2;
context.font = "bold 12px Arial";
var start_rad = 0;
var end_rad;
var end_percentage = 0;
for (i = 0; i < percentages.length; ++i) {
end_percentage += percentages[i];
end_rad = end_percentage / 100 * 2 * Math.PI;
context.fillStyle = colors[i];
drawWedge(context, cx, cy, radius, start_rad, end_rad);
start_rad = end_rad;
context.fillText(labels[i], cx + radius + 10, cy - radius/2 + i*18);
}
}
function drawWedge(context, cx, cy, radius, start_rad, end_rad) {
context.beginPath();
context.moveTo(cx,cy);
context.arc(cx, cy , radius, start_rad, end_rad, false);
context.lineTo(cx,cy);
context.fill();
}
Hey Ruben,
This function is no longer working in the latest version of Chrome. Any ideas what’s up with it?
I can confirm that on Chrome Version 26.0.1410.43 m the wedges are not drawn. It goes back to Magnus’ comment about “readability and maintainability”. The code for the wedge
a.beginPath() | a.fill(a.moveTo(x,y)|a.arc(x,y,r,(u||0)/50*Math.PI,(v||7)/50*Math.PI,0)|a.lineTo(x,y))
is the issue; probably cause the pipes. I updated the function to thisfunction W(x,y,r,u,v) {
and it now works.if(r) {
a.beginPath();
a.moveTo(x,y);
a.arc(x, y , r, (u||0)/50*Math.PI, (v||7)/50*Math.PI, 0);
a.lineTo(x,y);
a.fill();
} else {
a.fillStyle = '#'+'a000b4bbff95'.substr(x,3);
}
return W;
}
Edit: Changing the actual wedge to
a.beginPath() | a.moveTo(x,y) | a.arc(x,y,r,(u||0)/50*Math.PI,(v||7)/50*Math.PI,0) | a.lineTo(x,y) | a.fill()
works too.Ah Sweet! Thanks a lot Reuben – Works great again now.