source: trunk/LATMOS-Accounts-Web/root/static/js/jqplot/plugins/jqplot.pieRenderer.js @ 1362

Last change on this file since 1362 was 1362, checked in by nanardon, 9 years ago

Add a summary page with graph

File size: 34.7 KB
Line 
1/**
2 * jqPlot
3 * Pure JavaScript plotting plugin using jQuery
4 *
5 * Version: 1.0.8
6 * Revision: 1250
7 *
8 * Copyright (c) 2009-2013 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, whether 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   
Note: See TracBrowser for help on using the repository browser.