jquery_cheats 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/README.md +19 -2
  2. data/app/assets/javascripts/jqueryCheats.js +36 -1
  3. data/jquery_cheats.gemspec +2 -2
  4. data/lib/jquery_cheats.rb +4 -0
  5. data/vendor/assets/excanvas.js +1438 -0
  6. data/vendor/assets/jquery.jqplot.css +259 -0
  7. data/vendor/assets/jquery.jqplot.js +10901 -0
  8. data/vendor/assets/plugins/jqplot.BezierCurveRenderer.js +312 -0
  9. data/vendor/assets/plugins/jqplot.BezierCurveRenderer.min.js +57 -0
  10. data/vendor/assets/plugins/jqplot.barRenderer.js +747 -0
  11. data/vendor/assets/plugins/jqplot.barRenderer.min.js +57 -0
  12. data/vendor/assets/plugins/jqplot.blockRenderer.js +234 -0
  13. data/vendor/assets/plugins/jqplot.blockRenderer.min.js +57 -0
  14. data/vendor/assets/plugins/jqplot.bubbleRenderer.js +754 -0
  15. data/vendor/assets/plugins/jqplot.bubbleRenderer.min.js +57 -0
  16. data/vendor/assets/plugins/jqplot.canvasAxisLabelRenderer.js +202 -0
  17. data/vendor/assets/plugins/jqplot.canvasAxisLabelRenderer.min.js +57 -0
  18. data/vendor/assets/plugins/jqplot.canvasAxisTickRenderer.js +242 -0
  19. data/vendor/assets/plugins/jqplot.canvasAxisTickRenderer.min.js +57 -0
  20. data/vendor/assets/plugins/jqplot.canvasOverlay.js +864 -0
  21. data/vendor/assets/plugins/jqplot.canvasOverlay.min.js +57 -0
  22. data/vendor/assets/plugins/jqplot.canvasTextRenderer.js +448 -0
  23. data/vendor/assets/plugins/jqplot.canvasTextRenderer.min.js +57 -0
  24. data/vendor/assets/plugins/jqplot.categoryAxisRenderer.js +636 -0
  25. data/vendor/assets/plugins/jqplot.categoryAxisRenderer.min.js +57 -0
  26. data/vendor/assets/plugins/jqplot.ciParser.js +115 -0
  27. data/vendor/assets/plugins/jqplot.ciParser.min.js +57 -0
  28. data/vendor/assets/plugins/jqplot.cursor.js +1093 -0
  29. data/vendor/assets/plugins/jqplot.cursor.min.js +57 -0
  30. data/vendor/assets/plugins/jqplot.dateAxisRenderer.js +702 -0
  31. data/vendor/assets/plugins/jqplot.dateAxisRenderer.min.js +57 -0
  32. data/vendor/assets/plugins/jqplot.donutRenderer.js +800 -0
  33. data/vendor/assets/plugins/jqplot.donutRenderer.min.js +57 -0
  34. data/vendor/assets/plugins/jqplot.dragable.js +224 -0
  35. data/vendor/assets/plugins/jqplot.dragable.min.js +57 -0
  36. data/vendor/assets/plugins/jqplot.enhancedLegendRenderer.js +241 -0
  37. data/vendor/assets/plugins/jqplot.enhancedLegendRenderer.min.js +57 -0
  38. data/vendor/assets/plugins/jqplot.funnelRenderer.js +938 -0
  39. data/vendor/assets/plugins/jqplot.funnelRenderer.min.js +57 -0
  40. data/vendor/assets/plugins/jqplot.highlighter.js +454 -0
  41. data/vendor/assets/plugins/jqplot.highlighter.min.js +57 -0
  42. data/vendor/assets/plugins/jqplot.json2.js +475 -0
  43. data/vendor/assets/plugins/jqplot.json2.min.js +57 -0
  44. data/vendor/assets/plugins/jqplot.logAxisRenderer.js +528 -0
  45. data/vendor/assets/plugins/jqplot.logAxisRenderer.min.js +57 -0
  46. data/vendor/assets/plugins/jqplot.mekkoAxisRenderer.js +610 -0
  47. data/vendor/assets/plugins/jqplot.mekkoAxisRenderer.min.js +57 -0
  48. data/vendor/assets/plugins/jqplot.mekkoRenderer.js +436 -0
  49. data/vendor/assets/plugins/jqplot.mekkoRenderer.min.js +57 -0
  50. data/vendor/assets/plugins/jqplot.meterGaugeRenderer.js +1029 -0
  51. data/vendor/assets/plugins/jqplot.meterGaugeRenderer.min.js +57 -0
  52. data/vendor/assets/plugins/jqplot.ohlcRenderer.js +372 -0
  53. data/vendor/assets/plugins/jqplot.ohlcRenderer.min.js +57 -0
  54. data/vendor/assets/plugins/jqplot.pieRenderer.js +899 -0
  55. data/vendor/assets/plugins/jqplot.pieRenderer.min.js +57 -0
  56. data/vendor/assets/plugins/jqplot.pointLabels.js +362 -0
  57. data/vendor/assets/plugins/jqplot.pointLabels.min.js +57 -0
  58. data/vendor/assets/plugins/jqplot.pyramidAxisRenderer.js +730 -0
  59. data/vendor/assets/plugins/jqplot.pyramidAxisRenderer.min.js +57 -0
  60. data/vendor/assets/plugins/jqplot.pyramidGridRenderer.js +423 -0
  61. data/vendor/assets/plugins/jqplot.pyramidGridRenderer.min.js +57 -0
  62. data/vendor/assets/plugins/jqplot.pyramidRenderer.js +490 -0
  63. data/vendor/assets/plugins/jqplot.pyramidRenderer.min.js +57 -0
  64. data/vendor/assets/plugins/jqplot.trendline.js +222 -0
  65. data/vendor/assets/plugins/jqplot.trendline.min.js +57 -0
  66. metadata +64 -3
@@ -0,0 +1,938 @@
1
+ /**
2
+ * jqPlot
3
+ * Pure JavaScript plotting plugin using jQuery
4
+ *
5
+ * Version: 1.0.0b2_r1012
6
+ *
7
+ * Copyright (c) 2009-2011 Chris Leonello
8
+ * jqPlot is currently available for use in all personal or commercial projects
9
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
10
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
11
+ * choose the license that best suits your project and use it accordingly.
12
+ *
13
+ * Although not required, the author would appreciate an email letting him
14
+ * know of any substantial use of jqPlot. You can reach the author at:
15
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
16
+ *
17
+ * If you are feeling kind and generous, consider supporting the project by
18
+ * making a donation at: http://www.jqplot.com/donate.php .
19
+ *
20
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
21
+ *
22
+ * version 2007.04.27
23
+ * author Ash Searle
24
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
25
+ * http://hexmen.com/js/sprintf.js
26
+ * The author (Ash Searle) has placed this code in the public domain:
27
+ * "This code is unrestricted: you are free to use it however you like."
28
+ *
29
+ */
30
+ (function($) {
31
+ /**
32
+ * Class: $.jqplot.FunnelRenderer
33
+ * Plugin renderer to draw a funnel chart.
34
+ * x values, if present, will be used as labels.
35
+ * y values give area size.
36
+ *
37
+ * Funnel charts will draw a single series
38
+ * only.
39
+ *
40
+ * To use this renderer, you need to include the
41
+ * funnel renderer plugin, for example:
42
+ *
43
+ * > <script type="text/javascript" src="plugins/jqplot.funnelRenderer.js"></script>
44
+ *
45
+ * Properties described here are passed into the $.jqplot function
46
+ * as options on the series renderer. For example:
47
+ *
48
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
49
+ * > seriesDefaults: {
50
+ * > renderer:$.jqplot.FunnelRenderer,
51
+ * > rendererOptions:{
52
+ * > sectionMargin: 12,
53
+ * > widthRatio: 0.3
54
+ * > }
55
+ * > }
56
+ * > });
57
+ *
58
+ * IMPORTANT
59
+ *
60
+ * *The funnel renderer will reorder data in descending order* so the largest value in
61
+ * the data set is first and displayed on top of the funnel. Data will then
62
+ * be displayed in descending order down the funnel. The area of each funnel
63
+ * section will correspond to the value of each data point relative to the sum
64
+ * of all values. That is section area is proportional to section value divided by
65
+ * sum of all section values.
66
+ *
67
+ * If your data is not in descending order when passed into the plot, *it will be
68
+ * reordered* when stored in the series.data property. A copy of the unordered
69
+ * data is kept in the series._unorderedData property.
70
+ *
71
+ * A funnel plot will trigger events on the plot target
72
+ * according to user interaction. All events return the event object,
73
+ * the series index, the point (section) index, and the point data for
74
+ * the appropriate section. *Note* the point index will referr to the ordered
75
+ * data, not the original unordered data.
76
+ *
77
+ * 'jqplotDataMouseOver' - triggered when mousing over a section.
78
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a section,
79
+ * if highlighting is enabled.
80
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
81
+ * a highlighted section.
82
+ * 'jqplotDataClick' - triggered when the user clicks on a section.
83
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a section if
84
+ * the "captureRightClick" option is set to true on the plot.
85
+ */
86
+ $.jqplot.FunnelRenderer = function(){
87
+ $.jqplot.LineRenderer.call(this);
88
+ };
89
+
90
+ $.jqplot.FunnelRenderer.prototype = new $.jqplot.LineRenderer();
91
+ $.jqplot.FunnelRenderer.prototype.constructor = $.jqplot.FunnelRenderer;
92
+
93
+ // called with scope of a series
94
+ $.jqplot.FunnelRenderer.prototype.init = function(options, plot) {
95
+ // Group: Properties
96
+ //
97
+ // prop: padding
98
+ // padding between the funnel and plot edges, legend, etc.
99
+ this.padding = {top: 20, right: 20, bottom: 20, left: 20};
100
+ // prop: sectionMargin
101
+ // spacing between funnel sections in pixels.
102
+ this.sectionMargin = 6;
103
+ // prop: fill
104
+ // true or false, wether to fill the areas.
105
+ this.fill = true;
106
+ // prop: shadowOffset
107
+ // offset of the shadow from the area 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 area when moused over.
119
+ // This must be false to enable highlightMouseDown to highlight when clicking on a area.
120
+ this.highlightMouseOver = true;
121
+ // prop: highlightMouseDown
122
+ // True to highlight when a mouse button is pressed over a area.
123
+ // This will be disabled if highlightMouseOver is true.
124
+ this.highlightMouseDown = false;
125
+ // prop: highlightColors
126
+ // array of colors to use when highlighting an area.
127
+ this.highlightColors = [];
128
+ // prop: widthRatio
129
+ // The ratio of the width of the top of the funnel to the bottom.
130
+ // a ratio of 0 will make an upside down pyramid.
131
+ this.widthRatio = 0.2;
132
+ // prop: lineWidth
133
+ // width of line if areas are stroked and not filled.
134
+ this.lineWidth = 2;
135
+ // prop: dataLabels
136
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
137
+ // Defaults to percentage of each pie slice.
138
+ this.dataLabels = 'percent';
139
+ // prop: showDataLabels
140
+ // true to show data labels on slices.
141
+ this.showDataLabels = false;
142
+ // prop: dataLabelFormatString
143
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
144
+ this.dataLabelFormatString = null;
145
+ // prop: dataLabelThreshold
146
+ // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
147
+ // This applies to all label types, not just to percentage labels.
148
+ this.dataLabelThreshold = 3;
149
+ this._type = 'funnel';
150
+
151
+ this.tickRenderer = $.jqplot.FunnelTickRenderer;
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
+ // index of the currenty highlighted point, if any
161
+ this._highlightedPoint = null;
162
+
163
+ // lengths of bases, or horizontal sides of areas of trapezoid.
164
+ this._bases = [];
165
+ // total area
166
+ this._atot;
167
+ // areas of segments.
168
+ this._areas = [];
169
+ // vertical lengths of segments.
170
+ this._lengths = [];
171
+ // angle of the funnel to vertical.
172
+ this._angle;
173
+ this._dataIndices = [];
174
+
175
+ // sort data
176
+ this._unorderedData = $.extend(true, [], this.data);
177
+ var idxs = $.extend(true, [], this.data);
178
+ for (var i=0; i<idxs.length; i++) {
179
+ idxs[i].push(i);
180
+ }
181
+ this.data.sort( function (a, b) { return b[1] - a[1]; } );
182
+ idxs.sort( function (a, b) { return b[1] - a[1]; });
183
+ for (var i=0; i<idxs.length; i++) {
184
+ this._dataIndices.push(idxs[i][2]);
185
+ }
186
+
187
+ // set highlight colors if none provided
188
+ if (this.highlightColors.length == 0) {
189
+ for (var i=0; i<this.seriesColors.length; i++){
190
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
191
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
192
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
193
+ for (var j=0; j<3; j++) {
194
+ // when darkening, lowest color component can be is 60.
195
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.4 * (255 - newrgb[j]);
196
+ newrgb[j] = parseInt(newrgb[j], 10);
197
+ }
198
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
199
+ }
200
+ }
201
+
202
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
203
+ plot.postInitHooks.addOnce(postInit);
204
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
205
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
206
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
207
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
208
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
209
+ plot.postDrawHooks.addOnce(postPlotDraw);
210
+
211
+ };
212
+
213
+ // gridData will be of form [label, percentage of total]
214
+ $.jqplot.FunnelRenderer.prototype.setGridData = function(plot) {
215
+ // set gridData property. This will hold angle in radians of each data point.
216
+ var sum = 0;
217
+ var td = [];
218
+ for (var i=0; i<this.data.length; i++){
219
+ sum += this.data[i][1];
220
+ td.push([this.data[i][0], this.data[i][1]]);
221
+ }
222
+
223
+ // normalize y values, so areas are proportional.
224
+ for (var i=0; i<td.length; i++) {
225
+ td[i][1] = td[i][1]/sum;
226
+ }
227
+
228
+ this._bases = new Array(td.length + 1);
229
+ this._lengths = new Array(td.length);
230
+
231
+ this.gridData = td;
232
+ };
233
+
234
+ $.jqplot.FunnelRenderer.prototype.makeGridData = function(data, plot) {
235
+ // set gridData property. This will hold angle in radians of each data point.
236
+ var sum = 0;
237
+ var td = [];
238
+ for (var i=0; i<this.data.length; i++){
239
+ sum += this.data[i][1];
240
+ td.push([this.data[i][0], this.data[i][1]]);
241
+ }
242
+
243
+ // normalize y values, so areas are proportional.
244
+ for (var i=0; i<td.length; i++) {
245
+ td[i][1] = td[i][1]/sum;
246
+ }
247
+
248
+ this._bases = new Array(td.length + 1);
249
+ this._lengths = new Array(td.length);
250
+
251
+ return td;
252
+ };
253
+
254
+ $.jqplot.FunnelRenderer.prototype.drawSection = function (ctx, vertices, color, isShadow) {
255
+ var fill = this.fill;
256
+ var lineWidth = this.lineWidth;
257
+ ctx.save();
258
+
259
+ if (isShadow) {
260
+ for (var i=0; i<this.shadowDepth; i++) {
261
+ ctx.save();
262
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
263
+ doDraw();
264
+ }
265
+ }
266
+
267
+ else {
268
+ doDraw();
269
+ }
270
+
271
+ function doDraw () {
272
+ ctx.beginPath();
273
+ ctx.fillStyle = color;
274
+ ctx.strokeStyle = color;
275
+ ctx.lineWidth = lineWidth;
276
+ ctx.moveTo(vertices[0][0], vertices[0][1]);
277
+ for (var i=1; i<4; i++) {
278
+ ctx.lineTo(vertices[i][0], vertices[i][1]);
279
+ }
280
+ ctx.closePath();
281
+ if (fill) {
282
+ ctx.fill();
283
+ }
284
+ else {
285
+ ctx.stroke();
286
+ }
287
+ }
288
+
289
+ if (isShadow) {
290
+ for (var i=0; i<this.shadowDepth; i++) {
291
+ ctx.restore();
292
+ }
293
+ }
294
+
295
+ ctx.restore();
296
+ };
297
+
298
+ // called with scope of series
299
+ $.jqplot.FunnelRenderer.prototype.draw = function (ctx, gd, options, plot) {
300
+ var i;
301
+ var opts = (options != undefined) ? options : {};
302
+ // offset and direction of offset due to legend placement
303
+ var offx = 0;
304
+ var offy = 0;
305
+ var trans = 1;
306
+ this._areas = [];
307
+ // var colorGenerator = new this.colorGenerator(this.seriesColors);
308
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
309
+ var li = options.legendInfo;
310
+ switch (li.location) {
311
+ case 'nw':
312
+ offx = li.width + li.xoffset;
313
+ break;
314
+ case 'w':
315
+ offx = li.width + li.xoffset;
316
+ break;
317
+ case 'sw':
318
+ offx = li.width + li.xoffset;
319
+ break;
320
+ case 'ne':
321
+ offx = li.width + li.xoffset;
322
+ trans = -1;
323
+ break;
324
+ case 'e':
325
+ offx = li.width + li.xoffset;
326
+ trans = -1;
327
+ break;
328
+ case 'se':
329
+ offx = li.width + li.xoffset;
330
+ trans = -1;
331
+ break;
332
+ case 'n':
333
+ offy = li.height + li.yoffset;
334
+ break;
335
+ case 's':
336
+ offy = li.height + li.yoffset;
337
+ trans = -1;
338
+ break;
339
+ default:
340
+ break;
341
+ }
342
+ }
343
+
344
+ var loff = (trans==1) ? this.padding.left + offx : this.padding.left;
345
+ var toff = (trans==1) ? this.padding.top + offy : this.padding.top;
346
+ var roff = (trans==-1) ? this.padding.right + offx : this.padding.right;
347
+ var boff = (trans==-1) ? this.padding.bottom + offy : this.padding.bottom;
348
+
349
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
350
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
351
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
352
+ var cw = ctx.canvas.width;
353
+ var ch = ctx.canvas.height;
354
+ this._bases[0] = cw - loff - roff;
355
+ var ltot = this._length = ch - toff - boff;
356
+
357
+ var hend = this._bases[0]*this.widthRatio;
358
+ this._atot = ltot/2 * (this._bases[0] + this._bases[0]*this.widthRatio);
359
+
360
+ this._angle = Math.atan((this._bases[0] - hend)/2/ltot);
361
+
362
+ for (i=0; i<gd.length; i++) {
363
+ this._areas.push(gd[i][1] * this._atot);
364
+ }
365
+
366
+
367
+ var guess, err, count, lsum=0;
368
+ var tolerance = 0.0001;
369
+
370
+ for (i=0; i<this._areas.length; i++) {
371
+ guess = this._areas[i]/this._bases[i];
372
+ err = 999999;
373
+ this._lengths[i] = guess;
374
+ count = 0;
375
+ while (err > this._lengths[i]*tolerance && count < 100) {
376
+ this._lengths[i] = this._areas[i]/(this._bases[i] - this._lengths[i] * Math.tan(this._angle));
377
+ err = Math.abs(this._lengths[i] - guess);
378
+ this._bases[i+1] = this._bases[i] - (2*this._lengths[i]*Math.tan(this._angle));
379
+ guess = this._lengths[i];
380
+ count++;
381
+ }
382
+ lsum += this._lengths[i];
383
+ }
384
+
385
+ // figure out vertices of each section
386
+ this._vertices = new Array(gd.length);
387
+
388
+ // these are 4 coners of entire trapezoid
389
+ var p0 = [loff, toff],
390
+ p1 = [loff+this._bases[0], toff],
391
+ p2 = [loff + (this._bases[0] - this._bases[this._bases.length-1])/2, toff + this._length],
392
+ p3 = [p2[0] + this._bases[this._bases.length-1], p2[1]];
393
+
394
+ // equations of right and left sides, returns x, y values given height of section (y value)
395
+ function findleft (l) {
396
+ var m = (p0[1] - p2[1])/(p0[0] - p2[0]);
397
+ var b = p0[1] - m*p0[0];
398
+ var y = l + p0[1];
399
+
400
+ return [(y - b)/m, y];
401
+ }
402
+
403
+ function findright (l) {
404
+ var m = (p1[1] - p3[1])/(p1[0] - p3[0]);
405
+ var b = p1[1] - m*p1[0];
406
+ var y = l + p1[1];
407
+
408
+ return [(y - b)/m, y];
409
+ }
410
+
411
+ var x = offx, y = offy;
412
+ var h=0, adj=0;
413
+
414
+ for (i=0; i<gd.length; i++) {
415
+ this._vertices[i] = new Array();
416
+ var v = this._vertices[i];
417
+ var sm = this.sectionMargin;
418
+ if (i == 0) {
419
+ adj = 0;
420
+ }
421
+ if (i == 1) {
422
+ adj = sm/3;
423
+ }
424
+ else if (i > 0 && i < gd.length-1) {
425
+ adj = sm/2;
426
+ }
427
+ else if (i == gd.length -1) {
428
+ adj = 2*sm/3;
429
+ }
430
+ v.push(findleft(h+adj));
431
+ v.push(findright(h+adj));
432
+ h += this._lengths[i];
433
+ if (i == 0) {
434
+ adj = -2*sm/3;
435
+ }
436
+ else if (i > 0 && i < gd.length-1) {
437
+ adj = -sm/2;
438
+ }
439
+ else if (i == gd.length - 1) {
440
+ adj = 0;
441
+ }
442
+ v.push(findright(h+adj));
443
+ v.push(findleft(h+adj));
444
+
445
+ }
446
+
447
+ if (this.shadow) {
448
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
449
+ for (var i=0; i<gd.length; i++) {
450
+ this.renderer.drawSection.call (this, ctx, this._vertices[i], shadowColor, true);
451
+ }
452
+
453
+ }
454
+ for (var i=0; i<gd.length; i++) {
455
+ var v = this._vertices[i];
456
+ this.renderer.drawSection.call (this, ctx, v, this.seriesColors[i]);
457
+
458
+ if (this.showDataLabels && gd[i][1]*100 >= this.dataLabelThreshold) {
459
+ var fstr, label;
460
+
461
+ if (this.dataLabels == 'label') {
462
+ fstr = this.dataLabelFormatString || '%s';
463
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
464
+ }
465
+ else if (this.dataLabels == 'value') {
466
+ fstr = this.dataLabelFormatString || '%d';
467
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
468
+ }
469
+ else if (this.dataLabels == 'percent') {
470
+ fstr = this.dataLabelFormatString || '%d%%';
471
+ label = $.jqplot.sprintf(fstr, gd[i][1]*100);
472
+ }
473
+ else if (this.dataLabels.constructor == Array) {
474
+ fstr = this.dataLabelFormatString || '%s';
475
+ label = $.jqplot.sprintf(fstr, this.dataLabels[this._dataIndices[i]]);
476
+ }
477
+
478
+ var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
479
+
480
+ var x = (v[0][0] + v[1][0])/2 + this.canvas._offsets.left;
481
+ var y = (v[1][1] + v[2][1])/2 + this.canvas._offsets.top;
482
+
483
+ var labelelem = $('<span class="jqplot-funnel-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
484
+ x -= labelelem.width()/2;
485
+ y -= labelelem.height()/2;
486
+ x = Math.round(x);
487
+ y = Math.round(y);
488
+ labelelem.css({left: x, top: y});
489
+ }
490
+
491
+ }
492
+
493
+ };
494
+
495
+ $.jqplot.FunnelAxisRenderer = function() {
496
+ $.jqplot.LinearAxisRenderer.call(this);
497
+ };
498
+
499
+ $.jqplot.FunnelAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
500
+ $.jqplot.FunnelAxisRenderer.prototype.constructor = $.jqplot.FunnelAxisRenderer;
501
+
502
+
503
+ // There are no traditional axes on a funnel chart. We just need to provide
504
+ // dummy objects with properties so the plot will render.
505
+ // called with scope of axis object.
506
+ $.jqplot.FunnelAxisRenderer.prototype.init = function(options){
507
+ //
508
+ this.tickRenderer = $.jqplot.FunnelTickRenderer;
509
+ $.extend(true, this, options);
510
+ // I don't think I'm going to need _dataBounds here.
511
+ // have to go Axis scaling in a way to fit chart onto plot area
512
+ // and provide u2p and p2u functionality for mouse cursor, etc.
513
+ // for convienence set _dataBounds to 0 and 100 and
514
+ // set min/max to 0 and 100.
515
+ this._dataBounds = {min:0, max:100};
516
+ this.min = 0;
517
+ this.max = 100;
518
+ this.showTicks = false;
519
+ this.ticks = [];
520
+ this.showMark = false;
521
+ this.show = false;
522
+ };
523
+
524
+
525
+
526
+ /**
527
+ * Class: $.jqplot.FunnelLegendRenderer
528
+ * Legend Renderer specific to funnel plots. Set by default
529
+ * when the user creates a funnel plot.
530
+ */
531
+ $.jqplot.FunnelLegendRenderer = function(){
532
+ $.jqplot.TableLegendRenderer.call(this);
533
+ };
534
+
535
+ $.jqplot.FunnelLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
536
+ $.jqplot.FunnelLegendRenderer.prototype.constructor = $.jqplot.FunnelLegendRenderer;
537
+
538
+ $.jqplot.FunnelLegendRenderer.prototype.init = function(options) {
539
+ // Group: Properties
540
+ //
541
+ // prop: numberRows
542
+ // Maximum number of rows in the legend. 0 or null for unlimited.
543
+ this.numberRows = null;
544
+ // prop: numberColumns
545
+ // Maximum number of columns in the legend. 0 or null for unlimited.
546
+ this.numberColumns = null;
547
+ $.extend(true, this, options);
548
+ };
549
+
550
+ // called with context of legend
551
+ $.jqplot.FunnelLegendRenderer.prototype.draw = function() {
552
+ var legend = this;
553
+ if (this.show) {
554
+ var series = this._series;
555
+ var ss = 'position:absolute;';
556
+ ss += (this.background) ? 'background:'+this.background+';' : '';
557
+ ss += (this.border) ? 'border:'+this.border+';' : '';
558
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
559
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
560
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
561
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
562
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
563
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
564
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
565
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
566
+ // Funnel charts legends don't go by number of series, but by number of data points
567
+ // in the series. Refactor things here for that.
568
+
569
+ var pad = false,
570
+ reverse = false,
571
+ nr, nc;
572
+ var s = series[0];
573
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
574
+
575
+ if (s.show) {
576
+ var pd = s.data;
577
+ if (this.numberRows) {
578
+ nr = this.numberRows;
579
+ if (!this.numberColumns){
580
+ nc = Math.ceil(pd.length/nr);
581
+ }
582
+ else{
583
+ nc = this.numberColumns;
584
+ }
585
+ }
586
+ else if (this.numberColumns) {
587
+ nc = this.numberColumns;
588
+ nr = Math.ceil(pd.length/this.numberColumns);
589
+ }
590
+ else {
591
+ nr = pd.length;
592
+ nc = 1;
593
+ }
594
+
595
+ var i, j, tr, td1, td2, lt, rs, color;
596
+ var idx = 0;
597
+
598
+ for (i=0; i<nr; i++) {
599
+ if (reverse){
600
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
601
+ }
602
+ else{
603
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
604
+ }
605
+ for (j=0; j<nc; j++) {
606
+ if (idx < pd.length){
607
+ lt = this.labels[idx] || pd[idx][0].toString();
608
+ color = colorGenerator.next();
609
+ if (!reverse){
610
+ if (i>0){
611
+ pad = true;
612
+ }
613
+ else{
614
+ pad = false;
615
+ }
616
+ }
617
+ else{
618
+ if (i == nr -1){
619
+ pad = false;
620
+ }
621
+ else{
622
+ pad = true;
623
+ }
624
+ }
625
+ rs = (pad) ? this.rowSpacing : '0';
626
+
627
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
628
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
629
+ '</div></td>');
630
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
631
+ if (this.escapeHtml){
632
+ td2.text(lt);
633
+ }
634
+ else {
635
+ td2.html(lt);
636
+ }
637
+ if (reverse) {
638
+ td2.prependTo(tr);
639
+ td1.prependTo(tr);
640
+ }
641
+ else {
642
+ td1.appendTo(tr);
643
+ td2.appendTo(tr);
644
+ }
645
+ pad = true;
646
+ }
647
+ idx++;
648
+ }
649
+ }
650
+ }
651
+ }
652
+ return this._elem;
653
+ };
654
+
655
+ // $.jqplot.FunnelLegendRenderer.prototype.pack = function(offsets) {
656
+ // if (this.show) {
657
+ // // fake a grid for positioning
658
+ // var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};
659
+ // if (this.placement == 'insideGrid') {
660
+ // switch (this.location) {
661
+ // case 'nw':
662
+ // var a = grid._left + this.xoffset;
663
+ // var b = grid._top + this.yoffset;
664
+ // this._elem.css('left', a);
665
+ // this._elem.css('top', b);
666
+ // break;
667
+ // case 'n':
668
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
669
+ // var b = grid._top + this.yoffset;
670
+ // this._elem.css('left', a);
671
+ // this._elem.css('top', b);
672
+ // break;
673
+ // case 'ne':
674
+ // var a = offsets.right + this.xoffset;
675
+ // var b = grid._top + this.yoffset;
676
+ // this._elem.css({right:a, top:b});
677
+ // break;
678
+ // case 'e':
679
+ // var a = offsets.right + this.xoffset;
680
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
681
+ // this._elem.css({right:a, top:b});
682
+ // break;
683
+ // case 'se':
684
+ // var a = offsets.right + this.xoffset;
685
+ // var b = offsets.bottom + this.yoffset;
686
+ // this._elem.css({right:a, bottom:b});
687
+ // break;
688
+ // case 's':
689
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
690
+ // var b = offsets.bottom + this.yoffset;
691
+ // this._elem.css({left:a, bottom:b});
692
+ // break;
693
+ // case 'sw':
694
+ // var a = grid._left + this.xoffset;
695
+ // var b = offsets.bottom + this.yoffset;
696
+ // this._elem.css({left:a, bottom:b});
697
+ // break;
698
+ // case 'w':
699
+ // var a = grid._left + this.xoffset;
700
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
701
+ // this._elem.css({left:a, top:b});
702
+ // break;
703
+ // default: // same as 'se'
704
+ // var a = grid._right - this.xoffset;
705
+ // var b = grid._bottom + this.yoffset;
706
+ // this._elem.css({right:a, bottom:b});
707
+ // break;
708
+ // }
709
+ //
710
+ // }
711
+ // else {
712
+ // switch (this.location) {
713
+ // case 'nw':
714
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
715
+ // var b = grid._top + this.yoffset;
716
+ // this._elem.css('right', a);
717
+ // this._elem.css('top', b);
718
+ // break;
719
+ // case 'n':
720
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
721
+ // var b = this._plotDimensions.height - grid._top + this.yoffset;
722
+ // this._elem.css('left', a);
723
+ // this._elem.css('bottom', b);
724
+ // break;
725
+ // case 'ne':
726
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
727
+ // var b = grid._top + this.yoffset;
728
+ // this._elem.css({left:a, top:b});
729
+ // break;
730
+ // case 'e':
731
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
732
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
733
+ // this._elem.css({left:a, top:b});
734
+ // break;
735
+ // case 'se':
736
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
737
+ // var b = offsets.bottom + this.yoffset;
738
+ // this._elem.css({left:a, bottom:b});
739
+ // break;
740
+ // case 's':
741
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
742
+ // var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
743
+ // this._elem.css({left:a, top:b});
744
+ // break;
745
+ // case 'sw':
746
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
747
+ // var b = offsets.bottom + this.yoffset;
748
+ // this._elem.css({right:a, bottom:b});
749
+ // break;
750
+ // case 'w':
751
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
752
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
753
+ // this._elem.css({right:a, top:b});
754
+ // break;
755
+ // default: // same as 'se'
756
+ // var a = grid._right - this.xoffset;
757
+ // var b = grid._bottom + this.yoffset;
758
+ // this._elem.css({right:a, bottom:b});
759
+ // break;
760
+ // }
761
+ // }
762
+ // }
763
+ // };
764
+
765
+ // setup default renderers for axes and legend so user doesn't have to
766
+ // called with scope of plot
767
+ function preInit(target, data, options) {
768
+ options = options || {};
769
+ options.axesDefaults = options.axesDefaults || {};
770
+ options.legend = options.legend || {};
771
+ options.seriesDefaults = options.seriesDefaults || {};
772
+ // only set these if there is a funnel series
773
+ var setopts = false;
774
+ if (options.seriesDefaults.renderer == $.jqplot.FunnelRenderer) {
775
+ setopts = true;
776
+ }
777
+ else if (options.series) {
778
+ for (var i=0; i < options.series.length; i++) {
779
+ if (options.series[i].renderer == $.jqplot.FunnelRenderer) {
780
+ setopts = true;
781
+ }
782
+ }
783
+ }
784
+
785
+ if (setopts) {
786
+ options.axesDefaults.renderer = $.jqplot.FunnelAxisRenderer;
787
+ options.legend.renderer = $.jqplot.FunnelLegendRenderer;
788
+ options.legend.preDraw = true;
789
+ options.sortData = false;
790
+ options.seriesDefaults.pointLabels = {show: false};
791
+ }
792
+ }
793
+
794
+ function postInit(target, data, options) {
795
+ // if multiple series, add a reference to the previous one so that
796
+ // funnel rings can nest.
797
+ for (var i=0; i<this.series.length; i++) {
798
+ if (this.series[i].renderer.constructor == $.jqplot.FunnelRenderer) {
799
+ // don't allow mouseover and mousedown at same time.
800
+ if (this.series[i].highlightMouseOver) {
801
+ this.series[i].highlightMouseDown = false;
802
+ }
803
+ }
804
+ }
805
+ }
806
+
807
+ // called with scope of plot
808
+ function postParseOptions(options) {
809
+ for (var i=0; i<this.series.length; i++) {
810
+ this.series[i].seriesColors = this.seriesColors;
811
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
812
+ }
813
+ }
814
+
815
+ function highlight (plot, sidx, pidx) {
816
+ var s = plot.series[sidx];
817
+ var canvas = plot.plugins.funnelRenderer.highlightCanvas;
818
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
819
+ s._highlightedPoint = pidx;
820
+ plot.plugins.funnelRenderer.highlightedSeriesIndex = sidx;
821
+ s.renderer.drawSection.call(s, canvas._ctx, s._vertices[pidx], s.highlightColors[pidx], false);
822
+ }
823
+
824
+ function unhighlight (plot) {
825
+ var canvas = plot.plugins.funnelRenderer.highlightCanvas;
826
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
827
+ for (var i=0; i<plot.series.length; i++) {
828
+ plot.series[i]._highlightedPoint = null;
829
+ }
830
+ plot.plugins.funnelRenderer.highlightedSeriesIndex = null;
831
+ plot.target.trigger('jqplotDataUnhighlight');
832
+ }
833
+
834
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
835
+ if (neighbor) {
836
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
837
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
838
+ evt1.pageX = ev.pageX;
839
+ evt1.pageY = ev.pageY;
840
+ plot.target.trigger(evt1, ins);
841
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
842
+ var evt = jQuery.Event('jqplotDataHighlight');
843
+ evt.pageX = ev.pageX;
844
+ evt.pageY = ev.pageY;
845
+ plot.target.trigger(evt, ins);
846
+ highlight (plot, ins[0], ins[1]);
847
+ }
848
+ }
849
+ else if (neighbor == null) {
850
+ unhighlight (plot);
851
+ }
852
+ }
853
+
854
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
855
+ if (neighbor) {
856
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
857
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
858
+ var evt = jQuery.Event('jqplotDataHighlight');
859
+ evt.pageX = ev.pageX;
860
+ evt.pageY = ev.pageY;
861
+ plot.target.trigger(evt, ins);
862
+ highlight (plot, ins[0], ins[1]);
863
+ }
864
+ }
865
+ else if (neighbor == null) {
866
+ unhighlight (plot);
867
+ }
868
+ }
869
+
870
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
871
+ var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
872
+ if (idx != null && plot.series[idx].highlightMouseDown) {
873
+ unhighlight(plot);
874
+ }
875
+ }
876
+
877
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
878
+ if (neighbor) {
879
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
880
+ var evt = jQuery.Event('jqplotDataClick');
881
+ evt.pageX = ev.pageX;
882
+ evt.pageY = ev.pageY;
883
+ plot.target.trigger(evt, ins);
884
+ }
885
+ }
886
+
887
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
888
+ if (neighbor) {
889
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
890
+ var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
891
+ if (idx != null && plot.series[idx].highlightMouseDown) {
892
+ unhighlight(plot);
893
+ }
894
+ var evt = jQuery.Event('jqplotDataRightClick');
895
+ evt.pageX = ev.pageX;
896
+ evt.pageY = ev.pageY;
897
+ plot.target.trigger(evt, ins);
898
+ }
899
+ }
900
+
901
+ // called within context of plot
902
+ // create a canvas which we can draw on.
903
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
904
+ function postPlotDraw() {
905
+ // Memory Leaks patch
906
+ if (this.plugins.funnelRenderer && this.plugins.funnelRenderer.highlightCanvas) {
907
+ this.plugins.funnelRenderer.highlightCanvas.resetCanvas();
908
+ this.plugins.funnelRenderer.highlightCanvas = null;
909
+ }
910
+
911
+ this.plugins.funnelRenderer = {};
912
+ this.plugins.funnelRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
913
+
914
+ // do we have any data labels? if so, put highlight canvas before those
915
+ var labels = $(this.targetId+' .jqplot-data-label');
916
+ if (labels.length) {
917
+ $(labels[0]).before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
918
+ }
919
+ // else put highlight canvas before event canvas.
920
+ else {
921
+ this.eventCanvas._elem.before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
922
+ }
923
+ var hctx = this.plugins.funnelRenderer.highlightCanvas.setContext();
924
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
925
+ }
926
+
927
+ $.jqplot.preInitHooks.push(preInit);
928
+
929
+ $.jqplot.FunnelTickRenderer = function() {
930
+ $.jqplot.AxisTickRenderer.call(this);
931
+ };
932
+
933
+ $.jqplot.FunnelTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
934
+ $.jqplot.FunnelTickRenderer.prototype.constructor = $.jqplot.FunnelTickRenderer;
935
+
936
+ })(jQuery);
937
+
938
+