A Snazzy Animated Pie Chart with HTML5 and jQuery

  You are currently not logged in. You can view the forums, but cannot post messages. Log In | Register

11-Aug-10 01:00
This is a forum topic for discussing the article "A Snazzy Animated Pie Chart with HTML5 and jQuery":

http://www.elated.com/articles/snazzy-animated-pie-chart-html5-jquery/

Learn how to use the HTML5 canvas element, CSS3 and jQuery to create a gorgeous, interactive animated pie chart. Full code included for your own use.
25-Aug-10 10:52
Demo works on iPhone 3GS. Slightly jittery, but perfectly usable. Sweet!
25-Aug-10 20:41
@nanoamp: That's great to hear, thanks!

I also tried it on the Android emulator yesterday and it was very slooooow (probably cos of the slow Mac it was running on), but it did work!

--
Matt Doyle, Elated
01-Dec-10 08:00
Very nice, look's beutiful!

Just want to point out that the angle at 12-o'clock should in fact be pi/2 which means you should add that to 0 or subtract pi/2 from pi like:

pi-(pi/2) = pi/2 = pi*5/2 and so on..

But other than that the code works very nice indeed. Very nice commented and very nice result! Good job!

--
Nitzarn
01-Dec-10 21:16
@Nitzarn: Not sure I follow. pi/2 is 6 o'clock since it's working clockwise from 3 o'clock. So 12 o'clock is -pi/2.

The code seems to work OK to me!

--
Matt Doyle, Elated
02-Dec-10 01:43
Yes I also agreed that the code works, just wanted to point out that from a strict mathematical view, angles are counted counter-clockwise as the positive direction from 3-o'clock.

However the code works great!

--
Nitzarn
02-Dec-10 21:16
@Nitzarn: I see what you're saying. Yes, in mathematics, angles tend to work in an anticlockwise direction, but the canvas drawing functions work clockwise by default. (arc() has an 'anticlockwise' parameter if you want it to work anticlockwise instead.)

--
Matt Doyle, Elated
18-Feb-11 17:35
Very nice Tutorial. How about live data manipulation and slice growth?
20-Feb-11 19:38
@stevebor1: Thanks for your comment. Do you mean Ajax updating of the chart from a live data source? That would be a fun project

--
Matt Doyle, Elated
02-Mar-11 13:34
@matt: Yes live ajax updating.

I have been searching for so long and tried many of the flash charts (flash charts pro, fusioncharts) and js charts. With all you can update the data set, however it redraws the entire chart. I am in need of an actual live growth from old point to new point. no one offers this.
02-Mar-11 20:32
@stevebor1: I don't think it would be too hard to do actually. There are quite a few jQuery plugins out there that can do Ajax push:

http://www.google.com/search?q=jquery+ajax+push

Once you receive the new data values then all you'd need to do is update the HTML table and chartData array, then call drawChart() to update the chart itself.

Cheers,
Matt

--
Matt Doyle, Elated
02-Mar-11 20:34
Yes, that is the easy part, the part that no one has is the dynamic 'growing' effect. the chart should visually grow and shrink slices based on new values.
02-Mar-11 21:05
@stevebor1: That's what would happen. You'd just call drawChart() to redraw the chart, which will grow and shrink the slices.

--
Matt Doyle, Elated
27-Apr-11 15:21
Its wonderful to see the demo and the clarity in he images - HTML5 and Juery are terrific.

I was just tying to get a mouseover version of the above rather than a clickable version..

I enmass replaced click by mouseover - so when I mouseiver the widget the chart moves but only on moving over the chart - it doesnt -- how to rectify it

Also any plans of candle stock charts in the same?
28-Apr-11 08:12
@ajmal017: You want mousemove, not mouseover:

http://api.jquery.com/mousemove/

(mouseover will only trigger once when the cursor first moves inside the canvas element. Nothing will happen when you then move the cursor over the pie slices.)

Then you'll need to modify the handleChartClick() handler to manually detect (using math) if the cursor has just moved into or out of a slice. If it has, then pull out or push in the slice as appropriate.

--
Matt Doyle, Elated
13-May-11 13:46
This is a fantastic tool, however, once I finished testing it and tried to put it into our actual web-based program the pie pieces stop moving in and out when clicked (name and percentage pop-up text do not appear either), and when you click on the menu on the right the pie piece attached to it disappears.
I've traced the issue to the prototype.js file that we have hooked up to the program, but I have no idea where to narrow it down from there. Has anybody come to this brick wall before? I really want to use this chart and would hate to not be able to due to something like this. Thanks in advance!
19-May-11 03:30
@cross01: Prototype doesn't play nicely with jQuery in the same page. However you can use jQuery.noConflict() to work around this:

http://docs.jquery.com/Using_jQuery_with_Other_Libraries

--
Matt Doyle, Elated
19-May-11 09:55
Thank you for your reply, Matt. We knew that prototype.js was a pain, and we had tried the jQuery.noConflict() before too... but you got us thinking about checking on a new version of jQuery, and we found out that our version was 1.4.1. We upgraded to 1.6.1, changed some of our Ajax calls, and now it works like a dream. If this wasn't an offline project that needed to be self-contained we'd just link to an online jQuery library and always have the newest version, instead we'll just have to be diligent and continue to check jQuery.com.

Thank you for your quick assistance! You rock!
20-May-11 00:52
@cross01: Great stuff - glad you got it working

--
Matt Doyle, Elated
07-Jul-11 18:36
Silly question here: We have a pie chart where the pie pieces are 2000, 60, and 3. The 3 pie piece shows up as "0%", and it's piece on the whole pie does not show any color because of this, making it appear to not be there. Like I said, silly question, but can we somehow get that pie piece's color to appear even as a sliver on the chart (we can see the "3" in the key on the side, we just want to see that bit of color in the pie itself)? Thanks!
12-Jul-11 03:29
@cross01: Here's a reworked chunk of the init() function. It's a bit of a hack but should give you a starting point!


// Now compute and store the start and end angles of each slice in the chart data

var currentPos = 0; // The current position of the slice in the pie (from 0 to 1)

for ( var slice in chartData ) {
var value = chartData[slice]['value'];

if ( value < (totalValue / 300) ) {
totalValue += ( totalValue / 300 );
value = totalValue / 300;
}

chartData[slice]['startAngle'] = 2 * Math.PI * currentPos;
chartData[slice]['endAngle'] = 2 * Math.PI * ( currentPos + ( value / totalValue ) );
currentPos += value / totalValue;
}


--
Matt Doyle, Elated
12-Jul-11 08:57
That seems to be exactly what we're looking for. Thank you again for your help!
04-Aug-11 13:59
Hi there,

The pie chart is not showing up in IE 8 for me. Just to make sure it wasn't my modified code, I uploaded the source file and still not showing up in IE 8.
Has the explorercanvas api changed?
09-Aug-11 05:42
@rexonms: Strange! It worked fine at the time I wrote the tutorial. Could be a problem with the version of excanvas and/or jQuery that the tutorial links to.

I can sometimes get it to work by reloading the page. It's intermittent.

You could try downloading the latest version of excanvas (r3) from http://code.google.com/p/explorercanvas/ and installing it locally. That might fix the problem. Also try linking to the latest version of jQuery (1.6.2).

Here are some other tips that might help:

http://stackoverflow.com/questions/941170/does-anyone-could-make-excanvas-work-in-ie-8-with-jquery

--
Matt Doyle, Elated
29-Aug-11 17:02
Matt
I love your pie charts and the tutorial(s). I've made some modification to your pie charts and in the end, I've got a funny thing happening that I thought maybe you could help me with. I've put your pie chart in an ASP.NET page, it works fine (using function pageLoad(sender, args) in the scripts so that it reloads after an AsyncPostBack update). Then I replaced your table with a <asp:Gridview> inside an UpdatePanel. What I want to do is change the table data, and thereby the pie chart on the page. And it works. Here's the problem, I've got ghosting. More than that, sometimes, when I click, I get the old pie chart back. But more often, which I click on a piece of the pie, I sometimes get a quick flicker of the previous pie chart, and the slice of pie that is moving is the old slice (in the flicker) and the current slice moves as well. And like I said, sometimes I get the swapping of the pie charts altogether. In fact, every click will toggle me between pie charts when it's in that state (might have to do with where the mouse is). It's all very cool if that was what I wanted, but it's not. Do you know what needs to happen to clear the other pie chart out of memory so the new pie chart will function without the ghost haunting us? I think that will fix it but I'm not sure where that should be done. Thank You.
S.
01-Sep-11 03:31
@seddleman: I'm afraid I know very little about ASP.NET so I'm not sure I can help much. I can put forward a couple of theories though:

1) Your table is somehow changing all the time, so that the data that my pie chart code reads is constantly changing as it draws the chart.

2) You've somehow ended up with 2 canvas elements on top of each other, and they're fighting over which one should be on top! (Check for this using your browser's DOM inspector.)

Also take a look at your JavaScript console for errors, and see if the problem is the same across all browsers.

--
Matt Doyle, Elated
01-Sep-11 09:01
Thanks Matt, for your reply. It's been an interesting working with your pie charts. The solution to my problem was to unbind all the #chart 'click's prior to defining them, that way each new pie chart gets a fresh start. It works very well, thanks for your post. I've learned a lot by manipulating and changing the charts.

seddleman
02-Sep-11 03:28
@seddleman: Glad you got it working

--
Matt Doyle, Elated
30-Nov-11 21:24
great tutorial! thanks for sharing.

--
Jeff Shamley
UI Developer
http://jeffshamley.com
05-Dec-11 08:45
What a useful tutorial! Thanks for posting...

I have one simple question:
I want to update the chart without refreshing the whole page. I am done with writing a jQuery code for updating the HTML table. [done it with the jQuery function: .load]
OK now I would like to know the next step to achieve my goal.
Could you help? Thanks Matt!

--
I am a professional web developer and blogger.
06-Dec-11 00:32
@jshamley: Thanks

@akos: Can you not just call init() to redraw the chart?

--
Matt Doyle, Elated
06-Dec-11 07:28
Hi Matt

Great piece of work and tutorial I'm looking to adapt the graph slightly. I want each piece of pie to have its own background-image attached to it. Is this easily done?

Ive been trying for a while with no luck

Any ideas?

Cheers

Skeddy
09-Dec-11 03:34
@skeddy: Tricky since the chart is done with canvas. You'd have to load the image into a JavaScript object, then (I think) place the image in the right position on the canvas using drawImage(), and clip the image to the shape of the slice somehow using clip().

drawImage():

https://developer.mozilla.org/en/Canvas_tutorial/Using_images

clip():

https://developer.mozilla.org/samples/canvas-tutorial/6_2_canvas_clipping.html

No idea if this would work but it's all I can think of right now!

--
Matt Doyle, Elated
09-Dec-11 06:24
Thanks Matt

Great article.

I need one pie chart after another on the same web page. The first table i gave an id of chartData as in the example but what would you call the second ? Is there any simple way to do this so they both work or does the code need a some re writing/enhancement.

Thanks

David
11-Dec-11 17:34
@dklugmann: The easiest, if hacky, approach would be to put 2 iframes in your page, and load a separate pie chart page into each iframe.

The more elegant, but long-winded approach would be to rewrite all the pie chart code to hold an array of charts, each with their own arrays of data and their own canvas elements.

--
Matt Doyle, Elated
12-Dec-11 08:24
Matt

Thanks. I appreciate the response and thanks for writing some great code in the first place.

David
17-Dec-11 03:23
You're welcome, David! I hope you manage to get it working.

--
Matt Doyle, Elated
22-Dec-11 10:53
Hi Matt

Did you ever find the answer why this doesnt should an image under ie8 ? Looks great in frefox but nothing in ie8.

Thanks

David
23-Dec-11 06:47
Matt

I think the ie7 and ie8 issues are a timing issue.

The line in the init function

if ( typeof canvas.getContext === 'undefined' ) return;

was giving undefined as the canvas element had not yet loaded.

I changed the call to pieChart() to be called via a body onload.

<body onload="pieChart();">

it then works in IE.

Hope that is of use to someone.

David
23-Feb-12 04:11
great work, I have one query w.r.t this graph , when I use mousemove instead of click event for handling the movement of the slices in pie(for moving the pie pieces while mouse hovers over it ) the pie pieces movement isn't smooth .

Eg:
$('#chart').mousemove( handleChartClick );


Can you give me some suggestions on it.

Thanks
Sajeev
http://sajeev4u.blogspot.com
27-Feb-12 06:26
Matt,

First of all, thanks for this great guide. It has been really helpfull.

I'm am trying to pull out several slices with the help of checkboxes, but i kinda get stuck on that end unfortunately.

I added a peace of code to make sure that the percentage will be shown in my table, but also that every row in the tabel gets a checkbox. This is the following code:

function procentTable()
{

var currentRow = -1;
var currentCell = 0;
var currentProcent = 0;

$('#chartData td').each
(
function()
{
currentCell++;
if ( currentCell % 2 != 0 )
{
currentRow++;
currentProcent++;

}
else
{
var percentvalue = "" + ( parseFloat( chartData[currentRow]['value'] / totalValue * 100).toFixed(2)) + "%";
var percentRow = document.getElementById('chartData').rows[currentProcent];
var cell = percentRow.insertCell(2);
cell.innerHTML = percentvalue;
var select = percentRow.insertCell(3);
select.innerHTML = "<input type='checkbox' onclick='toggleSlice( "+currentProcent+")'>";
}


I wonder if it's possible that as soon as i check several boxes, several slices will pull out. And as soon as i click the slice itself, or the informatie in the table only that one will remain.

i hope it's not that big of a deal to help me out.

Thanks and greetz,

Dumdi

[Edited by Dum_Di_Dum on 27-Feb-12 06:38]
27-Feb-12 22:08
@sajeev: See: http://www.elated.com/forums/topic/5000/#post20742

--
Matt Doyle, Elated
27-Feb-12 22:27
@Dum_Di_Dum: Hard to work out what's going on by just reading code. Please post the URL of your chart page so I can take a look.

--
Matt Doyle, Elated
28-Feb-12 01:30
Hi matt,

Cheers for you response!

Ofcourse i can URL my chart, sorry about that.

The change of most importance is this function procentTable()




// Run the code when the DOM is ready
$( pieChart );

function pieChart() {

// Config settings
var chartSizePercent = 55; // De grootte van de circle (in procent)
var sliceBorderWidth = 1; // De grootte (in pixels) van de randen van de stukken
var sliceBorderStyle = "#fff"; // Kleur van de rand rondom de stukken
var sliceGradientColour = "#1F1C1C"; // Kleur om 1 kant van de gradient aan te geven (hier kun je de diagram lichter of donkerder maken
var maxPullOutDistance = 20; // Hier kan je de uitschuif verte mee bepalen
var pullOutFrameStep = 2; // Hier geef je de uitschuif snelheid aan
var pullOutFrameInterval = 55; // Geef hier aan hoe snel het uischuiven moeten gaan
var pullOutLabelPadding = 65; // De verte dat de tekst staat na het uitschuiven
var pullOutLabelFont = "bold 18px 'Trebuchet MS', Verdana, sans-serif"; // Tekst gegevens (titel)
var pullOutValueFont = "bold 12px 'Trebuchet MS', Verdana, sans-serif"; // Tekst gegevens
var pullOutValuePrefix = "Aantal: "; // Tekst die voor de tekst moet komen te staan bij het uitschuiven
var pullOutShadowColour = "rgba( 0, 0, 0, .5 )"; // Colour to use for the pull-out slice shadow
var pullOutShadowOffsetX = 10; // X-offset (in pixels) Hoever de schaduw moet gaan
var pullOutShadowOffsetY = 10; // Y-offset (in pixels) Hoever de schaduw moet gaan
var pullOutShadowBlur = 25; // De Donkerheid van de schaduw
var pullOutBorderWidth = 2; // De dikte van de rand als het stuk uitgeschoven is
var pullOutBorderStyle = "#333"; // De kleur van de rand als het uitgeschoven is
var chartStartAngle = -.5 * Math.PI; // Start de chart op 12u

// Declare some variables for the chart
var canvas; // The canvas element in the page
var currentPullOutSlice = -1; // Welke slice er al standaard uitgeschoven moet zijn (-1 is geen slice)
var currentPullOutDistance = 0; // How many pixels the pulled-out slice is currently pulled out in the animation
var animationId = 0; // Tracks the interval ID for the animation created by setInterval()
var chartData = []; // Chart data (labels, values, and angles)
var chartColours = []; // Kleuren van de slices (die matche met die van de tabel
var totalValue = 0; // Total of all the values in the chart
var canvasWidth; // Width of the canvas, in pixels
var canvasHeight; // Height of the canvas, in pixels
var centreX; // X-coordinate of centre of the canvas/chart
var centreY; // Y-coordinate of centre of the canvas/chart
var chartRadius; // Radius of the pie chart, in pixels

// Set things up and draw the chart
init();



/**
* Set up the chart data and colours, as well as the chart and table click handlers,
* and draw the initial pie chart
*/

function init() {

// Get the canvas element in the page
canvas = document.getElementById('chart');

// Exit if the browser isn't canvas-capable
if ( typeof canvas.getContext === 'undefined' ) return;

// Initialise some properties of the canvas and chart
canvasWidth = canvas.width;
canvasHeight = canvas.height;
centreX = canvasWidth / 2;
centreY = canvasHeight / 2;
chartRadius = Math.min( canvasWidth, canvasHeight ) / 2 * ( chartSizePercent / 100 );

// Grab the data from the table,
// and assign click handlers to the table data cells

var currentRow = -1;
var currentCell = 0;

$('#chartData td').each( function() {
currentCell++;
if ( currentCell % 2 != 0 ) {
currentRow++;
chartData[currentRow] = [];
chartData[currentRow]['label'] = $(this).text();
} else {
var value = parseFloat($(this).text());
totalValue += value;
value = value.toFixed(0);
chartData[currentRow]['value'] = value;
}

// Store the slice index in this cell, and attach a click handler to it
$(this).data( 'slice', currentRow );
$(this).hover( handleTableClick );


// Extract and store the cell colour
if ( rgb = $(this).css('color').match( /rgb\((\d+), (\d+), (\d+)/) ) {
chartColours[currentRow] = [ rgb[1], rgb[2], rgb[3] ];
} else if ( hex = $(this).css('color').match(/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/) ) {
chartColours[currentRow] = [ parseInt(hex[1],16) ,parseInt(hex[2],16), parseInt(hex[3], 16) ];
} else {
alert( "Error: Colour could not be determined! Please specify table colours using the format '#xxxxxx'" );
return;
}

} );

procentTable ();

// Now compute and store the start and end angles of each slice in the chart data

var currentPos = 0; // The current position of the slice in the pie (from 0 to 1)

for ( var slice in chartData ) {
chartData[slice]['startAngle'] = 2 * Math.PI * currentPos;
chartData[slice]['endAngle'] = 2 * Math.PI * ( currentPos + ( chartData[slice]['value'] / totalValue ) );
currentPos += chartData[slice]['value'] / totalValue;
}

// All ready! Now draw the pie chart, and add the click handler to it
drawChart();
$('#chart').click ( handleChartClick );
}

function procentTable()
{

var currentRow = -1;
var currentCell = 0;
var currentProcent = 0;

$('#chartData td').each
(
function()
{
currentCell++;
if ( currentCell % 2 != 0 )
{
currentRow++;
currentProcent++;

}
else
{
var percentvalue = "" + ( parseFloat( chartData[currentRow]['value'] / totalValue * 100).toFixed(2)) + "%";
var percentRow = document.getElementById('chartData').rows[currentProcent];
var cell = percentRow.insertCell(2);
cell.innerHTML = percentvalue;
var select = percentRow.insertCell(3);
select.innerHTML = "<input type='checkbox' onclick='toggleSlice( "+currentProcent+")'>";
}
$(cell).data( 'slice', currentRow );
$(cell).hover( handleTableClick );
$(select).data( 'slice', currentRow );
$(select).hover( handleTableClick );

// Store the slice index in this cell, and attach a click handler to it
//$(this).data( 'slice', currentRow );
//$(this).click( handleTableClick );
}
);
}

/**
* Process mouse clicks in the chart area.
*
* If a slice was clicked, toggle it in or out.
* If the user clicked outside the pie, push any slices back in.
*
* @param Event The click event
*/

function handleChartClick ( clickEvent ) {

// Get the mouse cursor position at the time of the click, relative to the canvas
var mouseX = clickEvent.pageX - this.offsetLeft;
var mouseY = clickEvent.pageY - this.offsetTop;

// Was the click inside the pie chart?
var xFromCentre = mouseX - centreX;
var yFromCentre = mouseY - centreY;
var distanceFromCentre = Math.sqrt( Math.pow( Math.abs( xFromCentre ), 2 ) + Math.pow( Math.abs( yFromCentre ), 2 ) );

if ( distanceFromCentre <= chartRadius ) {

// Yes, the click was inside the chart.
// Find the slice that was clicked by comparing angles relative to the chart centre.

var clickAngle = Math.atan2( yFromCentre, xFromCentre ) - chartStartAngle;
if ( clickAngle < 0 ) clickAngle = 2 * Math.PI + clickAngle;

for ( var slice in chartData ) {
if ( clickAngle >= chartData[slice]['startAngle'] && clickAngle <= chartData[slice]['endAngle'] ) {

// Slice found. Pull it out or push it in, as required.
toggleSlice ( slice );
return;
}
}
}

// User must have clicked outside the pie. Push any pulled-out slice back in.
pushIn();
}


/**
* Process mouse clicks in the table area.
*
* Retrieve the slice number from the jQuery data stored in the
* clicked table cell, then toggle the slice
*
* @param Event The click event
*/

function handleTableClick ( clickEvent ) {
var slice = $(this).data('slice');
toggleSlice ( slice );
}


/**
* Push a slice in or out.
*
* If it's already pulled out, push it in. Otherwise, pull it out.
*
* @param Number The slice index (between 0 and the number of slices - 1)
*/

function toggleSlice ( slice ) {
if ( slice == currentPullOutSlice ) {
pushIn();
} else {
startPullOut ( slice );
}
}


/**
* Start pulling a slice out from the pie.
*
* @param Number The slice index (between 0 and the number of slices - 1)
*/

function startPullOut ( slice ) {

// Exit if we're already pulling out this slice
if ( currentPullOutSlice == slice ) return;

// Record the slice that we're pulling out, clear any previous animation, then start the animation
currentPullOutSlice = slice;
currentPullOutDistance = 0;
clearInterval( animationId );
animationId = setInterval( function() { animatePullOut( slice ); }, pullOutFrameInterval );

// Highlight the corresponding row in the key table
$('#chartData td').removeClass('highlight');
var labelCell = $('#chartData td:eq(' + (slice*4) + ')');
var valueCell = $('#chartData td:eq(' + (slice*4+1) + ')');
var percentCell = $('#chartData td:eq(' + (slice*4+2) + ')');
var selectCell = $('#chartData td:eq(' + (slice*4+3) + ')');
labelCell.addClass('highlight');
valueCell.addClass('highlight');
percentCell.addClass('highlight');
selectCell.addClass('highlight');
}


/**
* Draw a frame of the pull-out animation.
*
* @param Number The index of the slice being pulled out
*/

function animatePullOut ( slice ) {

// Pull the slice out some more
currentPullOutDistance += pullOutFrameStep;

// If we've pulled it right out, stop animating
if ( currentPullOutDistance >= maxPullOutDistance ) {
clearInterval( animationId );
return;
}

// Draw the frame
drawChart();
}


/**
* Push any pulled-out slice back in.
*
* Resets the animation variables and redraws the chart.
* Also un-highlights all rows in the table.
*/

function pushIn() {
currentPullOutSlice = -1;
currentPullOutDistance = 0;
clearInterval( animationId );
drawChart();
$('#chartData td').removeClass('highlight');
}


/**
* Draw the chart.
*
* Loop through each slice of the pie, and draw it.
*/

function drawChart() {

// Get a drawing context
var context = canvas.getContext('2d');

// Clear the canvas, ready for the new frame
context.clearRect ( 0, 0, canvasWidth, canvasHeight );

// Draw each slice of the chart, skipping the pull-out slice (if any)
for ( var slice in chartData ) {
if ( slice != currentPullOutSlice ) drawSlice( context, slice );
}

// If there's a pull-out slice in effect, draw it.
// (We draw the pull-out slice last so its drop shadow doesn't get painted over.)
if ( currentPullOutSlice != -1 ) drawSlice( context, currentPullOutSlice );
}


/**
* Draw an individual slice in the chart.
*
* @param Context A canvas context to draw on
* @param Number The index of the slice to draw
*/

function drawSlice ( context, slice ) {

// Compute the adjusted start and end angles for the slice
var startAngle = chartData[slice]['startAngle'] + chartStartAngle;
var endAngle = chartData[slice]['endAngle'] + chartStartAngle;

if ( slice == currentPullOutSlice ) {

// We're pulling (or have pulled) this slice out.
// Offset it from the pie centre, draw the text label,
// and add a drop shadow.

var midAngle = (startAngle + endAngle) / 2;
var actualPullOutDistance = currentPullOutDistance * easeOut( currentPullOutDistance/maxPullOutDistance, .8 );
startX = centreX + Math.cos(midAngle) * actualPullOutDistance;
startY = centreY + Math.sin(midAngle) * actualPullOutDistance;
context.fillStyle = 'rgb(' + chartColours[slice].join(',') + ')';
context.textAlign = "center";
context.font = pullOutLabelFont;
context.fillText( chartData[slice]['label'], centreX + Math.cos(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ), centreY + Math.sin(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ) );
context.font = pullOutValueFont;
context.fillText( pullOutValuePrefix + chartData[slice]['value'] + " (" + ( parseFloat( chartData[slice]['value'] / totalValue * 100).toFixed(2) ) + "%)", centreX + Math.cos(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ), centreY + Math.sin(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ) + 20 );
context.shadowOffsetX = pullOutShadowOffsetX;
context.shadowOffsetY = pullOutShadowOffsetY;
context.shadowBlur = pullOutShadowBlur;

} else {

// This slice isn't pulled out, so draw it from the pie centre
startX = centreX;
startY = centreY;
}

// Set up the gradient fill for the slice
var sliceGradient = context.createLinearGradient( 0, 0, canvasWidth*.75, canvasHeight*.75 );
sliceGradient.addColorStop( 0, sliceGradientColour );
sliceGradient.addColorStop( 1, 'rgb(' + chartColours[slice].join(',') + ')' );

// Draw the slice
context.beginPath();
context.moveTo( startX, startY );
context.arc( startX, startY, chartRadius, startAngle, endAngle, false );
context.lineTo( startX, startY );
context.closePath();
context.fillStyle = sliceGradient;
context.shadowColor = ( slice == currentPullOutSlice ) ? pullOutShadowColour : "rgba( 0, 0, 0, 0 )";
context.fill();
context.shadowColor = "rgba( 0, 0, 0, 0 )";

// Style the slice border appropriately
if ( slice == currentPullOutSlice ) {
context.lineWidth = pullOutBorderWidth;
context.strokeStyle = pullOutBorderStyle;
} else {
context.lineWidth = sliceBorderWidth;
context.strokeStyle = sliceBorderStyle;
}

// Draw the slice border
context.stroke();
}


/**
* Easing function.
*
* A bit hacky but it seems to work! (Note to self: Re-read my school maths books sometime)
*
* @param Number The ratio of the current distance travelled to the maximum distance
* @param Number The power (higher numbers = more gradual easing)
* @return Number The new ratio
*/

function easeOut( ratio, power ) {
return ( Math.pow ( 1 - ratio, power ) + 1 );
}

};




As you can see i create an checkbox behind every row of the table. My actual question is if there is any possbility that you can pop out the slices of every box that is checked.

I hope you can help me with this one,

Greetz,

Dumdi

[Edited by Dum_Di_Dum on 28-Feb-12 01:34]
28-Feb-12 14:37
This is awesome, however it bugs out if there is an entry of zero - do you know of a way to fix this?

thanks!!
01-Mar-12 04:41
@Dum_Di_Dum: Please post the URL.

@cdavidson: A data item of zero works fine for me. Please post the URL of your page with the problem.

--
Matt Doyle, Elated
14-Mar-12 06:12
Hi,
nice work.I'm fresh to jquery,so i juz want to know how we can get the values from an external database(like if a json is there),instead of the table.i have searched but most of them gives a vague idea.

--
bens
23-Mar-12 02:30
@ben_sam: Either:

1) Pull the data from the database in your server-side (PHP?) script and generate the markup for the page, including the #chartData table.

or:

2) Add some JS to the page to pull the data via Ajax/JSON and populate the #chartData table once the page has loaded, then run the pieChart() function to create the chart. You'll need to write a simple server-side script to retrieve the data from your DB and return it as a JSON object in the response. You might find this helpful:

http://www.elated.com/articles/ajax-with-jquery-a-beginners-guide/

--
Matt Doyle, Elated
30-Apr-12 04:54
hi can i know wt sholud be done to make above pie chart as a drill down pie chart..
thx in advance

--
dineshbnmit@gamil.com
30-Apr-12 06:51
Hi Matt , how to load data from array which is in one javascript file into table..

--
dineshbnmit@gamil.com
02-May-12 07:49
HI Matt .. why no reply to my question...


can u pls tel me how to load data to chart without table.. if u have any code pls share with me.. thx in advance

--
dineshbnmit@gamil.com
01-Jun-12 12:31
Hihi, first off: amazing piechart. The tutorial and code was very beautifully written. I'm having some trouble with the #chartData table. I'm pulling data from two javascript functions. Both returning a string, both print and display fine in the table and both don't work in the piechart. I've illustrated the issue here: http://imgur.com/1eV6V
and here is the troubling code:


<div id="container">
<canvas id="chart" width="600" height="500"></canvas>

<table id="chartData">

<tr>
<th>Twitter</th><th>Number of Fans</th>
</tr>

<tr style="color: #0DA068">
<td id="link_1"></td><td id="twitter_count1">100</td>
</tr>

<tr style="color: #194E9C">
<td>Test Data2</td><td>100</td>
</tr>
</div>


Many many thanks!

--
Thank you!! Awesome, superb graph love it!
15-Jun-12 04:36
@maxbye3: I'd need to see your whole page and code really. Can you post it to http://jsfiddle.net/ ?

Bear in mind that, if you're populating your data table dynamically with JS, you will of course have to run the pie chart code after you've populated the table.

--
Matt Doyle, Elated
21-Jun-12 12:47
Thank you so much Matt for this great stuff.
I am quite new to jquery, yet. I am trying to create the pie chart a little more dynamic. But ending up having the new chart overlapping the previous chart, and I can't remove the .data(slices) from the previous chart.
I am new to jquery. Please let me know how I can clear the chart datas completely before I can add new chart slices.
I tried
chartData[currentRow] = [];

chartData.empty();

$(this).prev().remove;

Nothing seems to work. Please help. Many thanks
26-Jun-12 03:28
Hi starter,

I don't totally understand what you're trying to do, but I'd imagine the easiest approach would be to add/remove rows from your data table as needed, then just call init() again to reinitialise the chart. Does that not work?

--
Matt Doyle, Elated
26-Jun-12 05:02
It does not work, as it will contain the previous pie chart at the same area. So when I click on the area, it appears both pie chart at the same time. So I need to remove the previous pie chart first. Would like to know how to delete the pie chart history. Sorry for making it confusing. Many thanks
27-Jun-12 07:38
Hi Matt,
You're an absolute star for helping the community like this.
I've re-read my previous post and it's not clear at all - hopefully this makes more sense.

I want to chart number of Likes on a Facebook page:


var f_page = ["TheHouseofMarley"];

retrieveData(f_page[0]);


function retrieveData(teamName) {
var baseURL = 'http://graph.facebook.com/';
$.getJSON(baseURL+teamName+"&callback=?", function(data) {
$('#FBLikes').append(data.likes)
});
};



// In the body:
<span id='FBLikes'></span>
// Gives an output of 8364 <- so it works.


However if I put this number into the chart table:



<table id="chartData">

<tr style="color: #0DA068">
<td>Number of Likes</td><td><span id='FBlikes'></span> </td>
</tr>

<tr style="color: #194E9C">
<td>MegaWidget</td><td>20000</td>
</tr>
</table>


It's displayed but not recognised by the pie chart, any idea what I'm doing wrong?

I've put my code on JSFiddle (http://jsfiddle.net/qmrpG/5/) if you could point me in any type of direction. I would highly appreciate it. Thank ya.

[Edited by maxbye3 on 27-Jun-12 06:39]

--
Thank you!! Awesome, superb graph love it!
27-Jun-12 12:37
Hi maxbye3,
http://jsfiddle.net/qmrpG/5/
you should call the piechart using
piechart();
instead of $(piechart);
27-Jun-12 15:27
Hi Matt,

Thanks for the code! It's exactly what I was looking for.

I ran into an issue with zero values with ExplorerCanvas (possibly the same issue cdavidson had). The zero value caused the slice to take over the entire pie, obscuring the other slices. To fix it I gave the slice a small value so it was still too small to display but was still enough to avoid the "whole pie" issue. Basically:


chartData[slice]['endAngle'] = 2 * Math.PI * ( currentPos + ( chartData[slice]['value'] / totalValue ) );


became:


// To correct 0 value slices in ExplorerCanvas, make zero/near-zero values
// into .01% of the total. Otherwise, ExplorerCanvas will draw over the whole pie.
chartData[slice]['endAngle'] = 2 * Math.PI * ( currentPos + ( Math.max(chartData[slice]['value'], (totalValue / 10000)) / totalValue ) );
29-Jun-12 05:28
Hi Matt,
Thanks so much for the help. I figured out what was going wrong. I had to initialise draw chart inside of the retrieve data function.


var f_page = ["TheHouseofMarley"];

retrieveData(f_page[0]);

function retrieveData(teamName) {
var baseURL = 'http://graph.facebook.com/';
$.getJSON(baseURL+teamName+"&callback=?", function(data) {
$('#FBLikes').append(data.likes)
init(); //This is what stumped me
});
};


Anyway, thanks for all the help and I've just brought your book!

--
Thank you!! Awesome, superb graph love it!
13-Jul-12 03:28
@starter: Hmm, I'm not sure why that would happen, since every time it draws the chart it clears the canvas (in the drawChart() function). If you can post your chart page on jsfidde/jsbin then we can take a look.

@grapoza: Thanks for the helpful tip

@maxbye3: Glad you got it working, and thanks for buying the book - hope you like it

--
Matt Doyle, Elated
16-Jul-12 07:12
Hi there, I would like to display the chart with data that are extract from ms access. Is it possible to do it in here?
24-Jul-12 14:21
I love your chart, thank you very much for putting it together. I am wondering if there is a way to change the spacing between the label and the value?

Thank you,
April
27-Jul-12 03:29
@april_r: In the table, or the chart?

--
Matt Doyle, Elated
27-Jul-12 10:43
@matt

sorry, in the chart.
28-Jul-12 00:42
@april_r: I believe the line you're looking for is in the drawSlice method:


context.fillText( pullOutValuePrefix + chartData[slice]['value'] + " (" + ( parseInt( chartData[slice]['value'] / totalValue * 100 + .5 ) ) + "%)", centreX + Math.cos(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ), centreY + Math.sin(midAngle) * ( chartRadius + maxPullOutDistance + pullOutLabelPadding ) + 20 );


The "+ 20" at the end of the line is what you'll want to change to increase or decrease the spacing between the label and value texts. Alternatively, I've put a derivative of Matt's work up on my website if you want a JavaScript class with getter/setter methods for this value. If you want to give that a shot just PM me and I can send the link to you.

@matt: I just looked over the compatibility chart again, and your note about needing to click to the left of the chart in IE7 sounded similar to or possibly the same as a problem I'd had with it as well. To fix it, I just used jQuery's .offset() method to get the position of the canvas instead of calculating it myself. That gave me the correct offset in all the browsers I tried. Happy days.
30-Jul-12 11:53
@grapoza
Thank you, that is what I needed.
28-Sep-12 01:36
This chart is amazing.. i need to add another columns to the table , however when i added another 2 columns , the chart does not work. Appreciate your help on this..
07-Dec-12 08:04
The chart is very nice. But, i have some issues and need suggestion from you. Actually in my page, the click event on chart does not work. I think the problem is with div element of the chart. Because if i click outside of chart in the canvas, the toggleslice is called but when i click on chart it does not work. Any suggestions? From the table chart handler works perfectly fine. If you want i can give you my page. Also, I need to display 3 charts on a same page. So do i have to write 3 different init functions or is there any one function that works?

--
Sampada
18-Dec-12 19:02
@sampada: Can you post the URL of your chart page so we can see the problem?

I answered your second question here: http://www.elated.com/forums/topic/5000/#post21904

--
Matt Doyle, Elated
19-Dec-12 04:11
var mouseX = clickEvent.pageX - this.offsetLeft;
var mouseY = clickEvent.pageY - this.offsetTop;

The code above will not work if the canvas is inside a <td> for example.
So i suggest the following modification :

var p = $('#' + name);
var offset = p.offset();
var mouseX = clickEvent.pageX - offset.left
var mouseY = clickEvent.pageY - offset.top
23-Jan-13 07:48
Hey Matt,

Thanks so much for the article and great sample code. I want to make sure I give credit where credit is do. Can you provide the copyright attribution text you'd like me to use in my about page?

Thanks,

Missing
27-Jan-13 16:53
Matt!
Amazing job, thank you very much!

I managed to understand most of the code and to implement it.
A question please, if i want to replace the text about each slice with a picture, how should i do it?

Again, Great job! thank you!

Meschiany
10-Feb-13 21:47
@missing: Just something like "pie chart code courtesy of Matt Doyle" (with a link to the article) is fine!

@meschiany: In drawSlice() you'd need to replace the calls to fillText() with a call to drawImage(): http://www.html5canvastutorials.com/tutorials/html5-canvas-images/

--
Matt Doyle, Elated
12-Mar-13 17:23
Thank you for this tutorial. I have a question regarding the colors. My chart is created dynamically from my DB. The problem i am having is I can not dynamically change the <tr style="color: #>?
I tried doing it via javascript but it didn't work. Is there something I can put into the var chartColours = []; instead of it creating from the HTML
10-Apr-13 17:54
Matt,

Thank you for sharing! This chart is fantastic, and exactly what I was looking for in my current project.

I just have one question... is there anyway to currently control the opacity of the slices (pulled out and inactive) ? What I need to do is essentially add opacity to the un-selected layers so that the selected slice is focused on by its opacity in comparison to the others. (my product manager would rather do that than toggle each slice).

jffgrdnr

--
jffgrdnr
30-Apr-13 01:01
@vinsite54: I'd need to see more context to answer your question. How are you pulling the data from the DB? If you're using Ajax then it should be fairly easy to use JS to change the tr elements as well as the chartColours array.

@jffgrdnr: Glad it helped! You should be able to just replace the rgb() notation in drawSlice() with rgba(), where 'a' is the alpha (opacity) value you want to use. 'a' ranges from 0 (completely transparent) to 1 (completely opaque).

--
Matt Doyle, Elated
30-Apr-13 04:46
The pie chart works awesomely, however it clash with Shareaholic scripts.
When Shareaholic script is installed, the piechart will have problem drawing the pullout slice, it will just show blank for that slice.
Using Chrome Developer tools, the error was
[i]"Uncaught TypeError: Object function (){return i} has no method 'join' "
[/i]

After diving into the script, I made a one line change in function drawChart().

I change from

for ( var slice in chartData ) {

to

for ( var slice=0; slice < chartData.length; slice++ ) {


Hopefully this will help other who face the same problem.

[Edited by shanai on 30-Apr-13 08:52]
21-May-13 12:01
HELLO thanks for this lovely article, my question is i want to display the info (in this case widget ...) into one place for example in a little zone just under the pie .

any help please would much appreciated
19-Feb-14 01:03
Hi Matt,

Great Work!!! This is what I am looking for my current project.

I wonder how to change the dollar sign into other currency symbol when I pull up the slice by clicking one of the rows in the table?
02-Mar-14 11:36
Hello

For obtuse909 :
- ligne 99


var pullOutValuePrefix = "€ "; // Pull-out slice value prefix



For my part, to make your interactive graph:
- I wish I could feed the digital values of those four variables calculated following the seizure of the user.

But I do not know
- Or the syntax to be used
- Or the place where he must place the mini script

The only thing I understood was that we must attribute "id" to <td>

Thank you in advance and bravos



PS : Traduction Google

--
PrimoDbutant
13-May-14 03:48
Hi,
First of all pie chart works awesomely, however I have one question....

I would like to know how to detect which of pullOutLabel's (pullOutLabel or pullOutValue) is clicked when slice is pulled out, and then to redirect to other page depending on which one is clicked.
I m pretty new to jQuery so would appreciate your help.

Thanks in advance.
20-Jun-14 09:22
Hey.

Do you think it would be possible to scale individual slices instead of the whole pie?

Thank you in advance.
18-Sep-15 03:43
Thanks for Sharing..
your Chart is Awesome..

however I just have one question..
how to add links to pie chart slices ?


I would highly appreciate it. Thank you.
18-Sep-15 14:54
"how to add links to pie chart slices "


It's a tutorial, the idea is that you use it to learn more about programming by adding your own features to it.


And if you want come back, and tell everyone how to extend it's functionality.

--
Chris.
So long, and thanks for all the fish.
http://webmaster-talk.eu/

 
New posts
Old posts

Follow Elated