PluginProbe
Contact Forms by Cimatti / 1.3
Contact Forms by Cimatti v1.3
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / flot / jquery.flot.pie.js

jquery.flot.pie.js in Contact Forms by Cimatti 1.3, at flot/jquery.flot.pie.js

751 lines 21.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 Flot plugin for rendering pie charts. The plugin assumes the data is
3 coming is as a single data value for each series, and each of those
4 values is a positive value or zero (negative numbers don't make
5 any sense and will cause strange effects). The data values do
6 NOT need to be passed in as percentage values because it
7 internally calculates the total and percentages.
8
9 * Created by Brian Medendorp, June 2009
10 * Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
11
12 * Changes:
13 2009-10-22: lineJoin set to round
14 2009-10-23: IE full circle fix, donut
15 2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
16 2009-11-17: Added IE hover capability submitted by Anthony Aragues
17 2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
18
19
20 Available options are:
21 series: {
22 pie: {
23 show: true/false
24 radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
25 innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
26 startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
27 tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
28 offset: {
29 top: integer value to move the pie up or down
30 left: integer value to move the pie left or right, or 'auto'
31 },
32 stroke: {
33 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
34 width: integer pixel width of the stroke
35 },
36 label: {
37 show: true/false, or 'auto'
38 formatter: a user-defined function that modifies the text/style of the label text
39 radius: 0-1 for percentage of fullsize, or a specified pixel length
40 background: {
41 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
42 opacity: 0-1
43 },
44 threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
45 },
46 combine: {
47 threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
48 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
49 label: any text value of what the combined slice should be labeled
50 }
51 highlight: {
52 opacity: 0-1
53 }
54 }
55 }
56
57 More detail and specific examples can be found in the included HTML file.
58
59 */
60
61 (function ($)
62 {
63 function init(plot) // this is the "body" of the plugin
64 {
65 var canvas = null;
66 var target = null;
67 var maxRadius = null;
68 var centerLeft = null;
69 var centerTop = null;
70 var total = 0;
71 var redraw = true;
72 var redrawAttempts = 10;
73 var shrink = 0.95;
74 var legendWidth = 0;
75 var processed = false;
76 var raw = false;
77
78 // interactive variables
79 var highlights = [];
80
81 // add hook to determine if pie plugin in enabled, and then perform necessary operations
82 plot.hooks.processOptions.push(checkPieEnabled);
83 plot.hooks.bindEvents.push(bindEvents);
84
85 // check to see if the pie plugin is enabled
86 function checkPieEnabled(plot, options)
87 {
88 if (options.series.pie.show)
89 {
90 //disable grid
91 options.grid.show = false;
92
93 // set labels.show
94 if (options.series.pie.label.show=='auto')
95 if (options.legend.show)
96 options.series.pie.label.show = false;
97 else
98 options.series.pie.label.show = true;
99
100 // set radius
101 if (options.series.pie.radius=='auto')
102 if (options.series.pie.label.show)
103 options.series.pie.radius = 3/4;
104 else
105 options.series.pie.radius = 1;
106
107 // ensure sane tilt
108 if (options.series.pie.tilt>1)
109 options.series.pie.tilt=1;
110 if (options.series.pie.tilt<0)
111 options.series.pie.tilt=0;
112
113 // add processData hook to do transformations on the data
114 plot.hooks.processDatapoints.push(processDatapoints);
115 plot.hooks.drawOverlay.push(drawOverlay);
116
117 // add draw hook
118 plot.hooks.draw.push(draw);
119 }
120 }
121
122 // bind hoverable events
123 function bindEvents(plot, eventHolder)
124 {
125 var options = plot.getOptions();
126
127 if (options.series.pie.show && options.grid.hoverable)
128 eventHolder.unbind('mousemove').mousemove(onMouseMove);
129
130 if (options.series.pie.show && options.grid.clickable)
131 eventHolder.unbind('click').click(onClick);
132 }
133
134
135 // debugging function that prints out an object
136 function alertObject(obj)
137 {
138 var msg = '';
139 function traverse(obj, depth)
140 {
141 if (!depth)
142 depth = 0;
143 for (var i = 0; i < obj.length; ++i)
144 {
145 for (var j=0; j<depth; j++)
146 msg += '\t';
147
148 if( typeof obj[i] == "object")
149 { // its an object
150 msg += ''+i+':\n';
151 traverse(obj[i], depth+1);
152 }
153 else
154 { // its a value
155 msg += ''+i+': '+obj[i]+'\n';
156 }
157 }
158 }
159 traverse(obj);
160 alert(msg);
161 }
162
163 function calcTotal(data)
164 {
165 for (var i = 0; i < data.length; ++i)
166 {
167 var item = parseFloat(data[i].data[0][1]);
168 if (item)
169 total += item;
170 }
171 }
172
173 function processDatapoints(plot, series, data, datapoints)
174 {
175 if (!processed)
176 {
177 processed = true;
178
179 canvas = plot.getCanvas();
180 target = $(canvas).parent();
181 options = plot.getOptions();
182
183 plot.setData(combine(plot.getData()));
184 }
185 }
186
187 function setupPie()
188 {
189 legendWidth = target.children().filter('.legend').children().width();
190
191 // calculate maximum radius and center point
192 maxRadius = Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
193 centerTop = (canvas.height/2)+options.series.pie.offset.top;
194 centerLeft = (canvas.width/2);
195
196 if (options.series.pie.offset.left=='auto')
197 if (options.legend.position.match('w'))
198 centerLeft += legendWidth/2;
199 else
200 centerLeft -= legendWidth/2;
201 else
202 centerLeft += options.series.pie.offset.left;
203
204 if (centerLeft<maxRadius)
205 centerLeft = maxRadius;
206 else if (centerLeft>canvas.width-maxRadius)
207 centerLeft = canvas.width-maxRadius;
208 }
209
210 function fixData(data)
211 {
212 for (var i = 0; i < data.length; ++i)
213 {
214 if (typeof(data[i].data)=='number')
215 data[i].data = [[1,data[i].data]];
216 else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
217 {
218 if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
219 data[i].label = data[i].data.label; // fix weirdness coming from flot
220 data[i].data = [[1,0]];
221
222 }
223 }
224 return data;
225 }
226
227 function combine(data)
228 {
229 data = fixData(data);
230 calcTotal(data);
231 var combined = 0;
232 var numCombined = 0;
233 var color = options.series.pie.combine.color;
234
235 var newdata = [];
236 for (var i = 0; i < data.length; ++i)
237 {
238 // make sure its a number
239 data[i].data[0][1] = parseFloat(data[i].data[0][1]);
240 if (!data[i].data[0][1])
241 data[i].data[0][1] = 0;
242
243 if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
244 {
245 combined += data[i].data[0][1];
246 numCombined++;
247 if (!color)
248 color = data[i].color;
249 }
250 else
251 {
252 newdata.push({
253 data: [[1,data[i].data[0][1]]],
254 color: data[i].color,
255 label: data[i].label,
256 angle: (data[i].data[0][1]*(Math.PI*2))/total,
257 percent: (data[i].data[0][1]/total*100)
258 });
259 }
260 }
261 if (numCombined>0)
262 newdata.push({
263 data: [[1,combined]],
264 color: color,
265 label: options.series.pie.combine.label,
266 angle: (combined*(Math.PI*2))/total,
267 percent: (combined/total*100)
268 });
269 return newdata;
270 }
271
272 function draw(plot, newCtx)
273 {
274 if (!target) return; // if no series were passed
275 ctx = newCtx;
276
277 setupPie();
278 var slices = plot.getData();
279
280 var attempts = 0;
281 while (redraw && attempts<redrawAttempts)
282 {
283 redraw = false;
284 if (attempts>0)
285 maxRadius *= shrink;
286 attempts += 1;
287 clear();
288 if (options.series.pie.tilt<=0.8)
289 drawShadow();
290 drawPie();
291 }
292 if (attempts >= redrawAttempts) {
293 clear();
294 target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
295 }
296
297 if ( plot.setSeries && plot.insertLegend )
298 {
299 plot.setSeries(slices);
300 plot.insertLegend();
301 }
302
303 // we're actually done at this point, just defining internal functions at this point
304
305 function clear()
306 {
307 ctx.clearRect(0,0,canvas.width,canvas.height);
308 target.children().filter('.pieLabel, .pieLabelBackground').remove();
309 }
310
311 function drawShadow()
312 {
313 var shadowLeft = 5;
314 var shadowTop = 15;
315 var edge = 10;
316 var alpha = 0.02;
317
318 // set radius
319 if (options.series.pie.radius>1)
320 var radius = options.series.pie.radius;
321 else
322 var radius = maxRadius * options.series.pie.radius;
323
324 if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
325 return; // shadow would be outside canvas, so don't draw it
326
327 ctx.save();
328 ctx.translate(shadowLeft,shadowTop);
329 ctx.globalAlpha = alpha;
330 ctx.fillStyle = '#000';
331
332 // center and rotate to starting position
333 ctx.translate(centerLeft,centerTop);
334 ctx.scale(1, options.series.pie.tilt);
335
336 //radius -= edge;
337 for (var i=1; i<=edge; i++)
338 {
339 ctx.beginPath();
340 ctx.arc(0,0,radius,0,Math.PI*2,false);
341 ctx.fill();
342 radius -= i;
343 }
344
345 ctx.restore();
346 }
347
348 function drawPie()
349 {
350 startAngle = Math.PI*options.series.pie.startAngle;
351
352 // set radius
353 if (options.series.pie.radius>1)
354 var radius = options.series.pie.radius;
355 else
356 var radius = maxRadius * options.series.pie.radius;
357
358 // center and rotate to starting position
359 ctx.save();
360 ctx.translate(centerLeft,centerTop);
361 ctx.scale(1, options.series.pie.tilt);
362 //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
363
364 // draw slices
365 ctx.save();
366 var currentAngle = startAngle;
367 for (var i = 0; i < slices.length; ++i)
368 {
369 slices[i].startAngle = currentAngle;
370 drawSlice(slices[i].angle, slices[i].color, true);
371 }
372 ctx.restore();
373
374 // draw slice outlines
375 ctx.save();
376 ctx.lineWidth = options.series.pie.stroke.width;
377 currentAngle = startAngle;
378 for (var i = 0; i < slices.length; ++i)
379 drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
380 ctx.restore();
381
382 // draw donut hole
383 drawDonutHole(ctx);
384
385 // draw labels
386 if (options.series.pie.label.show)
387 drawLabels();
388
389 // restore to original state
390 ctx.restore();
391
392 function drawSlice(angle, color, fill)
393 {
394 if (angle<=0)
395 return;
396
397 if (fill)
398 ctx.fillStyle = color;
399 else
400 {
401 ctx.strokeStyle = color;
402 ctx.lineJoin = 'round';
403 }
404
405 ctx.beginPath();
406 if (Math.abs(angle - Math.PI*2) > 0.000000001)
407 ctx.moveTo(0,0); // Center of the pie
408 else if ($.browser.msie)
409 angle -= 0.0001;
410 //ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
411 ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
412 ctx.closePath();
413 //ctx.rotate(angle); // This doesn't work properly in Opera
414 currentAngle += angle;
415
416 if (fill)
417 ctx.fill();
418 else
419 ctx.stroke();
420 }
421
422 function drawLabels()
423 {
424 var currentAngle = startAngle;
425
426 // set radius
427 if (options.series.pie.label.radius>1)
428 var radius = options.series.pie.label.radius;
429 else
430 var radius = maxRadius * options.series.pie.label.radius;
431
432 for (var i = 0; i < slices.length; ++i)
433 {
434 if (slices[i].percent >= options.series.pie.label.threshold*100)
435 drawLabel(slices[i], currentAngle, i);
436 currentAngle += slices[i].angle;
437 }
438
439 function drawLabel(slice, startAngle, index)
440 {
441 if (slice.data[0][1]==0)
442 return;
443
444 // format label text
445 var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
446 if (lf)
447 text = lf(slice.label, slice);
448 else
449 text = slice.label;
450 if (plf)
451 text = plf(text, slice);
452
453 var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
454 var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
455 var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
456
457 var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
458 target.append(html);
459 var label = target.children('#pieLabel'+index);
460 var labelTop = (y - label.height()/2);
461 var labelLeft = (x - label.width()/2);
462 label.css('top', labelTop);
463 label.css('left', labelLeft);
464
465 // check to make sure that the label is not outside the canvas
466 if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
467 redraw = true;
468
469 if (options.series.pie.label.background.opacity != 0) {
470 // put in the transparent background separately to avoid blended labels and label boxes
471 var c = options.series.pie.label.background.color;
472 if (c == null) {
473 c = slice.color;
474 }
475 var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
476 $('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
477 }
478 } // end individual label function
479 } // end drawLabels function
480 } // end drawPie function
481 } // end draw function
482
483 // Placed here because it needs to be accessed from multiple locations
484 function drawDonutHole(layer)
485 {
486 // draw donut hole
487 if(options.series.pie.innerRadius > 0)
488 {
489 // subtract the center
490 layer.save();
491 innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
492 layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
493 layer.beginPath();
494 layer.fillStyle = options.series.pie.stroke.color;
495 layer.arc(0,0,innerRadius,0,Math.PI*2,false);
496 layer.fill();
497 layer.closePath();
498 layer.restore();
499
500 // add inner stroke
501 layer.save();
502 layer.beginPath();
503 layer.strokeStyle = options.series.pie.stroke.color;
504 layer.arc(0,0,innerRadius,0,Math.PI*2,false);
505 layer.stroke();
506 layer.closePath();
507 layer.restore();
508 // TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
509 }
510 }
511
512 //-- Additional Interactive related functions --
513
514 function isPointInPoly(poly, pt)
515 {
516 for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
517 ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
518 && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
519 && (c = !c);
520 return c;
521 }
522
523 function findNearbySlice(mouseX, mouseY)
524 {
525 var slices = plot.getData(),
526 options = plot.getOptions(),
527 radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
528
529 for (var i = 0; i < slices.length; ++i)
530 {
531 var s = slices[i];
532
533 if(s.pie.show)
534 {
535 ctx.save();
536 ctx.beginPath();
537 ctx.moveTo(0,0); // Center of the pie
538 //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
539 ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
540 ctx.closePath();
541 x = mouseX-centerLeft;
542 y = mouseY-centerTop;
543 if(ctx.isPointInPath)
544 {
545 if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
546 {
547 //alert('found slice!');
548 ctx.restore();
549 return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
550 }
551 }
552 else
553 {
554 // excanvas for IE doesn;t support isPointInPath, this is a workaround.
555 p1X = (radius * Math.cos(s.startAngle));
556 p1Y = (radius * Math.sin(s.startAngle));
557 p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
558 p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
559 p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
560 p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
561 p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
562 p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
563 p5X = (radius * Math.cos(s.startAngle+s.angle));
564 p5Y = (radius * Math.sin(s.startAngle+s.angle));
565 arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
566 arrPoint = [x,y];
567 // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
568 if(isPointInPoly(arrPoly, arrPoint))
569 {
570 ctx.restore();
571 return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
572 }
573 }
574 ctx.restore();
575 }
576 }
577
578 return null;
579 }
580
581 function onMouseMove(e)
582 {
583 triggerClickHoverEvent('plothover', e);
584 }
585
586 function onClick(e)
587 {
588 triggerClickHoverEvent('plotclick', e);
589 }
590
591 // trigger click or hover event (they send the same parameters so we share their code)
592 function triggerClickHoverEvent(eventname, e)
593 {
594 var offset = plot.offset(),
595 canvasX = parseInt(e.pageX - offset.left),
596 canvasY = parseInt(e.pageY - offset.top),
597 item = findNearbySlice(canvasX, canvasY);
598
599 if (options.grid.autoHighlight)
600 {
601 // clear auto-highlights
602 for (var i = 0; i < highlights.length; ++i)
603 {
604 var h = highlights[i];
605 if (h.auto == eventname && !(item && h.series == item.series))
606 unhighlight(h.series);
607 }
608 }
609
610 // highlight the slice
611 if (item)
612 highlight(item.series, eventname);
613
614 // trigger any hover bind events
615 var pos = { pageX: e.pageX, pageY: e.pageY };
616 target.trigger(eventname, [ pos, item ]);
617 }
618
619 function highlight(s, auto)
620 {
621 if (typeof s == "number")
622 s = series[s];
623
624 var i = indexOfHighlight(s);
625 if (i == -1)
626 {
627 highlights.push({ series: s, auto: auto });
628 plot.triggerRedrawOverlay();
629 }
630 else if (!auto)
631 highlights[i].auto = false;
632 }
633
634 function unhighlight(s)
635 {
636 if (s == null)
637 {
638 highlights = [];
639 plot.triggerRedrawOverlay();
640 }
641
642 if (typeof s == "number")
643 s = series[s];
644
645 var i = indexOfHighlight(s);
646 if (i != -1)
647 {
648 highlights.splice(i, 1);
649 plot.triggerRedrawOverlay();
650 }
651 }
652
653 function indexOfHighlight(s)
654 {
655 for (var i = 0; i < highlights.length; ++i)
656 {
657 var h = highlights[i];
658 if (h.series == s)
659 return i;
660 }
661 return -1;
662 }
663
664 function drawOverlay(plot, octx)
665 {
666 //alert(options.series.pie.radius);
667 var options = plot.getOptions();
668 //alert(options.series.pie.radius);
669
670 var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
671
672 octx.save();
673 octx.translate(centerLeft, centerTop);
674 octx.scale(1, options.series.pie.tilt);
675
676 for (i = 0; i < highlights.length; ++i)
677 drawHighlight(highlights[i].series);
678
679 drawDonutHole(octx);
680
681 octx.restore();
682
683 function drawHighlight(series)
684 {
685 if (series.angle < 0) return;
686
687 //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
688 octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
689
690 octx.beginPath();
691 if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
692 octx.moveTo(0,0); // Center of the pie
693 octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
694 octx.closePath();
695 octx.fill();
696 }
697
698 }
699
700 } // end init (plugin body)
701
702 // define pie specific options and their default values
703 var options = {
704 series: {
705 pie: {
706 show: false,
707 radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
708 innerRadius:0, /* for donut */
709 startAngle: 3/2,
710 tilt: 1,
711 offset: {
712 top: 0,
713 left: 'auto'
714 },
715 stroke: {
716 color: '#FFF',
717 width: 1
718 },
719 label: {
720 show: 'auto',
721 formatter: function(label, slice){
722 return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
723 }, // formatter function
724 radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
725 background: {
726 color: null,
727 opacity: 0
728 },
729 threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
730 },
731 combine: {
732 threshold: -1, // percentage at which to combine little slices into one larger slice
733 color: null, // color to give the new slice (auto-generated if null)
734 label: 'Other' // label to give the new slice
735 },
736 highlight: {
737 //color: '#FFF', // will add this functionality once parseColor is available
738 opacity: 0.5
739 }
740 }
741 }
742 };
743
744 $.plot.plugins.push({
745 init: init,
746 options: options,
747 name: "pie",
748 version: "1.0"
749 });
750 })(jQuery);
751