outfielding-jqplot-rails 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +8 -4
  4. data/changes-jqplot.txt +48 -37
  5. data/copyright-jqplot.txt +17 -17
  6. data/lib/outfielding-jqplot-rails/version.rb +1 -1
  7. data/vendor/assets/javascripts/excanvas.js +1438 -1438
  8. data/vendor/assets/javascripts/jqplot-plugins/jqplot.BezierCurveRenderer.js +313 -313
  9. data/vendor/assets/javascripts/jqplot-plugins/jqplot.barRenderer.js +801 -801
  10. data/vendor/assets/javascripts/jqplot-plugins/jqplot.blockRenderer.js +234 -234
  11. data/vendor/assets/javascripts/jqplot-plugins/jqplot.bubbleRenderer.js +758 -758
  12. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasAxisLabelRenderer.js +202 -202
  13. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasAxisTickRenderer.js +252 -252
  14. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasOverlay.js +1020 -1020
  15. data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasTextRenderer.js +448 -448
  16. data/vendor/assets/javascripts/jqplot-plugins/jqplot.categoryAxisRenderer.js +679 -679
  17. data/vendor/assets/javascripts/jqplot-plugins/jqplot.ciParser.js +115 -115
  18. data/vendor/assets/javascripts/jqplot-plugins/jqplot.cursor.js +1108 -1108
  19. data/vendor/assets/javascripts/jqplot-plugins/jqplot.dateAxisRenderer.js +741 -741
  20. data/vendor/assets/javascripts/jqplot-plugins/jqplot.donutRenderer.js +816 -805
  21. data/vendor/assets/javascripts/jqplot-plugins/jqplot.dragable.js +224 -224
  22. data/vendor/assets/javascripts/jqplot-plugins/jqplot.enhancedLegendRenderer.js +305 -305
  23. data/vendor/assets/javascripts/jqplot-plugins/jqplot.enhancedPieLegendRenderer.js +261 -0
  24. data/vendor/assets/javascripts/jqplot-plugins/jqplot.funnelRenderer.js +942 -942
  25. data/vendor/assets/javascripts/jqplot-plugins/jqplot.highlighter.js +464 -464
  26. data/vendor/assets/javascripts/jqplot-plugins/jqplot.json2.js +475 -475
  27. data/vendor/assets/javascripts/jqplot-plugins/jqplot.logAxisRenderer.js +533 -533
  28. data/vendor/assets/javascripts/jqplot-plugins/jqplot.mekkoAxisRenderer.js +611 -611
  29. data/vendor/assets/javascripts/jqplot-plugins/jqplot.mekkoRenderer.js +437 -437
  30. data/vendor/assets/javascripts/jqplot-plugins/jqplot.meterGaugeRenderer.js +1029 -1029
  31. data/vendor/assets/javascripts/jqplot-plugins/jqplot.mobile.js +2 -2
  32. data/vendor/assets/javascripts/jqplot-plugins/jqplot.ohlcRenderer.js +373 -373
  33. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pieRenderer.js +945 -903
  34. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pointLabels.js +379 -377
  35. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidAxisRenderer.js +728 -728
  36. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidGridRenderer.js +428 -428
  37. data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidRenderer.js +513 -513
  38. data/vendor/assets/javascripts/jqplot-plugins/jqplot.trendline.js +222 -222
  39. data/vendor/assets/javascripts/jquery.jqplot.js +11477 -11411
  40. data/vendor/assets/stylesheets/jquery.jqplot.css +259 -259
  41. metadata +9 -10
@@ -1,805 +1,816 @@
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.DonutRenderer
34
- * Plugin renderer to draw a donut 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
- * donut renderer plugin, for example:
40
- *
41
- * > <script type="text/javascript" src="plugins/jqplot.donutRenderer.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.DonutRenderer,
49
- * > rendererOptions:{
50
- * > sliceMargin: 2,
51
- * > innerDiameter: 110,
52
- * > startAngle: -90
53
- * > }
54
- * > }
55
- * > });
56
- *
57
- * A donut plot will trigger events on the plot target
58
- * according to user interaction. All events return the event object,
59
- * the series index, the point (slice) index, and the point data for
60
- * the appropriate slice.
61
- *
62
- * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
63
- * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
64
- * if highlighting is enabled.
65
- * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
66
- * a highlighted slice.
67
- * 'jqplotDataClick' - triggered when the user clicks on a slice.
68
- * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
69
- * the "captureRightClick" option is set to true on the plot.
70
- */
71
- $.jqplot.DonutRenderer = function(){
72
- $.jqplot.LineRenderer.call(this);
73
- };
74
-
75
- $.jqplot.DonutRenderer.prototype = new $.jqplot.LineRenderer();
76
- $.jqplot.DonutRenderer.prototype.constructor = $.jqplot.DonutRenderer;
77
-
78
- // called with scope of a series
79
- $.jqplot.DonutRenderer.prototype.init = function(options, plot) {
80
- // Group: Properties
81
- //
82
- // prop: diameter
83
- // Outer diameter of the donut, auto computed by default
84
- this.diameter = null;
85
- // prop: innerDiameter
86
- // Inner diameter of the donut, auto calculated by default.
87
- // If specified will override thickness value.
88
- this.innerDiameter = null;
89
- // prop: thickness
90
- // thickness of the donut, auto computed by default
91
- // Overridden by if innerDiameter is specified.
92
- this.thickness = null;
93
- // prop: padding
94
- // padding between the donut and plot edges, legend, etc.
95
- this.padding = 20;
96
- // prop: sliceMargin
97
- // angular spacing between donut slices in degrees.
98
- this.sliceMargin = 0;
99
- // prop: ringMargin
100
- // pixel distance between rings, or multiple series in a donut plot.
101
- // null will compute ringMargin based on sliceMargin.
102
- this.ringMargin = null;
103
- // prop: fill
104
- // true or false, whether to fil the slices.
105
- this.fill = true;
106
- // prop: shadowOffset
107
- // offset of the shadow from the slice and offset of
108
- // each succesive stroke of the shadow from the last.
109
- this.shadowOffset = 2;
110
- // prop: shadowAlpha
111
- // transparency of the shadow (0 = transparent, 1 = opaque)
112
- this.shadowAlpha = 0.07;
113
- // prop: shadowDepth
114
- // number of strokes to apply to the shadow,
115
- // each stroke offset shadowOffset from the last.
116
- this.shadowDepth = 5;
117
- // prop: highlightMouseOver
118
- // True to highlight slice when moused over.
119
- // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
120
- this.highlightMouseOver = true;
121
- // prop: highlightMouseDown
122
- // True to highlight when a mouse button is pressed over a slice.
123
- // This will be disabled if highlightMouseOver is true.
124
- this.highlightMouseDown = false;
125
- // prop: highlightColors
126
- // an array of colors to use when highlighting a slice.
127
- this.highlightColors = [];
128
- // prop: dataLabels
129
- // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
130
- // Defaults to percentage of each pie slice.
131
- this.dataLabels = 'percent';
132
- // prop: showDataLabels
133
- // true to show data labels on slices.
134
- this.showDataLabels = false;
135
- // prop: dataLabelFormatString
136
- // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
137
- this.dataLabelFormatString = null;
138
- // prop: dataLabelThreshold
139
- // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
140
- // This applies to all label types, not just to percentage labels.
141
- this.dataLabelThreshold = 3;
142
- // prop: dataLabelPositionFactor
143
- // A Multiplier (0-1) of the pie radius which controls position of label on slice.
144
- // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
145
- this.dataLabelPositionFactor = 0.4;
146
- // prop: dataLabelNudge
147
- // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
148
- this.dataLabelNudge = 0;
149
- // prop: startAngle
150
- // Angle to start drawing donut in degrees.
151
- // According to orientation of canvas coordinate system:
152
- // 0 = on the positive x axis
153
- // -90 = on the positive y axis.
154
- // 90 = on the negaive y axis.
155
- // 180 or - 180 = on the negative x axis.
156
- this.startAngle = 0;
157
- this.tickRenderer = $.jqplot.DonutTickRenderer;
158
- // Used as check for conditions where donut shouldn't be drawn.
159
- this._drawData = true;
160
- this._type = 'donut';
161
-
162
- // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
163
- if (options.highlightMouseDown && options.highlightMouseOver == null) {
164
- options.highlightMouseOver = false;
165
- }
166
-
167
- $.extend(true, this, options);
168
- if (this.diameter != null) {
169
- this.diameter = this.diameter - this.sliceMargin;
170
- }
171
- this._diameter = null;
172
- this._innerDiameter = null;
173
- this._radius = null;
174
- this._innerRadius = null;
175
- this._thickness = null;
176
- // references to the previous series in the plot to properly calculate diameters
177
- // and thicknesses of nested rings.
178
- this._previousSeries = [];
179
- this._numberSeries = 1;
180
- // array of [start,end] angles arrays, one for each slice. In radians.
181
- this._sliceAngles = [];
182
- // index of the currenty highlighted point, if any
183
- this._highlightedPoint = null;
184
-
185
- // set highlight colors if none provided
186
- if (this.highlightColors.length == 0) {
187
- for (var i=0; i<this.seriesColors.length; i++){
188
- var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
189
- var newrgb = [rgba[0], rgba[1], rgba[2]];
190
- var sum = newrgb[0] + newrgb[1] + newrgb[2];
191
- for (var j=0; j<3; j++) {
192
- // when darkening, lowest color component can be is 60.
193
- newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
194
- newrgb[j] = parseInt(newrgb[j], 10);
195
- }
196
- this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
197
- }
198
- }
199
-
200
- plot.postParseOptionsHooks.addOnce(postParseOptions);
201
- plot.postInitHooks.addOnce(postInit);
202
- plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
203
- plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
204
- plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
205
- plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
206
- plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
207
- plot.postDrawHooks.addOnce(postPlotDraw);
208
-
209
-
210
- };
211
-
212
- $.jqplot.DonutRenderer.prototype.setGridData = function(plot) {
213
- // set gridData property. This will hold angle in radians of each data point.
214
- var stack = [];
215
- var td = [];
216
- var sa = this.startAngle/180*Math.PI;
217
- var tot = 0;
218
- // don't know if we have any valid data yet, so set plot to not draw.
219
- this._drawData = false;
220
- for (var i=0; i<this.data.length; i++){
221
- if (this.data[i][1] != 0) {
222
- // we have data, O.K. to draw.
223
- this._drawData = true;
224
- }
225
- stack.push(this.data[i][1]);
226
- td.push([this.data[i][0]]);
227
- if (i>0) {
228
- stack[i] += stack[i-1];
229
- }
230
- tot += this.data[i][1];
231
- }
232
- var fact = Math.PI*2/stack[stack.length - 1];
233
-
234
- for (var i=0; i<stack.length; i++) {
235
- td[i][1] = stack[i] * fact;
236
- td[i][2] = this.data[i][1]/tot;
237
- }
238
- this.gridData = td;
239
- };
240
-
241
- $.jqplot.DonutRenderer.prototype.makeGridData = function(data, plot) {
242
- var stack = [];
243
- var td = [];
244
- var tot = 0;
245
- var sa = this.startAngle/180*Math.PI;
246
- // don't know if we have any valid data yet, so set plot to not draw.
247
- this._drawData = false;
248
- for (var i=0; i<data.length; i++){
249
- if (this.data[i][1] != 0) {
250
- // we have data, O.K. to draw.
251
- this._drawData = true;
252
- }
253
- stack.push(data[i][1]);
254
- td.push([data[i][0]]);
255
- if (i>0) {
256
- stack[i] += stack[i-1];
257
- }
258
- tot += data[i][1];
259
- }
260
- var fact = Math.PI*2/stack[stack.length - 1];
261
-
262
- for (var i=0; i<stack.length; i++) {
263
- td[i][1] = stack[i] * fact;
264
- td[i][2] = data[i][1]/tot;
265
- }
266
- return td;
267
- };
268
-
269
- $.jqplot.DonutRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
270
- var r = this._diameter / 2;
271
- var ri = r - this._thickness;
272
- var fill = this.fill;
273
- // var lineWidth = this.lineWidth;
274
- ctx.save();
275
- ctx.translate(this._center[0], this._center[1]);
276
- // ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2));
277
-
278
- if (isShadow) {
279
- for (var i=0; i<this.shadowDepth; i++) {
280
- ctx.save();
281
- ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
282
- doDraw();
283
- }
284
- }
285
-
286
- else {
287
- doDraw();
288
- }
289
-
290
- function doDraw () {
291
- // Fix for IE and Chrome that can't seem to draw circles correctly.
292
- // ang2 should always be <= 2 pi since that is the way the data is converted.
293
- if (ang2 > 6.282 + this.startAngle) {
294
- ang2 = 6.282 + this.startAngle;
295
- if (ang1 > ang2) {
296
- ang1 = 6.281 + this.startAngle;
297
- }
298
- }
299
- // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
300
- // ugly line on unfilled donuts.
301
- if (ang1 >= ang2) {
302
- return;
303
- }
304
- ctx.beginPath();
305
- ctx.fillStyle = color;
306
- ctx.strokeStyle = color;
307
- // ctx.lineWidth = lineWidth;
308
- ctx.arc(0, 0, r, ang1, ang2, false);
309
- ctx.lineTo(ri*Math.cos(ang2), ri*Math.sin(ang2));
310
- ctx.arc(0,0, ri, ang2, ang1, true);
311
- ctx.closePath();
312
- if (fill) {
313
- ctx.fill();
314
- }
315
- else {
316
- ctx.stroke();
317
- }
318
- }
319
-
320
- if (isShadow) {
321
- for (var i=0; i<this.shadowDepth; i++) {
322
- ctx.restore();
323
- }
324
- }
325
-
326
- ctx.restore();
327
- };
328
-
329
- // called with scope of series
330
- $.jqplot.DonutRenderer.prototype.draw = function (ctx, gd, options, plot) {
331
- var i;
332
- var opts = (options != undefined) ? options : {};
333
- // offset and direction of offset due to legend placement
334
- var offx = 0;
335
- var offy = 0;
336
- var trans = 1;
337
- // var colorGenerator = new this.colorGenerator(this.seriesColors);
338
- if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
339
- var li = options.legendInfo;
340
- switch (li.location) {
341
- case 'nw':
342
- offx = li.width + li.xoffset;
343
- break;
344
- case 'w':
345
- offx = li.width + li.xoffset;
346
- break;
347
- case 'sw':
348
- offx = li.width + li.xoffset;
349
- break;
350
- case 'ne':
351
- offx = li.width + li.xoffset;
352
- trans = -1;
353
- break;
354
- case 'e':
355
- offx = li.width + li.xoffset;
356
- trans = -1;
357
- break;
358
- case 'se':
359
- offx = li.width + li.xoffset;
360
- trans = -1;
361
- break;
362
- case 'n':
363
- offy = li.height + li.yoffset;
364
- break;
365
- case 's':
366
- offy = li.height + li.yoffset;
367
- trans = -1;
368
- break;
369
- default:
370
- break;
371
- }
372
- }
373
-
374
- var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
375
- var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
376
- var fill = (opts.fill != undefined) ? opts.fill : this.fill;
377
- var cw = ctx.canvas.width;
378
- var ch = ctx.canvas.height;
379
- var w = cw - offx - 2 * this.padding;
380
- var h = ch - offy - 2 * this.padding;
381
- var mindim = Math.min(w,h);
382
- var d = mindim;
383
- var ringmargin = (this.ringMargin == null) ? this.sliceMargin * 2.0 : this.ringMargin;
384
-
385
- for (var i=0; i<this._previousSeries.length; i++) {
386
- d -= 2.0 * this._previousSeries[i]._thickness + 2.0 * ringmargin;
387
- }
388
- this._diameter = this.diameter || d;
389
- if (this.innerDiameter != null) {
390
- var od = (this._numberSeries > 1 && this.index > 0) ? this._previousSeries[0]._diameter : this._diameter;
391
- this._thickness = this.thickness || (od - this.innerDiameter - 2.0*ringmargin*this._numberSeries) / this._numberSeries/2.0;
392
- }
393
- else {
394
- this._thickness = this.thickness || mindim / 2 / (this._numberSeries + 1) * 0.85;
395
- }
396
-
397
- var r = this._radius = this._diameter/2;
398
- this._innerRadius = this._radius - this._thickness;
399
- var sa = this.startAngle / 180 * Math.PI;
400
- this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
401
-
402
- if (this.shadow) {
403
- var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
404
- for (var i=0; i<gd.length; i++) {
405
- var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
406
- // Adjust ang1 and ang2 for sliceMargin
407
- ang1 += this.sliceMargin/180*Math.PI;
408
- this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true);
409
- }
410
-
411
- }
412
- for (var i=0; i<gd.length; i++) {
413
- var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
414
- // Adjust ang1 and ang2 for sliceMargin
415
- ang1 += this.sliceMargin/180*Math.PI;
416
- var ang2 = gd[i][1] + sa;
417
- this._sliceAngles.push([ang1, ang2]);
418
- this.renderer.drawSlice.call (this, ctx, ang1, ang2, this.seriesColors[i], false);
419
-
420
- if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
421
- var fstr, avgang = (ang1+ang2)/2, label;
422
-
423
- if (this.dataLabels == 'label') {
424
- fstr = this.dataLabelFormatString || '%s';
425
- label = $.jqplot.sprintf(fstr, gd[i][0]);
426
- }
427
- else if (this.dataLabels == 'value') {
428
- fstr = this.dataLabelFormatString || '%d';
429
- label = $.jqplot.sprintf(fstr, this.data[i][1]);
430
- }
431
- else if (this.dataLabels == 'percent') {
432
- fstr = this.dataLabelFormatString || '%d%%';
433
- label = $.jqplot.sprintf(fstr, gd[i][2]*100);
434
- }
435
- else if (this.dataLabels.constructor == Array) {
436
- fstr = this.dataLabelFormatString || '%s';
437
- label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
438
- }
439
-
440
- var fact = this._innerRadius + this._thickness * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
441
-
442
- var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
443
- var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
444
-
445
- var labelelem = $('<span class="jqplot-donut-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
446
- x -= labelelem.width()/2;
447
- y -= labelelem.height()/2;
448
- x = Math.round(x);
449
- y = Math.round(y);
450
- labelelem.css({left: x, top: y});
451
- }
452
- }
453
-
454
- };
455
-
456
- $.jqplot.DonutAxisRenderer = function() {
457
- $.jqplot.LinearAxisRenderer.call(this);
458
- };
459
-
460
- $.jqplot.DonutAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
461
- $.jqplot.DonutAxisRenderer.prototype.constructor = $.jqplot.DonutAxisRenderer;
462
-
463
-
464
- // There are no traditional axes on a donut chart. We just need to provide
465
- // dummy objects with properties so the plot will render.
466
- // called with scope of axis object.
467
- $.jqplot.DonutAxisRenderer.prototype.init = function(options){
468
- //
469
- this.tickRenderer = $.jqplot.DonutTickRenderer;
470
- $.extend(true, this, options);
471
- // I don't think I'm going to need _dataBounds here.
472
- // have to go Axis scaling in a way to fit chart onto plot area
473
- // and provide u2p and p2u functionality for mouse cursor, etc.
474
- // for convienence set _dataBounds to 0 and 100 and
475
- // set min/max to 0 and 100.
476
- this._dataBounds = {min:0, max:100};
477
- this.min = 0;
478
- this.max = 100;
479
- this.showTicks = false;
480
- this.ticks = [];
481
- this.showMark = false;
482
- this.show = false;
483
- };
484
-
485
-
486
-
487
-
488
- $.jqplot.DonutLegendRenderer = function(){
489
- $.jqplot.TableLegendRenderer.call(this);
490
- };
491
-
492
- $.jqplot.DonutLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
493
- $.jqplot.DonutLegendRenderer.prototype.constructor = $.jqplot.DonutLegendRenderer;
494
-
495
- /**
496
- * Class: $.jqplot.DonutLegendRenderer
497
- * Legend Renderer specific to donut plots. Set by default
498
- * when user creates a donut plot.
499
- */
500
- $.jqplot.DonutLegendRenderer.prototype.init = function(options) {
501
- // Group: Properties
502
- //
503
- // prop: numberRows
504
- // Maximum number of rows in the legend. 0 or null for unlimited.
505
- this.numberRows = null;
506
- // prop: numberColumns
507
- // Maximum number of columns in the legend. 0 or null for unlimited.
508
- this.numberColumns = null;
509
- $.extend(true, this, options);
510
- };
511
-
512
- // called with context of legend
513
- $.jqplot.DonutLegendRenderer.prototype.draw = function() {
514
- var legend = this;
515
- if (this.show) {
516
- var series = this._series;
517
- var ss = 'position:absolute;';
518
- ss += (this.background) ? 'background:'+this.background+';' : '';
519
- ss += (this.border) ? 'border:'+this.border+';' : '';
520
- ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
521
- ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
522
- ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
523
- ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
524
- ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
525
- ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
526
- ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
527
- this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
528
- // Donut charts legends don't go by number of series, but by number of data points
529
- // in the series. Refactor things here for that.
530
-
531
- var pad = false,
532
- reverse = false,
533
- nr, nc;
534
- var s = series[0];
535
- var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
536
-
537
- if (s.show) {
538
- var pd = s.data;
539
- if (this.numberRows) {
540
- nr = this.numberRows;
541
- if (!this.numberColumns){
542
- nc = Math.ceil(pd.length/nr);
543
- }
544
- else{
545
- nc = this.numberColumns;
546
- }
547
- }
548
- else if (this.numberColumns) {
549
- nc = this.numberColumns;
550
- nr = Math.ceil(pd.length/this.numberColumns);
551
- }
552
- else {
553
- nr = pd.length;
554
- nc = 1;
555
- }
556
-
557
- var i, j, tr, td1, td2, lt, rs, color;
558
- var idx = 0;
559
-
560
- for (i=0; i<nr; i++) {
561
- if (reverse){
562
- tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
563
- }
564
- else{
565
- tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
566
- }
567
- for (j=0; j<nc; j++) {
568
- if (idx < pd.length){
569
- lt = this.labels[idx] || pd[idx][0].toString();
570
- color = colorGenerator.next();
571
- if (!reverse){
572
- if (i>0){
573
- pad = true;
574
- }
575
- else{
576
- pad = false;
577
- }
578
- }
579
- else{
580
- if (i == nr -1){
581
- pad = false;
582
- }
583
- else{
584
- pad = true;
585
- }
586
- }
587
- rs = (pad) ? this.rowSpacing : '0';
588
-
589
- td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
590
- '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
591
- '</div></td>');
592
- td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
593
- if (this.escapeHtml){
594
- td2.text(lt);
595
- }
596
- else {
597
- td2.html(lt);
598
- }
599
- if (reverse) {
600
- td2.prependTo(tr);
601
- td1.prependTo(tr);
602
- }
603
- else {
604
- td1.appendTo(tr);
605
- td2.appendTo(tr);
606
- }
607
- pad = true;
608
- }
609
- idx++;
610
- }
611
- }
612
- }
613
- }
614
- return this._elem;
615
- };
616
-
617
- // setup default renderers for axes and legend so user doesn't have to
618
- // called with scope of plot
619
- function preInit(target, data, options) {
620
- options = options || {};
621
- options.axesDefaults = options.axesDefaults || {};
622
- options.legend = options.legend || {};
623
- options.seriesDefaults = options.seriesDefaults || {};
624
- // only set these if there is a donut series
625
- var setopts = false;
626
- if (options.seriesDefaults.renderer == $.jqplot.DonutRenderer) {
627
- setopts = true;
628
- }
629
- else if (options.series) {
630
- for (var i=0; i < options.series.length; i++) {
631
- if (options.series[i].renderer == $.jqplot.DonutRenderer) {
632
- setopts = true;
633
- }
634
- }
635
- }
636
-
637
- if (setopts) {
638
- options.axesDefaults.renderer = $.jqplot.DonutAxisRenderer;
639
- options.legend.renderer = $.jqplot.DonutLegendRenderer;
640
- options.legend.preDraw = true;
641
- options.seriesDefaults.pointLabels = {show: false};
642
- }
643
- }
644
-
645
- // called with scope of plot.
646
- function postInit(target, data, options) {
647
- // if multiple series, add a reference to the previous one so that
648
- // donut rings can nest.
649
- for (var i=1; i<this.series.length; i++) {
650
- if (!this.series[i]._previousSeries.length){
651
- for (var j=0; j<i; j++) {
652
- if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer && this.series[j].renderer.constructor == $.jqplot.DonutRenderer) {
653
- this.series[i]._previousSeries.push(this.series[j]);
654
- }
655
- }
656
- }
657
- }
658
- for (i=0; i<this.series.length; i++) {
659
- if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer) {
660
- this.series[i]._numberSeries = this.series.length;
661
- // don't allow mouseover and mousedown at same time.
662
- if (this.series[i].highlightMouseOver) {
663
- this.series[i].highlightMouseDown = false;
664
- }
665
- }
666
- }
667
- }
668
-
669
- var postParseOptionsRun = false;
670
- // called with scope of plot
671
- function postParseOptions(options) {
672
- for (var i=0; i<this.series.length; i++) {
673
- this.series[i].seriesColors = this.seriesColors;
674
- this.series[i].colorGenerator = $.jqplot.colorGenerator;
675
- }
676
- }
677
-
678
- function highlight (plot, sidx, pidx) {
679
- var s = plot.series[sidx];
680
- var canvas = plot.plugins.donutRenderer.highlightCanvas;
681
- canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
682
- s._highlightedPoint = pidx;
683
- plot.plugins.donutRenderer.highlightedSeriesIndex = sidx;
684
- s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColors[pidx], false);
685
- }
686
-
687
- function unhighlight (plot) {
688
- var canvas = plot.plugins.donutRenderer.highlightCanvas;
689
- canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
690
- for (var i=0; i<plot.series.length; i++) {
691
- plot.series[i]._highlightedPoint = null;
692
- }
693
- plot.plugins.donutRenderer.highlightedSeriesIndex = null;
694
- plot.target.trigger('jqplotDataUnhighlight');
695
- }
696
-
697
- function handleMove(ev, gridpos, datapos, neighbor, plot) {
698
- if (neighbor) {
699
- var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
700
- var evt1 = jQuery.Event('jqplotDataMouseOver');
701
- evt1.pageX = ev.pageX;
702
- evt1.pageY = ev.pageY;
703
- plot.target.trigger(evt1, ins);
704
- if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
705
- var evt = jQuery.Event('jqplotDataHighlight');
706
- evt.which = ev.which;
707
- evt.pageX = ev.pageX;
708
- evt.pageY = ev.pageY;
709
- plot.target.trigger(evt, ins);
710
- highlight (plot, ins[0], ins[1]);
711
- }
712
- }
713
- else if (neighbor == null) {
714
- unhighlight (plot);
715
- }
716
- }
717
-
718
- function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
719
- if (neighbor) {
720
- var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
721
- if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
722
- var evt = jQuery.Event('jqplotDataHighlight');
723
- evt.which = ev.which;
724
- evt.pageX = ev.pageX;
725
- evt.pageY = ev.pageY;
726
- plot.target.trigger(evt, ins);
727
- highlight (plot, ins[0], ins[1]);
728
- }
729
- }
730
- else if (neighbor == null) {
731
- unhighlight (plot);
732
- }
733
- }
734
-
735
- function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
736
- var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
737
- if (idx != null && plot.series[idx].highlightMouseDown) {
738
- unhighlight(plot);
739
- }
740
- }
741
-
742
- function handleClick(ev, gridpos, datapos, neighbor, plot) {
743
- if (neighbor) {
744
- var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
745
- var evt = jQuery.Event('jqplotDataClick');
746
- evt.which = ev.which;
747
- evt.pageX = ev.pageX;
748
- evt.pageY = ev.pageY;
749
- plot.target.trigger(evt, ins);
750
- }
751
- }
752
-
753
- function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
754
- if (neighbor) {
755
- var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
756
- var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
757
- if (idx != null && plot.series[idx].highlightMouseDown) {
758
- unhighlight(plot);
759
- }
760
- var evt = jQuery.Event('jqplotDataRightClick');
761
- evt.which = ev.which;
762
- evt.pageX = ev.pageX;
763
- evt.pageY = ev.pageY;
764
- plot.target.trigger(evt, ins);
765
- }
766
- }
767
-
768
- // called within context of plot
769
- // create a canvas which we can draw on.
770
- // insert it before the eventCanvas, so eventCanvas will still capture events.
771
- function postPlotDraw() {
772
- // Memory Leaks patch
773
- if (this.plugins.donutRenderer && this.plugins.donutRenderer.highlightCanvas) {
774
- this.plugins.donutRenderer.highlightCanvas.resetCanvas();
775
- this.plugins.donutRenderer.highlightCanvas = null;
776
- }
777
-
778
- this.plugins.donutRenderer = {highlightedSeriesIndex:null};
779
- this.plugins.donutRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
780
- // do we have any data labels? if so, put highlight canvas before those
781
- // Fix for broken jquery :first selector with canvas (VML) elements.
782
- var labels = $(this.targetId+' .jqplot-data-label');
783
- if (labels.length) {
784
- $(labels[0]).before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
785
- }
786
- // else put highlight canvas before event canvas.
787
- else {
788
- this.eventCanvas._elem.before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
789
- }
790
- var hctx = this.plugins.donutRenderer.highlightCanvas.setContext();
791
- this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
792
- }
793
-
794
- $.jqplot.preInitHooks.push(preInit);
795
-
796
- $.jqplot.DonutTickRenderer = function() {
797
- $.jqplot.AxisTickRenderer.call(this);
798
- };
799
-
800
- $.jqplot.DonutTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
801
- $.jqplot.DonutTickRenderer.prototype.constructor = $.jqplot.DonutTickRenderer;
802
-
803
- })(jQuery);
804
-
805
-
1
+ /**
2
+ * jqPlot
3
+ * Pure JavaScript plotting plugin using jQuery
4
+ *
5
+ * Version: 1.0.9
6
+ * Revision: d96a669
7
+ *
8
+ * Copyright (c) 2009-2016 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.DonutRenderer
34
+ * Plugin renderer to draw a donut 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
+ * donut renderer plugin, for example:
40
+ *
41
+ * > <script type="text/javascript" src="plugins/jqplot.donutRenderer.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.DonutRenderer,
49
+ * > rendererOptions:{
50
+ * > sliceMargin: 2,
51
+ * > innerDiameter: 110,
52
+ * > startAngle: -90
53
+ * > }
54
+ * > }
55
+ * > });
56
+ *
57
+ * A donut plot will trigger events on the plot target
58
+ * according to user interaction. All events return the event object,
59
+ * the series index, the point (slice) index, and the point data for
60
+ * the appropriate slice.
61
+ *
62
+ * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
63
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
64
+ * if highlighting is enabled.
65
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
66
+ * a highlighted slice.
67
+ * 'jqplotDataClick' - triggered when the user clicks on a slice.
68
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
69
+ * the "captureRightClick" option is set to true on the plot.
70
+ */
71
+ $.jqplot.DonutRenderer = function(){
72
+ $.jqplot.LineRenderer.call(this);
73
+ };
74
+
75
+ $.jqplot.DonutRenderer.prototype = new $.jqplot.LineRenderer();
76
+ $.jqplot.DonutRenderer.prototype.constructor = $.jqplot.DonutRenderer;
77
+
78
+ // called with scope of a series
79
+ $.jqplot.DonutRenderer.prototype.init = function(options, plot) {
80
+ // Group: Properties
81
+ //
82
+ // prop: diameter
83
+ // Outer diameter of the donut, auto computed by default
84
+ this.diameter = null;
85
+ // prop: innerDiameter
86
+ // Inner diameter of the donut, auto calculated by default.
87
+ // If specified will override thickness value.
88
+ this.innerDiameter = null;
89
+ // prop: thickness
90
+ // thickness of the donut, auto computed by default
91
+ // Overridden by if innerDiameter is specified.
92
+ this.thickness = null;
93
+ // prop: padding
94
+ // padding between the donut and plot edges, legend, etc.
95
+ this.padding = 20;
96
+ // prop: sliceMargin
97
+ // angular spacing between donut slices in degrees.
98
+ this.sliceMargin = 0;
99
+ // prop: ringMargin
100
+ // pixel distance between rings, or multiple series in a donut plot.
101
+ // null will compute ringMargin based on sliceMargin.
102
+ this.ringMargin = null;
103
+ // prop: fill
104
+ // true or false, whether to fil the slices.
105
+ this.fill = true;
106
+ // prop: shadowOffset
107
+ // offset of the shadow from the slice and offset of
108
+ // each succesive stroke of the shadow from the last.
109
+ this.shadowOffset = 2;
110
+ // prop: shadowAlpha
111
+ // transparency of the shadow (0 = transparent, 1 = opaque)
112
+ this.shadowAlpha = 0.07;
113
+ // prop: shadowDepth
114
+ // number of strokes to apply to the shadow,
115
+ // each stroke offset shadowOffset from the last.
116
+ this.shadowDepth = 5;
117
+ // prop: highlightMouseOver
118
+ // True to highlight slice when moused over.
119
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
120
+ this.highlightMouseOver = true;
121
+ // prop: highlightMouseDown
122
+ // True to highlight when a mouse button is pressed over a slice.
123
+ // This will be disabled if highlightMouseOver is true.
124
+ this.highlightMouseDown = false;
125
+ // prop: highlightColors
126
+ // an array of colors to use when highlighting a slice.
127
+ this.highlightColors = [];
128
+ // prop: dataLabels
129
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
130
+ // Defaults to percentage of each pie slice.
131
+ this.dataLabels = 'percent';
132
+ // prop: showDataLabels
133
+ // true to show data labels on slices.
134
+ this.showDataLabels = false;
135
+ // prop: totalLabel
136
+ // true to show total label in the centre
137
+ this.totalLabel = false;
138
+ // prop: dataLabelFormatString
139
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
140
+ this.dataLabelFormatString = null;
141
+ // prop: dataLabelThreshold
142
+ // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
143
+ // This applies to all label types, not just to percentage labels.
144
+ this.dataLabelThreshold = 3;
145
+ // prop: dataLabelPositionFactor
146
+ // A Multiplier (0-1) of the pie radius which controls position of label on slice.
147
+ // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
148
+ this.dataLabelPositionFactor = 0.4;
149
+ // prop: dataLabelNudge
150
+ // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
151
+ this.dataLabelNudge = 0;
152
+ // prop: startAngle
153
+ // Angle to start drawing donut in degrees.
154
+ // According to orientation of canvas coordinate system:
155
+ // 0 = on the positive x axis
156
+ // -90 = on the positive y axis.
157
+ // 90 = on the negaive y axis.
158
+ // 180 or - 180 = on the negative x axis.
159
+ this.startAngle = 0;
160
+ this.tickRenderer = $.jqplot.DonutTickRenderer;
161
+ // Used as check for conditions where donut shouldn't be drawn.
162
+ this._drawData = true;
163
+ this._type = 'donut';
164
+
165
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
166
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
167
+ options.highlightMouseOver = false;
168
+ }
169
+
170
+ $.extend(true, this, options);
171
+ if (this.diameter != null) {
172
+ this.diameter = this.diameter - this.sliceMargin;
173
+ }
174
+ this._diameter = null;
175
+ this._innerDiameter = null;
176
+ this._radius = null;
177
+ this._innerRadius = null;
178
+ this._thickness = null;
179
+ // references to the previous series in the plot to properly calculate diameters
180
+ // and thicknesses of nested rings.
181
+ this._previousSeries = [];
182
+ this._numberSeries = 1;
183
+ // array of [start,end] angles arrays, one for each slice. In radians.
184
+ this._sliceAngles = [];
185
+ // index of the currenty highlighted point, if any
186
+ this._highlightedPoint = null;
187
+
188
+ // set highlight colors if none provided
189
+ if (this.highlightColors.length == 0) {
190
+ for (var i=0; i<this.seriesColors.length; i++){
191
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
192
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
193
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
194
+ for (var j=0; j<3; j++) {
195
+ // when darkening, lowest color component can be is 60.
196
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
197
+ newrgb[j] = parseInt(newrgb[j], 10);
198
+ }
199
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
200
+ }
201
+ }
202
+
203
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
204
+ plot.postInitHooks.addOnce(postInit);
205
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
206
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
207
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
208
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
209
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
210
+ plot.postDrawHooks.addOnce(postPlotDraw);
211
+
212
+
213
+ };
214
+
215
+ $.jqplot.DonutRenderer.prototype.setGridData = function(plot) {
216
+ // set gridData property. This will hold angle in radians of each data point.
217
+ var stack = [];
218
+ var td = [];
219
+ var sa = this.startAngle/180*Math.PI;
220
+ var tot = 0;
221
+ // don't know if we have any valid data yet, so set plot to not draw.
222
+ this._drawData = false;
223
+ for (var i=0; i<this.data.length; i++){
224
+ if (this.data[i][1] != 0) {
225
+ // we have data, O.K. to draw.
226
+ this._drawData = true;
227
+ }
228
+ stack.push(this.data[i][1]);
229
+ td.push([this.data[i][0]]);
230
+ if (i>0) {
231
+ stack[i] += stack[i-1];
232
+ }
233
+ tot += this.data[i][1];
234
+ }
235
+ var fact = Math.PI*2/stack[stack.length - 1];
236
+
237
+ for (var i=0; i<stack.length; i++) {
238
+ td[i][1] = stack[i] * fact;
239
+ td[i][2] = this.data[i][1]/tot;
240
+ }
241
+ this.gridData = td;
242
+ };
243
+
244
+ $.jqplot.DonutRenderer.prototype.makeGridData = function(data, plot) {
245
+ var stack = [];
246
+ var td = [];
247
+ var tot = 0;
248
+ var sa = this.startAngle/180*Math.PI;
249
+ // don't know if we have any valid data yet, so set plot to not draw.
250
+ this._drawData = false;
251
+ for (var i=0; i<data.length; i++){
252
+ if (this.data[i][1] != 0) {
253
+ // we have data, O.K. to draw.
254
+ this._drawData = true;
255
+ }
256
+ stack.push(data[i][1]);
257
+ td.push([data[i][0]]);
258
+ if (i>0) {
259
+ stack[i] += stack[i-1];
260
+ }
261
+ tot += data[i][1];
262
+ }
263
+ var fact = Math.PI*2/stack[stack.length - 1];
264
+
265
+ for (var i=0; i<stack.length; i++) {
266
+ td[i][1] = stack[i] * fact;
267
+ td[i][2] = data[i][1]/tot;
268
+ }
269
+ this._totalAmount = tot;
270
+ return td;
271
+ };
272
+
273
+ $.jqplot.DonutRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
274
+ var r = this._diameter / 2;
275
+ var ri = r - this._thickness;
276
+ var fill = this.fill;
277
+ // var lineWidth = this.lineWidth;
278
+ ctx.save();
279
+ ctx.translate(this._center[0], this._center[1]);
280
+ // ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2));
281
+
282
+ if (isShadow) {
283
+ for (var i=0; i<this.shadowDepth; i++) {
284
+ ctx.save();
285
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
286
+ doDraw();
287
+ }
288
+ }
289
+
290
+ else {
291
+ doDraw();
292
+ }
293
+
294
+ function doDraw () {
295
+ // Fix for IE and Chrome that can't seem to draw circles correctly.
296
+ // ang2 should always be <= 2 pi since that is the way the data is converted.
297
+ if (ang2 > 6.282 + this.startAngle) {
298
+ ang2 = 6.282 + this.startAngle;
299
+ if (ang1 > ang2) {
300
+ ang1 = 6.281 + this.startAngle;
301
+ }
302
+ }
303
+ // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
304
+ // ugly line on unfilled donuts.
305
+ if (ang1 >= ang2) {
306
+ return;
307
+ }
308
+ ctx.beginPath();
309
+ ctx.fillStyle = color;
310
+ ctx.strokeStyle = color;
311
+ // ctx.lineWidth = lineWidth;
312
+ ctx.arc(0, 0, r, ang1, ang2, false);
313
+ ctx.lineTo(ri*Math.cos(ang2), ri*Math.sin(ang2));
314
+ ctx.arc(0,0, ri, ang2, ang1, true);
315
+ ctx.closePath();
316
+ if (fill) {
317
+ ctx.fill();
318
+ }
319
+ else {
320
+ ctx.stroke();
321
+ }
322
+ }
323
+
324
+ if (isShadow) {
325
+ for (var i=0; i<this.shadowDepth; i++) {
326
+ ctx.restore();
327
+ }
328
+ }
329
+
330
+ ctx.restore();
331
+ };
332
+
333
+ // called with scope of series
334
+ $.jqplot.DonutRenderer.prototype.draw = function (ctx, gd, options, plot) {
335
+ var i;
336
+ var opts = (options != undefined) ? options : {};
337
+ // offset and direction of offset due to legend placement
338
+ var offx = 0;
339
+ var offy = 0;
340
+ var trans = 1;
341
+ // var colorGenerator = new this.colorGenerator(this.seriesColors);
342
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
343
+ var li = options.legendInfo;
344
+ switch (li.location) {
345
+ case 'nw':
346
+ offx = li.width + li.xoffset;
347
+ break;
348
+ case 'w':
349
+ offx = li.width + li.xoffset;
350
+ break;
351
+ case 'sw':
352
+ offx = li.width + li.xoffset;
353
+ break;
354
+ case 'ne':
355
+ offx = li.width + li.xoffset;
356
+ trans = -1;
357
+ break;
358
+ case 'e':
359
+ offx = li.width + li.xoffset;
360
+ trans = -1;
361
+ break;
362
+ case 'se':
363
+ offx = li.width + li.xoffset;
364
+ trans = -1;
365
+ break;
366
+ case 'n':
367
+ offy = li.height + li.yoffset;
368
+ break;
369
+ case 's':
370
+ offy = li.height + li.yoffset;
371
+ trans = -1;
372
+ break;
373
+ default:
374
+ break;
375
+ }
376
+ }
377
+
378
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
379
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
380
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
381
+ //see http://stackoverflow.com/questions/20221461/hidpi-retina-plot-drawing
382
+ var cw = parseInt(ctx.canvas.style.width);
383
+ var ch = parseInt(ctx.canvas.style.height);
384
+ var w = cw - offx - 2 * this.padding;
385
+ var h = ch - offy - 2 * this.padding;
386
+ var mindim = Math.min(w,h);
387
+ var d = mindim;
388
+ var ringmargin = (this.ringMargin == null) ? this.sliceMargin * 2.0 : this.ringMargin;
389
+
390
+ for (var i=0; i<this._previousSeries.length; i++) {
391
+ d -= 2.0 * this._previousSeries[i]._thickness + 2.0 * ringmargin;
392
+ }
393
+ this._diameter = this.diameter || d;
394
+ if (this.innerDiameter != null) {
395
+ var od = (this._numberSeries > 1 && this.index > 0) ? this._previousSeries[0]._diameter : this._diameter;
396
+ this._thickness = this.thickness || (od - this.innerDiameter - 2.0*ringmargin*this._numberSeries) / this._numberSeries/2.0;
397
+ }
398
+ else {
399
+ this._thickness = this.thickness || mindim / 2 / (this._numberSeries + 1) * 0.85;
400
+ }
401
+ if (this._diameter < 6) {
402
+ $.jqplot.log("Diameter of donut too small, not rendering.");
403
+ return;
404
+ }
405
+ var r = this._radius = this._diameter/2;
406
+ this._innerRadius = this._radius - this._thickness;
407
+ var sa = this.startAngle / 180 * Math.PI;
408
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
409
+
410
+ if (this.shadow) {
411
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
412
+ for (var i=0; i<gd.length; i++) {
413
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
414
+ // Adjust ang1 and ang2 for sliceMargin
415
+ ang1 += this.sliceMargin/180*Math.PI;
416
+ this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true);
417
+ }
418
+
419
+ }
420
+ for (var i=0; i<gd.length; i++) {
421
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
422
+ // Adjust ang1 and ang2 for sliceMargin
423
+ ang1 += this.sliceMargin/180*Math.PI;
424
+ var ang2 = gd[i][1] + sa;
425
+ this._sliceAngles.push([ang1, ang2]);
426
+ this.renderer.drawSlice.call (this, ctx, ang1, ang2, this.seriesColors[i], false);
427
+
428
+ if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
429
+ var fstr, avgang = (ang1+ang2)/2, label;
430
+
431
+ if (this.dataLabels == 'label') {
432
+ fstr = this.dataLabelFormatString || '%s';
433
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
434
+ }
435
+ else if (this.dataLabels == 'value') {
436
+ fstr = this.dataLabelFormatString || '%d';
437
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
438
+ }
439
+ else if (this.dataLabels == 'percent') {
440
+ fstr = this.dataLabelFormatString || '%d%%';
441
+ label = $.jqplot.sprintf(fstr, gd[i][2]*100);
442
+ }
443
+ else if (this.dataLabels.constructor == Array) {
444
+ fstr = this.dataLabelFormatString || '%s';
445
+ label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
446
+ }
447
+
448
+ var fact = this._innerRadius + this._thickness * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
449
+
450
+ var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
451
+ var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
452
+
453
+ var labelelem = $('<span class="jqplot-donut-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
454
+ x -= labelelem.width()/2;
455
+ y -= labelelem.height()/2;
456
+ x = Math.round(x);
457
+ y = Math.round(y);
458
+ labelelem.css({left: x, top: y});
459
+ }
460
+ }
461
+ if (this.totalLabel) {
462
+ var totalLabel = $('<div class="jqplot-data-label" style="position:absolute">' + this._totalAmount + '</div>').insertAfter(plot.eventCanvas._elem);
463
+ totalLabel.css({left: this._center[0], top: this._center[1]});
464
+ }
465
+ };
466
+
467
+ $.jqplot.DonutAxisRenderer = function() {
468
+ $.jqplot.LinearAxisRenderer.call(this);
469
+ };
470
+
471
+ $.jqplot.DonutAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
472
+ $.jqplot.DonutAxisRenderer.prototype.constructor = $.jqplot.DonutAxisRenderer;
473
+
474
+
475
+ // There are no traditional axes on a donut chart. We just need to provide
476
+ // dummy objects with properties so the plot will render.
477
+ // called with scope of axis object.
478
+ $.jqplot.DonutAxisRenderer.prototype.init = function(options){
479
+ //
480
+ this.tickRenderer = $.jqplot.DonutTickRenderer;
481
+ $.extend(true, this, options);
482
+ // I don't think I'm going to need _dataBounds here.
483
+ // have to go Axis scaling in a way to fit chart onto plot area
484
+ // and provide u2p and p2u functionality for mouse cursor, etc.
485
+ // for convienence set _dataBounds to 0 and 100 and
486
+ // set min/max to 0 and 100.
487
+ this._dataBounds = {min:0, max:100};
488
+ this.min = 0;
489
+ this.max = 100;
490
+ this.showTicks = false;
491
+ this.ticks = [];
492
+ this.showMark = false;
493
+ this.show = false;
494
+ };
495
+
496
+
497
+
498
+
499
+ $.jqplot.DonutLegendRenderer = function(){
500
+ $.jqplot.TableLegendRenderer.call(this);
501
+ };
502
+
503
+ $.jqplot.DonutLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
504
+ $.jqplot.DonutLegendRenderer.prototype.constructor = $.jqplot.DonutLegendRenderer;
505
+
506
+ /**
507
+ * Class: $.jqplot.DonutLegendRenderer
508
+ * Legend Renderer specific to donut plots. Set by default
509
+ * when user creates a donut plot.
510
+ */
511
+ $.jqplot.DonutLegendRenderer.prototype.init = function(options) {
512
+ // Group: Properties
513
+ //
514
+ // prop: numberRows
515
+ // Maximum number of rows in the legend. 0 or null for unlimited.
516
+ this.numberRows = null;
517
+ // prop: numberColumns
518
+ // Maximum number of columns in the legend. 0 or null for unlimited.
519
+ this.numberColumns = null;
520
+ $.extend(true, this, options);
521
+ };
522
+
523
+ // called with context of legend
524
+ $.jqplot.DonutLegendRenderer.prototype.draw = function() {
525
+ var legend = this;
526
+ if (this.show) {
527
+ var series = this._series;
528
+ var ss = 'position:absolute;';
529
+ ss += (this.background) ? 'background:'+this.background+';' : '';
530
+ ss += (this.border) ? 'border:'+this.border+';' : '';
531
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
532
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
533
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
534
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
535
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
536
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
537
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
538
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
539
+ // Donut charts legends don't go by number of series, but by number of data points
540
+ // in the series. Refactor things here for that.
541
+
542
+ var pad = false,
543
+ reverse = false,
544
+ nr, nc;
545
+ var s = series[0];
546
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
547
+
548
+ if (s.show) {
549
+ var pd = s.data;
550
+ if (this.numberRows) {
551
+ nr = this.numberRows;
552
+ if (!this.numberColumns){
553
+ nc = Math.ceil(pd.length/nr);
554
+ }
555
+ else{
556
+ nc = this.numberColumns;
557
+ }
558
+ }
559
+ else if (this.numberColumns) {
560
+ nc = this.numberColumns;
561
+ nr = Math.ceil(pd.length/this.numberColumns);
562
+ }
563
+ else {
564
+ nr = pd.length;
565
+ nc = 1;
566
+ }
567
+
568
+ var i, j, tr, td1, td2, lt, rs, color;
569
+ var idx = 0;
570
+
571
+ for (i=0; i<nr; i++) {
572
+ if (reverse){
573
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
574
+ }
575
+ else{
576
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
577
+ }
578
+ for (j=0; j<nc; j++) {
579
+ if (idx < pd.length){
580
+ lt = this.labels[idx] || pd[idx][0].toString();
581
+ color = colorGenerator.next();
582
+ if (!reverse){
583
+ if (i>0){
584
+ pad = true;
585
+ }
586
+ else{
587
+ pad = false;
588
+ }
589
+ }
590
+ else{
591
+ if (i == nr -1){
592
+ pad = false;
593
+ }
594
+ else{
595
+ pad = true;
596
+ }
597
+ }
598
+ rs = (pad) ? this.rowSpacing : '0';
599
+
600
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
601
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
602
+ '</div></td>');
603
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
604
+ if (this.escapeHtml){
605
+ td2.text(lt);
606
+ }
607
+ else {
608
+ td2.html(lt);
609
+ }
610
+ if (reverse) {
611
+ td2.prependTo(tr);
612
+ td1.prependTo(tr);
613
+ }
614
+ else {
615
+ td1.appendTo(tr);
616
+ td2.appendTo(tr);
617
+ }
618
+ pad = true;
619
+ }
620
+ idx++;
621
+ }
622
+ }
623
+ }
624
+ }
625
+ return this._elem;
626
+ };
627
+
628
+ // setup default renderers for axes and legend so user doesn't have to
629
+ // called with scope of plot
630
+ function preInit(target, data, options) {
631
+ options = options || {};
632
+ options.axesDefaults = options.axesDefaults || {};
633
+ options.legend = options.legend || {};
634
+ options.seriesDefaults = options.seriesDefaults || {};
635
+ // only set these if there is a donut series
636
+ var setopts = false;
637
+ if (options.seriesDefaults.renderer == $.jqplot.DonutRenderer) {
638
+ setopts = true;
639
+ }
640
+ else if (options.series) {
641
+ for (var i=0; i < options.series.length; i++) {
642
+ if (options.series[i].renderer == $.jqplot.DonutRenderer) {
643
+ setopts = true;
644
+ }
645
+ }
646
+ }
647
+
648
+ if (setopts) {
649
+ options.axesDefaults.renderer = $.jqplot.DonutAxisRenderer;
650
+ options.legend.renderer = $.jqplot.DonutLegendRenderer;
651
+ options.legend.preDraw = true;
652
+ options.seriesDefaults.pointLabels = {show: false};
653
+ }
654
+ }
655
+
656
+ // called with scope of plot.
657
+ function postInit(target, data, options) {
658
+ // if multiple series, add a reference to the previous one so that
659
+ // donut rings can nest.
660
+ for (var i=1; i<this.series.length; i++) {
661
+ if (!this.series[i]._previousSeries.length){
662
+ for (var j=0; j<i; j++) {
663
+ if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer && this.series[j].renderer.constructor == $.jqplot.DonutRenderer) {
664
+ this.series[i]._previousSeries.push(this.series[j]);
665
+ }
666
+ }
667
+ }
668
+ }
669
+ for (i=0; i<this.series.length; i++) {
670
+ if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer) {
671
+ this.series[i]._numberSeries = this.series.length;
672
+ // don't allow mouseover and mousedown at same time.
673
+ if (this.series[i].highlightMouseOver) {
674
+ this.series[i].highlightMouseDown = false;
675
+ }
676
+ }
677
+ }
678
+ }
679
+
680
+ var postParseOptionsRun = false;
681
+ // called with scope of plot
682
+ function postParseOptions(options) {
683
+ for (var i=0; i<this.series.length; i++) {
684
+ this.series[i].seriesColors = this.seriesColors;
685
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
686
+ }
687
+ }
688
+
689
+ function highlight (plot, sidx, pidx) {
690
+ var s = plot.series[sidx];
691
+ var canvas = plot.plugins.donutRenderer.highlightCanvas;
692
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
693
+ s._highlightedPoint = pidx;
694
+ plot.plugins.donutRenderer.highlightedSeriesIndex = sidx;
695
+ s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColors[pidx], false);
696
+ }
697
+
698
+ function unhighlight (plot) {
699
+ var canvas = plot.plugins.donutRenderer.highlightCanvas;
700
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
701
+ for (var i=0; i<plot.series.length; i++) {
702
+ plot.series[i]._highlightedPoint = null;
703
+ }
704
+ plot.plugins.donutRenderer.highlightedSeriesIndex = null;
705
+ plot.target.trigger('jqplotDataUnhighlight');
706
+ }
707
+
708
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
709
+ if (neighbor) {
710
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
711
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
712
+ evt1.pageX = ev.pageX;
713
+ evt1.pageY = ev.pageY;
714
+ plot.target.trigger(evt1, ins);
715
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
716
+ var evt = jQuery.Event('jqplotDataHighlight');
717
+ evt.which = ev.which;
718
+ evt.pageX = ev.pageX;
719
+ evt.pageY = ev.pageY;
720
+ plot.target.trigger(evt, ins);
721
+ highlight (plot, ins[0], ins[1]);
722
+ }
723
+ }
724
+ else if (neighbor == null) {
725
+ unhighlight (plot);
726
+ }
727
+ }
728
+
729
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
730
+ if (neighbor) {
731
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
732
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
733
+ var evt = jQuery.Event('jqplotDataHighlight');
734
+ evt.which = ev.which;
735
+ evt.pageX = ev.pageX;
736
+ evt.pageY = ev.pageY;
737
+ plot.target.trigger(evt, ins);
738
+ highlight (plot, ins[0], ins[1]);
739
+ }
740
+ }
741
+ else if (neighbor == null) {
742
+ unhighlight (plot);
743
+ }
744
+ }
745
+
746
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
747
+ var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
748
+ if (idx != null && plot.series[idx].highlightMouseDown) {
749
+ unhighlight(plot);
750
+ }
751
+ }
752
+
753
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
754
+ if (neighbor) {
755
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
756
+ var evt = jQuery.Event('jqplotDataClick');
757
+ evt.which = ev.which;
758
+ evt.pageX = ev.pageX;
759
+ evt.pageY = ev.pageY;
760
+ plot.target.trigger(evt, ins);
761
+ }
762
+ }
763
+
764
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
765
+ if (neighbor) {
766
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
767
+ var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
768
+ if (idx != null && plot.series[idx].highlightMouseDown) {
769
+ unhighlight(plot);
770
+ }
771
+ var evt = jQuery.Event('jqplotDataRightClick');
772
+ evt.which = ev.which;
773
+ evt.pageX = ev.pageX;
774
+ evt.pageY = ev.pageY;
775
+ plot.target.trigger(evt, ins);
776
+ }
777
+ }
778
+
779
+ // called within context of plot
780
+ // create a canvas which we can draw on.
781
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
782
+ function postPlotDraw() {
783
+ // Memory Leaks patch
784
+ if (this.plugins.donutRenderer && this.plugins.donutRenderer.highlightCanvas) {
785
+ this.plugins.donutRenderer.highlightCanvas.resetCanvas();
786
+ this.plugins.donutRenderer.highlightCanvas = null;
787
+ }
788
+
789
+ this.plugins.donutRenderer = {highlightedSeriesIndex:null};
790
+ this.plugins.donutRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
791
+ // do we have any data labels? if so, put highlight canvas before those
792
+ // Fix for broken jquery :first selector with canvas (VML) elements.
793
+ var labels = $(this.targetId+' .jqplot-data-label');
794
+ if (labels.length) {
795
+ $(labels[0]).before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
796
+ }
797
+ // else put highlight canvas before event canvas.
798
+ else {
799
+ this.eventCanvas._elem.before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
800
+ }
801
+ var hctx = this.plugins.donutRenderer.highlightCanvas.setContext();
802
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
803
+ }
804
+
805
+ $.jqplot.preInitHooks.push(preInit);
806
+
807
+ $.jqplot.DonutTickRenderer = function() {
808
+ $.jqplot.AxisTickRenderer.call(this);
809
+ };
810
+
811
+ $.jqplot.DonutTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
812
+ $.jqplot.DonutTickRenderer.prototype.constructor = $.jqplot.DonutTickRenderer;
813
+
814
+ })(jQuery);
815
+
816
+