OSDN Git Service

初回コミット(v2.6.17.1)
[magic3/magic3.git] / scripts / jquery / jqplot1.0 / plugins / jqplot.pieRenderer.js
1 /**
2  * jqPlot
3  * Pure JavaScript plotting plugin using jQuery
4  *
5  * Version: 1.0.4
6  * Revision: 1120
7  *
8  * Copyright (c) 2009-2012 Chris Leonello
9  * jqPlot is currently available for use in all personal or commercial projects 
10  * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 
11  * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 
12  * choose the license that best suits your project and use it accordingly. 
13  *
14  * Although not required, the author would appreciate an email letting him 
15  * know of any substantial use of jqPlot.  You can reach the author at: 
16  * chris at jqplot dot com or see http://www.jqplot.com/info.php .
17  *
18  * If you are feeling kind and generous, consider supporting the project by
19  * making a donation at: http://www.jqplot.com/donate.php .
20  *
21  * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
22  *
23  *     version 2007.04.27
24  *     author Ash Searle
25  *     http://hexmen.com/blog/2007/03/printf-sprintf/
26  *     http://hexmen.com/js/sprintf.js
27  *     The author (Ash Searle) has placed this code in the public domain:
28  *     "This code is unrestricted: you are free to use it however you like."
29  * 
30  */
31 (function($) {
32     /**
33      * Class: $.jqplot.PieRenderer
34      * Plugin renderer to draw a pie chart.
35      * x values, if present, will be used as slice labels.
36      * y values give slice size.
37      * 
38      * To use this renderer, you need to include the 
39      * pie renderer plugin, for example:
40      * 
41      * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script>
42      * 
43      * Properties described here are passed into the $.jqplot function
44      * as options on the series renderer.  For example:
45      * 
46      * > plot2 = $.jqplot('chart2', [s1, s2], {
47      * >     seriesDefaults: {
48      * >         renderer:$.jqplot.PieRenderer,
49      * >         rendererOptions:{
50      * >              sliceMargin: 2,
51      * >              startAngle: -90
52      * >          }
53      * >      }
54      * > });
55      * 
56      * A pie plot will trigger events on the plot target
57      * according to user interaction.  All events return the event object,
58      * the series index, the point (slice) index, and the point data for 
59      * the appropriate slice.
60      * 
61      * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
62      * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
63      * if highlighting is enabled.
64      * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
65      * a highlighted slice.
66      * 'jqplotDataClick' - triggered when the user clicks on a slice.
67      * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
68      * the "captureRightClick" option is set to true on the plot.
69      */
70     $.jqplot.PieRenderer = function(){
71         $.jqplot.LineRenderer.call(this);
72     };
73     
74     $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
75     $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
76     
77     // called with scope of a series
78     $.jqplot.PieRenderer.prototype.init = function(options, plot) {
79         // Group: Properties
80         //
81         // prop: diameter
82         // Outer diameter of the pie, auto computed by default
83         this.diameter = null;
84         // prop: padding
85         // padding between the pie and plot edges, legend, etc.
86         this.padding = 20;
87         // prop: sliceMargin
88         // angular spacing between pie slices in degrees.
89         this.sliceMargin = 0;
90         // prop: fill
91         // true or false, wether to fil the slices.
92         this.fill = true;
93         // prop: shadowOffset
94         // offset of the shadow from the slice and offset of 
95         // each succesive stroke of the shadow from the last.
96         this.shadowOffset = 2;
97         // prop: shadowAlpha
98         // transparency of the shadow (0 = transparent, 1 = opaque)
99         this.shadowAlpha = 0.07;
100         // prop: shadowDepth
101         // number of strokes to apply to the shadow, 
102         // each stroke offset shadowOffset from the last.
103         this.shadowDepth = 5;
104         // prop: highlightMouseOver
105         // True to highlight slice when moused over.
106         // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
107         this.highlightMouseOver = true;
108         // prop: highlightMouseDown
109         // True to highlight when a mouse button is pressed over a slice.
110         // This will be disabled if highlightMouseOver is true.
111         this.highlightMouseDown = false;
112         // prop: highlightColors
113         // an array of colors to use when highlighting a slice.
114         this.highlightColors = [];
115         // prop: dataLabels
116         // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
117         // Defaults to percentage of each pie slice.
118         this.dataLabels = 'percent';
119         // prop: showDataLabels
120         // true to show data labels on slices.
121         this.showDataLabels = false;
122         // prop: dataLabelFormatString
123         // Format string for data labels.  If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
124         this.dataLabelFormatString = null;
125         // prop: dataLabelThreshold
126         // Threshhold in percentage (0-100) of pie area, below which no label will be displayed.
127         // This applies to all label types, not just to percentage labels.
128         this.dataLabelThreshold = 3;
129         // prop: dataLabelPositionFactor
130         // A Multiplier (0-1) of the pie radius which controls position of label on slice.
131         // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
132         this.dataLabelPositionFactor = 0.52;
133         // prop: dataLabelNudge
134         // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
135         this.dataLabelNudge = 2;
136         // prop: dataLabelCenterOn
137         // True to center the data label at its position.
138         // False to set the inside facing edge of the label at its position.
139         this.dataLabelCenterOn = true;
140         // prop: startAngle
141         // Angle to start drawing pie in degrees.  
142         // According to orientation of canvas coordinate system:
143         // 0 = on the positive x axis
144         // -90 = on the positive y axis.
145         // 90 = on the negaive y axis.
146         // 180 or - 180 = on the negative x axis.
147         this.startAngle = 0;
148         this.tickRenderer = $.jqplot.PieTickRenderer;
149         // Used as check for conditions where pie shouldn't be drawn.
150         this._drawData = true;
151         this._type = 'pie';
152         
153         // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
154         if (options.highlightMouseDown && options.highlightMouseOver == null) {
155             options.highlightMouseOver = false;
156         }
157         
158         $.extend(true, this, options);
159
160         if (this.sliceMargin < 0) {
161             this.sliceMargin = 0;
162         }
163
164         this._diameter = null;
165         this._radius = null;
166         // array of [start,end] angles arrays, one for each slice.  In radians.
167         this._sliceAngles = [];
168         // index of the currenty highlighted point, if any
169         this._highlightedPoint = null;
170         
171         // set highlight colors if none provided
172         if (this.highlightColors.length == 0) {
173             for (var i=0; i<this.seriesColors.length; i++){
174                 var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
175                 var newrgb = [rgba[0], rgba[1], rgba[2]];
176                 var sum = newrgb[0] + newrgb[1] + newrgb[2];
177                 for (var j=0; j<3; j++) {
178                     // when darkening, lowest color component can be is 60.
179                     newrgb[j] = (sum > 570) ?  newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
180                     newrgb[j] = parseInt(newrgb[j], 10);
181                 }
182                 this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
183             }
184         }
185         
186         this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
187         
188         plot.postParseOptionsHooks.addOnce(postParseOptions);
189         plot.postInitHooks.addOnce(postInit);
190         plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
191         plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
192         plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
193         plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
194         plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
195         plot.postDrawHooks.addOnce(postPlotDraw);
196     };
197     
198     $.jqplot.PieRenderer.prototype.setGridData = function(plot) {
199         // set gridData property.  This will hold angle in radians of each data point.
200         var stack = [];
201         var td = [];
202         var sa = this.startAngle/180*Math.PI;
203         var tot = 0;
204         // don't know if we have any valid data yet, so set plot to not draw.
205         this._drawData = false;
206         for (var i=0; i<this.data.length; i++){
207             if (this.data[i][1] != 0) {
208                 // we have data, O.K. to draw.
209                 this._drawData = true;
210             }
211             stack.push(this.data[i][1]);
212             td.push([this.data[i][0]]);
213             if (i>0) {
214                 stack[i] += stack[i-1];
215             }
216             tot += this.data[i][1];
217         }
218         var fact = Math.PI*2/stack[stack.length - 1];
219         
220         for (var i=0; i<stack.length; i++) {
221             td[i][1] = stack[i] * fact;
222             td[i][2] = this.data[i][1]/tot;
223         }
224         this.gridData = td;
225     };
226     
227     $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) {
228         var stack = [];
229         var td = [];
230         var tot = 0;
231         var sa = this.startAngle/180*Math.PI;
232         // don't know if we have any valid data yet, so set plot to not draw.
233         this._drawData = false;
234         for (var i=0; i<data.length; i++){
235             if (this.data[i][1] != 0) {
236                 // we have data, O.K. to draw.
237                 this._drawData = true;
238             }
239             stack.push(data[i][1]);
240             td.push([data[i][0]]);
241             if (i>0) {
242                 stack[i] += stack[i-1];
243             }
244             tot += data[i][1];
245         }
246         var fact = Math.PI*2/stack[stack.length - 1];
247         
248         for (var i=0; i<stack.length; i++) {
249             td[i][1] = stack[i] * fact;
250             td[i][2] = data[i][1]/tot;
251         }
252         return td;
253     };
254
255     function calcRadiusAdjustment(ang) {
256         return Math.sin((ang - (ang-Math.PI) / 8 / Math.PI )/2.0);
257     }
258
259     function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) {
260         var rprime = 0;
261         var ang = ang2 - ang1;
262         var absang = Math.abs(ang);
263         var sm = sliceMargin;
264         if (fill == false) {
265             sm += lineWidth;
266         }
267
268         if (sm > 0 && absang > 0.01 && absang < 6.282) {
269             rprime = parseFloat(sm) / 2.0 / calcRadiusAdjustment(ang);
270         }
271
272         return rprime;
273     }
274     
275     $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
276         if (this._drawData) {
277             var r = this._radius;
278             var fill = this.fill;
279             var lineWidth = this.lineWidth;
280             var sm = this.sliceMargin;
281             if (this.fill == false) {
282                 sm += this.lineWidth;
283             }
284             ctx.save();
285             ctx.translate(this._center[0], this._center[1]);
286             
287             var rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
288
289             var transx = rprime * Math.cos((ang1 + ang2) / 2.0);
290             var transy = rprime * Math.sin((ang1 + ang2) / 2.0);
291
292             if ((ang2 - ang1) <= Math.PI) {
293                 r -= rprime;  
294             }
295             else {
296                 r += rprime;
297             }
298
299             ctx.translate(transx, transy);
300             
301             if (isShadow) {
302                 for (var i=0, l=this.shadowDepth; i<l; i++) {
303                     ctx.save();
304                     ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
305                     doDraw(r);
306                 }
307                 for (var i=0, l=this.shadowDepth; i<l; i++) {
308                     ctx.restore();
309                 }
310             }
311     
312             else {
313                 doDraw(r);
314             }
315             ctx.restore();
316         }
317     
318         function doDraw (rad) {
319             // Fix for IE and Chrome that can't seem to draw circles correctly.
320             // ang2 should always be <= 2 pi since that is the way the data is converted.
321             // 2Pi = 6.2831853, Pi = 3.1415927
322              if (ang2 > 6.282 + this.startAngle) {
323                 ang2 = 6.282 + this.startAngle;
324                 if (ang1 > ang2) {
325                     ang1 = 6.281 + this.startAngle;
326                 }
327             }
328             // Fix for IE, where it can't seem to handle 0 degree angles.  Also avoids
329             // ugly line on unfilled pies.
330             if (ang1 >= ang2) {
331                 return;
332             }            
333         
334             ctx.beginPath();  
335             ctx.fillStyle = color;
336             ctx.strokeStyle = color;
337             ctx.lineWidth = lineWidth;
338             ctx.arc(0, 0, rad, ang1, ang2, false);
339             ctx.lineTo(0,0);
340             ctx.closePath();
341         
342             if (fill) {
343                 ctx.fill();
344             }
345             else {
346                 ctx.stroke();
347             }
348         }
349     };
350     
351     // called with scope of series
352     $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) {
353         var i;
354         var opts = (options != undefined) ? options : {};
355         // offset and direction of offset due to legend placement
356         var offx = 0;
357         var offy = 0;
358         var trans = 1;
359         var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
360         if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
361             var li = options.legendInfo;
362             switch (li.location) {
363                 case 'nw':
364                     offx = li.width + li.xoffset;
365                     break;
366                 case 'w':
367                     offx = li.width + li.xoffset;
368                     break;
369                 case 'sw':
370                     offx = li.width + li.xoffset;
371                     break;
372                 case 'ne':
373                     offx = li.width + li.xoffset;
374                     trans = -1;
375                     break;
376                 case 'e':
377                     offx = li.width + li.xoffset;
378                     trans = -1;
379                     break;
380                 case 'se':
381                     offx = li.width + li.xoffset;
382                     trans = -1;
383                     break;
384                 case 'n':
385                     offy = li.height + li.yoffset;
386                     break;
387                 case 's':
388                     offy = li.height + li.yoffset;
389                     trans = -1;
390                     break;
391                 default:
392                     break;
393             }
394         }
395         
396         var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
397         var fill = (opts.fill != undefined) ? opts.fill : this.fill;
398         var cw = ctx.canvas.width;
399         var ch = ctx.canvas.height;
400         var w = cw - offx - 2 * this.padding;
401         var h = ch - offy - 2 * this.padding;
402         var mindim = Math.min(w,h);
403         var d = mindim;
404         
405         // Fixes issue #272.  Thanks hugwijst!
406         // reset slice angles array.
407         this._sliceAngles = [];
408
409         var sm = this.sliceMargin;
410         if (this.fill == false) {
411             sm += this.lineWidth;
412         }
413         
414         var rprime;
415         var maxrprime = 0;
416
417         var ang, ang1, ang2, shadowColor;
418         var sa = this.startAngle / 180 * Math.PI;
419
420         // have to pre-draw shadows, so loop throgh here and calculate some values also.
421         for (var i=0, l=gd.length; i<l; i++) {
422             ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
423             ang2 = gd[i][1] + sa;
424
425             this._sliceAngles.push([ang1, ang2]);
426
427             rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
428
429             if (Math.abs(ang2-ang1) > Math.PI) {
430                 maxrprime = Math.max(rprime, maxrprime);  
431             }
432         }
433
434         if (this.diameter != null && this.diameter > 0) {
435             this._diameter = this.diameter - 2*maxrprime;
436         }
437         else {
438             this._diameter = d - 2*maxrprime;
439         }
440
441         // Need to check for undersized pie.  This can happen if
442         // plot area too small and legend is too big.
443         if (this._diameter < 6) {
444             $.jqplot.log('Diameter of pie too small, not rendering.');
445             return;
446         }
447
448         var r = this._radius = this._diameter/2;
449
450         this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)];
451
452         if (this.shadow) {
453             for (var i=0, l=gd.length; i<l; i++) {
454                 shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
455                 this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], shadowColor, true);
456             }
457         }
458         
459         for (var i=0; i<gd.length; i++) {
460                       
461             this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], colorGenerator.next(), false);
462         
463             if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
464                 var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label;
465             
466                 if (this.dataLabels == 'label') {
467                     fstr = this.dataLabelFormatString || '%s';
468                     label = $.jqplot.sprintf(fstr, gd[i][0]);
469                 }
470                 else if (this.dataLabels == 'value') {
471                     fstr = this.dataLabelFormatString || '%d';
472                     label = $.jqplot.sprintf(fstr, this.data[i][1]);
473                 }
474                 else if (this.dataLabels == 'percent') {
475                     fstr = this.dataLabelFormatString || '%d%%';
476                     label = $.jqplot.sprintf(fstr, gd[i][2]*100);
477                 }
478                 else if (this.dataLabels.constructor == Array) {
479                     fstr = this.dataLabelFormatString || '%s';
480                     label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
481                 }
482             
483                 var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
484             
485                 var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
486                 var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
487             
488                 var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem);
489                 if (this.dataLabelCenterOn) {
490                     x -= labelelem.width()/2;
491                     y -= labelelem.height()/2;
492                 }
493                 else {
494                     x -= labelelem.width() * Math.sin(avgang/2);
495                     y -= labelelem.height()/2;
496                 }
497                 x = Math.round(x);
498                 y = Math.round(y);
499                 labelelem.css({left: x, top: y});
500             }
501         }            
502     };
503     
504     $.jqplot.PieAxisRenderer = function() {
505         $.jqplot.LinearAxisRenderer.call(this);
506     };
507     
508     $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
509     $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
510         
511     
512     // There are no traditional axes on a pie chart.  We just need to provide
513     // dummy objects with properties so the plot will render.
514     // called with scope of axis object.
515     $.jqplot.PieAxisRenderer.prototype.init = function(options){
516         //
517         this.tickRenderer = $.jqplot.PieTickRenderer;
518         $.extend(true, this, options);
519         // I don't think I'm going to need _dataBounds here.
520         // have to go Axis scaling in a way to fit chart onto plot area
521         // and provide u2p and p2u functionality for mouse cursor, etc.
522         // for convienence set _dataBounds to 0 and 100 and
523         // set min/max to 0 and 100.
524         this._dataBounds = {min:0, max:100};
525         this.min = 0;
526         this.max = 100;
527         this.showTicks = false;
528         this.ticks = [];
529         this.showMark = false;
530         this.show = false; 
531     };
532     
533     
534     
535     
536     $.jqplot.PieLegendRenderer = function(){
537         $.jqplot.TableLegendRenderer.call(this);
538     };
539     
540     $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
541     $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer;
542     
543     /**
544      * Class: $.jqplot.PieLegendRenderer
545      * Legend Renderer specific to pie plots.  Set by default
546      * when user creates a pie plot.
547      */
548     $.jqplot.PieLegendRenderer.prototype.init = function(options) {
549         // Group: Properties
550         //
551         // prop: numberRows
552         // Maximum number of rows in the legend.  0 or null for unlimited.
553         this.numberRows = null;
554         // prop: numberColumns
555         // Maximum number of columns in the legend.  0 or null for unlimited.
556         this.numberColumns = null;
557         $.extend(true, this, options);
558     };
559     
560     // called with context of legend
561     $.jqplot.PieLegendRenderer.prototype.draw = function() {
562         var legend = this;
563         if (this.show) {
564             var series = this._series;
565
566
567             this._elem = $(document.createElement('table'));
568             this._elem.addClass('jqplot-table-legend');
569
570             var ss = {position:'absolute'};
571             if (this.background) {
572                 ss['background'] = this.background;
573             }
574             if (this.border) {
575                 ss['border'] = this.border;
576             }
577             if (this.fontSize) {
578                 ss['fontSize'] = this.fontSize;
579             }
580             if (this.fontFamily) {
581                 ss['fontFamily'] = this.fontFamily;
582             }
583             if (this.textColor) {
584                 ss['textColor'] = this.textColor;
585             }
586             if (this.marginTop != null) {
587                 ss['marginTop'] = this.marginTop;
588             }
589             if (this.marginBottom != null) {
590                 ss['marginBottom'] = this.marginBottom;
591             }
592             if (this.marginLeft != null) {
593                 ss['marginLeft'] = this.marginLeft;
594             }
595             if (this.marginRight != null) {
596                 ss['marginRight'] = this.marginRight;
597             }
598
599             this._elem.css(ss);
600
601             // Pie charts legends don't go by number of series, but by number of data points
602             // in the series.  Refactor things here for that.
603             
604             var pad = false, 
605                 reverse = false,
606                 nr, 
607                 nc;
608             var s = series[0];
609             var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
610             
611             if (s.show) {
612                 var pd = s.data;
613                 if (this.numberRows) {
614                     nr = this.numberRows;
615                     if (!this.numberColumns){
616                         nc = Math.ceil(pd.length/nr);
617                     }
618                     else{
619                         nc = this.numberColumns;
620                     }
621                 }
622                 else if (this.numberColumns) {
623                     nc = this.numberColumns;
624                     nr = Math.ceil(pd.length/this.numberColumns);
625                 }
626                 else {
627                     nr = pd.length;
628                     nc = 1;
629                 }
630                 
631                 var i, j;
632                 var tr, td1, td2; 
633                 var lt, rs, color;
634                 var idx = 0; 
635                 var div0, div1;   
636                 
637                 for (i=0; i<nr; i++) {
638                     tr = $(document.createElement('tr'));
639                     tr.addClass('jqplot-table-legend');
640                     
641                     if (reverse){
642                         tr.prependTo(this._elem);
643                     }
644                     
645                     else{
646                         tr.appendTo(this._elem);
647                     }
648                     
649                     for (j=0; j<nc; j++) {
650                         if (idx < pd.length){
651                             lt = this.labels[idx] || pd[idx][0].toString();
652                             color = colorGenerator.next();
653                             if (!reverse){
654                                 if (i>0){
655                                     pad = true;
656                                 }
657                                 else{
658                                     pad = false;
659                                 }
660                             }
661                             else{
662                                 if (i == nr -1){
663                                     pad = false;
664                                 }
665                                 else{
666                                     pad = true;
667                                 }
668                             }
669                             rs = (pad) ? this.rowSpacing : '0';
670
671
672
673                             td1 = $(document.createElement('td'));
674                             td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
675                             td1.css({textAlign: 'center', paddingTop: rs});
676
677                             div0 = $(document.createElement('div'));
678                             div0.addClass('jqplot-table-legend-swatch-outline');
679                             div1 = $(document.createElement('div'));
680                             div1.addClass('jqplot-table-legend-swatch');
681                             div1.css({backgroundColor: color, borderColor: color});
682                             td1.append(div0.append(div1));
683
684                             td2 = $(document.createElement('td'));
685                             td2.addClass('jqplot-table-legend jqplot-table-legend-label');
686                             td2.css('paddingTop', rs);
687
688                             if (this.escapeHtml){
689                                 td2.text(lt);
690                             }
691                             else {
692                                 td2.html(lt);
693                             }
694                             if (reverse) {
695                                 td2.prependTo(tr);
696                                 td1.prependTo(tr);
697                             }
698                             else {
699                                 td1.appendTo(tr);
700                                 td2.appendTo(tr);
701                             }
702                             pad = true;
703                         }
704                         idx++;
705                     }   
706                 }
707             }
708         }
709         return this._elem;                
710     };
711     
712     $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) {
713         if (neighbor) {
714             var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
715             plot.target.trigger('jqplotDataMouseOver', ins);
716             if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
717                 plot.target.trigger('jqplotDataHighlight', ins);
718                 highlight (plot, ins[0], ins[1]);
719             }
720         }
721         else if (neighbor == null) {
722             unhighlight (plot);
723         }
724     };
725     
726     
727     // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
728     
729     // setup default renderers for axes and legend so user doesn't have to
730     // called with scope of plot
731     function preInit(target, data, options) {
732         options = options || {};
733         options.axesDefaults = options.axesDefaults || {};
734         options.legend = options.legend || {};
735         options.seriesDefaults = options.seriesDefaults || {};
736         // only set these if there is a pie series
737         var setopts = false;
738         if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
739             setopts = true;
740         }
741         else if (options.series) {
742             for (var i=0; i < options.series.length; i++) {
743                 if (options.series[i].renderer == $.jqplot.PieRenderer) {
744                     setopts = true;
745                 }
746             }
747         }
748         
749         if (setopts) {
750             options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
751             options.legend.renderer = $.jqplot.PieLegendRenderer;
752             options.legend.preDraw = true;
753             options.seriesDefaults.pointLabels = {show: false};
754         }
755     }
756     
757     function postInit(target, data, options) {
758         for (var i=0; i<this.series.length; i++) {
759             if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) {
760                 // don't allow mouseover and mousedown at same time.
761                 if (this.series[i].highlightMouseOver) {
762                     this.series[i].highlightMouseDown = false;
763                 }
764             }
765         }
766     }
767     
768     // called with scope of plot
769     function postParseOptions(options) {
770         for (var i=0; i<this.series.length; i++) {
771             this.series[i].seriesColors = this.seriesColors;
772             this.series[i].colorGenerator = $.jqplot.colorGenerator;
773         }
774     }
775     
776     function highlight (plot, sidx, pidx) {
777         var s = plot.series[sidx];
778         var canvas = plot.plugins.pieRenderer.highlightCanvas;
779         canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
780         s._highlightedPoint = pidx;
781         plot.plugins.pieRenderer.highlightedSeriesIndex = sidx;
782         s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false);
783     }
784     
785     function unhighlight (plot) {
786         var canvas = plot.plugins.pieRenderer.highlightCanvas;
787         canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
788         for (var i=0; i<plot.series.length; i++) {
789             plot.series[i]._highlightedPoint = null;
790         }
791         plot.plugins.pieRenderer.highlightedSeriesIndex = null;
792         plot.target.trigger('jqplotDataUnhighlight');
793     }
794  
795     function handleMove(ev, gridpos, datapos, neighbor, plot) {
796         if (neighbor) {
797             var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
798             var evt1 = jQuery.Event('jqplotDataMouseOver');
799             evt1.pageX = ev.pageX;
800             evt1.pageY = ev.pageY;
801             plot.target.trigger(evt1, ins);
802             if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
803                 var evt = jQuery.Event('jqplotDataHighlight');
804                 evt.which = ev.which;
805                 evt.pageX = ev.pageX;
806                 evt.pageY = ev.pageY;
807                 plot.target.trigger(evt, ins);
808                 highlight (plot, ins[0], ins[1]);
809             }
810         }
811         else if (neighbor == null) {
812             unhighlight (plot);
813         }
814     } 
815     
816     function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
817         if (neighbor) {
818             var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
819             if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
820                 var evt = jQuery.Event('jqplotDataHighlight');
821                 evt.which = ev.which;
822                 evt.pageX = ev.pageX;
823                 evt.pageY = ev.pageY;
824                 plot.target.trigger(evt, ins);
825                 highlight (plot, ins[0], ins[1]);
826             }
827         }
828         else if (neighbor == null) {
829             unhighlight (plot);
830         }
831     }
832     
833     function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
834         var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
835         if (idx != null && plot.series[idx].highlightMouseDown) {
836             unhighlight(plot);
837         }
838     }
839     
840     function handleClick(ev, gridpos, datapos, neighbor, plot) {
841         if (neighbor) {
842             var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
843             var evt = jQuery.Event('jqplotDataClick');
844             evt.which = ev.which;
845             evt.pageX = ev.pageX;
846             evt.pageY = ev.pageY;
847             plot.target.trigger(evt, ins);
848         }
849     }
850     
851     function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
852         if (neighbor) {
853             var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
854             var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
855             if (idx != null && plot.series[idx].highlightMouseDown) {
856                 unhighlight(plot);
857             }
858             var evt = jQuery.Event('jqplotDataRightClick');
859             evt.which = ev.which;
860             evt.pageX = ev.pageX;
861             evt.pageY = ev.pageY;
862             plot.target.trigger(evt, ins);
863         }
864     }    
865     
866     // called within context of plot
867     // create a canvas which we can draw on.
868     // insert it before the eventCanvas, so eventCanvas will still capture events.
869     function postPlotDraw() {
870         // Memory Leaks patch    
871         if (this.plugins.pieRenderer && this.plugins.pieRenderer.highlightCanvas) {
872             this.plugins.pieRenderer.highlightCanvas.resetCanvas();
873             this.plugins.pieRenderer.highlightCanvas = null;
874         }
875
876         this.plugins.pieRenderer = {highlightedSeriesIndex:null};
877         this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
878         
879         // do we have any data labels?  if so, put highlight canvas before those
880         var labels = $(this.targetId+' .jqplot-data-label');
881         if (labels.length) {
882             $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
883         }
884         // else put highlight canvas before event canvas.
885         else {
886             this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
887         }
888         
889         var hctx = this.plugins.pieRenderer.highlightCanvas.setContext();
890         this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
891     }
892     
893     $.jqplot.preInitHooks.push(preInit);
894     
895     $.jqplot.PieTickRenderer = function() {
896         $.jqplot.AxisTickRenderer.call(this);
897     };
898     
899     $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
900     $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
901     
902 })(jQuery);
903     
904