Mmmmm. Pie.
ExCanvas is Google's answer to the problem of the <canvas>
tag not being natively understood by the market hogging Internet Explorer browser. This element allows us to "draw" directly within it, creating vector graphics (including animations) on the fly.
If you can see two pie charts below then so far, so good. If they look like pie charts, even better! This means the <canvas>
tag has done it's job, albeit assisted by ExCanvas if you're viewing this in IE. Sadly, on my laptop, IE7 rendered the "donut" chart (the one on the right side of the two) sans donut until I coded around the problem with some hackery. I had to apply even uglier hackery to make it render nicely.
While I could solve the above problem quickly, this required nastiness that really annoyed me; why can nothing work across the board as it is designed to? I'm sure I'll find more of these shenanigans as I play further, but regardless, I think ExCanvas is going to be the way to go in future when it comes to drawing graphs and charts for my employers by day, and particularly - in the spirit of open source - for my JAWStats web statistics project I tinker with by night.
P.S. Everytime I think of the word donut, I laugh about this skit. Thank you, Ammon & Anne, for introducing it to me. :)
For completeness, here is my pie chart function:
function PieChart(iMiddleX, iMiddleY, iRadius, iExplodeDistance, bShowShadow, iDonutRadius, aData) { // draw shadow if (bShowShadow == true) { var iStartAngle = 0; var iShadowOffset = (iRadius / 45); for (var i = 0; i < aData.length; i++) { iStartAngle = DrawSlice(oColors.shadow, iMiddleX + iShadowOffset, iMiddleY + iShadowOffset, (iRadius * 1), iExplodeDistance, iStartAngle, aData[i]); } } // draw slices var iStartAngle = 0; for (var i = 0; i < aData.length; i++) { iStartAngle = DrawSlice(oColors.colors[i], iMiddleX, iMiddleY, iRadius, iExplodeDistance, iStartAngle, aData[i]); } // draw donut if (iDonutRadius > 0) { // 4 half circles? IE hackery :( oCTX.globalCompositeOperation = "destination-out"; iStartAngle = DrawSlice(oColors.shadow, iMiddleX, iMiddleY, iDonutRadius, 0, 0, 50); iStartAngle = DrawSlice(oColors.shadow, iMiddleX, iMiddleY, iDonutRadius, 0, iStartAngle, 50); iStartAngle = DrawSlice(oColors.shadow, iMiddleX, iMiddleY, iDonutRadius, 0, (iStartAngle + 5), 50); iStartAngle = DrawSlice(oColors.shadow, iMiddleX, iMiddleY, iDonutRadius, 0, (iStartAngle + 5), 50); } // slice drawing function DrawSlice(sColor, iMiddleX, iMiddleY, iRadius, iExplodeDistance, iStartAngle, iPercentage) { // calculate angles var iEndAngle = ((iPercentage * 3.6) + iStartAngle); var iRadiansFrom = DegreesToRadians(iStartAngle); var iRadiansTo = DegreesToRadians(iEndAngle); var iRadiansMid = (((iRadiansTo - iRadiansFrom) / 2) + iRadiansFrom); // calculate explode var iExplodeModify = (iExplodeDistance * (1 - (iPercentage / 100))); iMiddleX += (Math.cos(iRadiansMid) * iExplodeModify); iMiddleY += (Math.sin(iRadiansMid) * iExplodeModify); // draw oCTX.fillStyle = sColor; oCTX.beginPath(); oCTX.moveTo(iMiddleX, iMiddleY); oCTX.arc(iMiddleX, iMiddleY, iRadius, iRadiansFrom, iRadiansTo, false); oCTX.fill(); // return end point angle return iEndAngle; } } function DegreesToRadians(iDegrees) { return (Math.PI / 180) * (iDegrees - 90); }
Above is a cobbled together proof of concept function, written quickly. View Source to get the overall gist, because if you want to use it yourself, you'll need to break out the oCTX
reference if you have multiple graphs.
Useful stuff:
Code Snippets:
Recommended reading: