rgraph-rails 1.0.1

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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +4 -0
  7. data/README.md +73 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/lib/rgraph-rails/version.rb +3 -0
  12. data/lib/rgraph-rails.rb +8 -0
  13. data/license.txt +19 -0
  14. data/rgraph-rails.gemspec +26 -0
  15. data/vendor/assets/images/bg.png +0 -0
  16. data/vendor/assets/images/bullet.png +0 -0
  17. data/vendor/assets/images/facebook-large.png +0 -0
  18. data/vendor/assets/images/google-plus-large.png +0 -0
  19. data/vendor/assets/images/logo.png +0 -0
  20. data/vendor/assets/images/meter-image-sd-needle.png +0 -0
  21. data/vendor/assets/images/meter-image-sd.png +0 -0
  22. data/vendor/assets/images/meter-sketch-needle.png +0 -0
  23. data/vendor/assets/images/meter-sketch.png +0 -0
  24. data/vendor/assets/images/odometer-background.png +0 -0
  25. data/vendor/assets/images/rgraph.jpg +0 -0
  26. data/vendor/assets/images/title.png +0 -0
  27. data/vendor/assets/images/twitter-large.png +0 -0
  28. data/vendor/assets/javascripts/RGraph.bar.js +3246 -0
  29. data/vendor/assets/javascripts/RGraph.bipolar.js +2003 -0
  30. data/vendor/assets/javascripts/RGraph.common.annotate.js +399 -0
  31. data/vendor/assets/javascripts/RGraph.common.context.js +600 -0
  32. data/vendor/assets/javascripts/RGraph.common.core.js +4751 -0
  33. data/vendor/assets/javascripts/RGraph.common.csv.js +275 -0
  34. data/vendor/assets/javascripts/RGraph.common.deprecated.js +454 -0
  35. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1194 -0
  36. data/vendor/assets/javascripts/RGraph.common.effects.js +1524 -0
  37. data/vendor/assets/javascripts/RGraph.common.key.js +735 -0
  38. data/vendor/assets/javascripts/RGraph.common.resizing.js +550 -0
  39. data/vendor/assets/javascripts/RGraph.common.tooltips.js +605 -0
  40. data/vendor/assets/javascripts/RGraph.common.zoom.js +223 -0
  41. data/vendor/assets/javascripts/RGraph.drawing.background.js +636 -0
  42. data/vendor/assets/javascripts/RGraph.drawing.circle.js +579 -0
  43. data/vendor/assets/javascripts/RGraph.drawing.image.js +810 -0
  44. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +710 -0
  45. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +672 -0
  46. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +568 -0
  47. data/vendor/assets/javascripts/RGraph.drawing.poly.js +623 -0
  48. data/vendor/assets/javascripts/RGraph.drawing.rect.js +603 -0
  49. data/vendor/assets/javascripts/RGraph.drawing.text.js +648 -0
  50. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +815 -0
  51. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +860 -0
  52. data/vendor/assets/javascripts/RGraph.fuel.js +965 -0
  53. data/vendor/assets/javascripts/RGraph.funnel.js +988 -0
  54. data/vendor/assets/javascripts/RGraph.gantt.js +1242 -0
  55. data/vendor/assets/javascripts/RGraph.gauge.js +1391 -0
  56. data/vendor/assets/javascripts/RGraph.hbar.js +1794 -0
  57. data/vendor/assets/javascripts/RGraph.hprogress.js +1307 -0
  58. data/vendor/assets/javascripts/RGraph.line.js +3940 -0
  59. data/vendor/assets/javascripts/RGraph.meter.js +1242 -0
  60. data/vendor/assets/javascripts/RGraph.modaldialog.js +292 -0
  61. data/vendor/assets/javascripts/RGraph.odo.js +1265 -0
  62. data/vendor/assets/javascripts/RGraph.pie.js +1979 -0
  63. data/vendor/assets/javascripts/RGraph.radar.js +1840 -0
  64. data/vendor/assets/javascripts/RGraph.rose.js +1860 -0
  65. data/vendor/assets/javascripts/RGraph.rscatter.js +1332 -0
  66. data/vendor/assets/javascripts/RGraph.scatter.js +3029 -0
  67. data/vendor/assets/javascripts/RGraph.thermometer.js +1131 -0
  68. data/vendor/assets/javascripts/RGraph.vprogress.js +1326 -0
  69. data/vendor/assets/javascripts/RGraph.waterfall.js +1252 -0
  70. data/vendor/assets/javascripts/financial-data.js +1067 -0
  71. data/vendor/assets/stylesheets/ModalDialog.css +90 -0
  72. data/vendor/assets/stylesheets/animations.css +3347 -0
  73. data/vendor/assets/stylesheets/website.css +402 -0
  74. metadata +175 -0
@@ -0,0 +1,1979 @@
1
+ // version: 2015-11-02
2
+ /**
3
+ * o--------------------------------------------------------------------------------o
4
+ * | This file is part of the RGraph package - you can learn more at: |
5
+ * | |
6
+ * | http://www.rgraph.net |
7
+ * | |
8
+ * | RGraph is dual licensed under the Open Source GPL (General Public License) |
9
+ * | v2.0 license and a commercial license which means that you're not bound by |
10
+ * | the terms of the GPL. The commercial license is just �99 (GBP) and you can |
11
+ * | read about it here: |
12
+ * | http://www.rgraph.net/license |
13
+ * o--------------------------------------------------------------------------------o
14
+ */
15
+
16
+ RGraph = window.RGraph || {isRGraph: true};
17
+
18
+ /**
19
+ * The pie chart constructor
20
+ *
21
+ * @param data array The data to be represented on the Pie chart
22
+ */
23
+ RGraph.Pie = function (conf)
24
+ {
25
+ /**
26
+ * Allow for object config style
27
+ */
28
+ if ( typeof conf === 'object'
29
+ && typeof conf.data === 'object'
30
+ && typeof conf.id === 'string') {
31
+
32
+ var id = conf.id;
33
+ var canvas = document.getElementById(id);
34
+ var data = conf.data;
35
+ var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
36
+
37
+ } else {
38
+
39
+ var id = conf;
40
+ var canvas = document.getElementById(id);
41
+ var data = arguments[1];
42
+ }
43
+
44
+
45
+
46
+
47
+ // Get the canvas and context objects
48
+ this.id = id;
49
+ this.canvas = canvas;
50
+ this.context = this.canvas.getContext ? this.canvas.getContext("2d", {alpha: (typeof id === 'object' && id.alpha === false) ? false : true}) : null;
51
+ this.canvas.__object__ = this;
52
+ this.total = 0;
53
+ this.subTotal = 0;
54
+ this.angles = [];
55
+ this.data = data;
56
+ this.properties = [];
57
+ this.type = 'pie';
58
+ this.isRGraph = true;
59
+ this.coords = [];
60
+ this.coords.key = [];
61
+ this.coordsSticks = [];
62
+ this.coordsText = [];
63
+ this.uid = RGraph.CreateUID();
64
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
65
+ this.colorsParsed = false;
66
+ this.original_colors = [];
67
+ this.firstDraw = true; // After the first draw this will be false
68
+
69
+
70
+ /**
71
+ * Compatibility with older browsers
72
+ */
73
+ //RGraph.OldBrowserCompat(this.context);
74
+
75
+ this.properties =
76
+ {
77
+ 'chart.centerx.adjust': 0,
78
+ 'chart.centery.adjust': 0,
79
+ 'chart.colors': ['Gradient(red:#fcc)', 'Gradient(#ddd:#eee)', 'Gradient(#0f0:#cfc)', 'Gradient(blue:#ccf)', 'Gradient(#FB7BA3:#FCC7EE)', 'Gradient(yellow:#ffc)', 'Gradient(#000:#ccc)', 'Gradient(#EE9D80:#FEE5C8)', 'Gradient(cyan:#ccf)','Gradient(#9E7BF6:#C7B6D2)','Gradient(#78CAEA:#C5FBFD)','Gradient(#E284E9:#FDC4FF)','Gradient(white:#ccf)','Gradient(blue:#ccf)','Gradient(#9E7BF6:#C7B6D2)'],
80
+ 'chart.strokestyle': 'white',
81
+ 'chart.linewidth': 3,
82
+ 'chart.labels': [],
83
+ 'chart.labels.sticks': false,
84
+ 'chart.labels.sticks.length': 7,
85
+ 'chart.labels.sticks.color': '#aaa',
86
+ 'chart.labels.sticks.hlength': 5,
87
+ 'chart.labels.ingraph': null,
88
+ 'chart.labels.ingraph.color': null,
89
+ 'chart.labels.ingraph.font': null,
90
+ 'chart.labels.ingraph.size': null,
91
+ 'chart.labels.ingraph.bounding':true,
92
+ 'chart.labels.ingraph.bounding.fill':'white',
93
+ 'chart.labels.ingraph.specific':null,
94
+ 'chart.labels.ingraph.units.pre':'',
95
+ 'chart.labels.ingraph.units.post':'',
96
+ 'chart.labels.ingraph.radius': null,
97
+ 'chart.labels.center': null,
98
+ 'chart.labels.center.size': 26,
99
+ 'chart.labels.center.font': 'Arial',
100
+ 'chart.labels.center.color': 'black',
101
+ 'chart.labels.center.italic': false,
102
+ 'chart.labels.center.bold': false,
103
+ 'chart.labels.center.units.pre': '',
104
+ 'chart.labels.center.units.post': '',
105
+ 'chart.gutter.left': 25,
106
+ 'chart.gutter.right': 25,
107
+ 'chart.gutter.top': 25,
108
+ 'chart.gutter.bottom': 25,
109
+ 'chart.title': '',
110
+ 'chart.title.background': null,
111
+ 'chart.title.hpos': null,
112
+ 'chart.title.vpos': 0.5,
113
+ 'chart.title.bold': true,
114
+ 'chart.title.font': null,
115
+ 'chart.title.x': null,
116
+ 'chart.title.y': null,
117
+ 'chart.title.halign': null,
118
+ 'chart.title.valign': null,
119
+ 'chart.shadow': true,
120
+ 'chart.shadow.color': '#aaa',
121
+ 'chart.shadow.offsetx': 0,
122
+ 'chart.shadow.offsety': 0,
123
+ 'chart.shadow.blur': 15,
124
+ 'chart.text.size': 12,
125
+ 'chart.text.color': 'black',
126
+ 'chart.text.font': 'Arial',
127
+ 'chart.contextmenu': null,
128
+ 'chart.tooltips': null,
129
+ 'chart.tooltips.event': 'onclick',
130
+ 'chart.tooltips.effect': 'fade',
131
+ 'chart.tooltips.css.class': 'RGraph_tooltip',
132
+ 'chart.tooltips.highlight': true,
133
+ 'chart.highlight.style': '2d',
134
+ 'chart.highlight.style.2d.fill': 'rgba(255,255,255,0.7)',
135
+ 'chart.highlight.style.2d.stroke': 'rgba(255,255,255,0.7)',
136
+ 'chart.centerx': null,
137
+ 'chart.centery': null,
138
+ 'chart.radius': null,
139
+ 'chart.border': false,
140
+ 'chart.border.color': 'rgba(255,255,255,0.5)',
141
+ 'chart.key': null,
142
+ 'chart.key.background': 'white',
143
+ 'chart.key.position': 'graph',
144
+ 'chart.key.halign': 'right',
145
+ 'chart.key.shadow': false,
146
+ 'chart.key.shadow.color': '#666',
147
+ 'chart.key.shadow.blur': 3,
148
+ 'chart.key.shadow.offsetx': 2,
149
+ 'chart.key.shadow.offsety': 2,
150
+ 'chart.key.position.gutter.boxed': false,
151
+ 'chart.key.position.x': null,
152
+ 'chart.key.position.y': null,
153
+ 'chart.key.color.shape': 'square',
154
+ 'chart.key.rounded': true,
155
+ 'chart.key.linewidth': 1,
156
+ 'chart.key.colors': null,
157
+ 'chart.key.interactive': false,
158
+ 'chart.key.interactive.highlight.chart.stroke': 'black',
159
+ 'chart.key.interactive.highlight.chart.fill': 'rgba(255,255,255,0.7)',
160
+ 'chart.key.interactive.highlight.label': 'rgba(255,0,0,0.2)',
161
+ 'chart.key.text.color': 'black',
162
+ 'chart.annotatable': false,
163
+ 'chart.annotate.color': 'black',
164
+ 'chart.zoom.factor': 1.5,
165
+ 'chart.zoom.fade.in': true,
166
+ 'chart.zoom.fade.out': true,
167
+ 'chart.zoom.hdir': 'right',
168
+ 'chart.zoom.vdir': 'down',
169
+ 'chart.zoom.frames': 25,
170
+ 'chart.zoom.delay': 16.666,
171
+ 'chart.zoom.shadow': true,
172
+ 'chart.zoom.background': true,
173
+ 'chart.zoom.action': 'zoom',
174
+ 'chart.resizable': false,
175
+ 'chart.resize.handle.adjust': [0,0],
176
+ 'chart.resize.handle.background': null,
177
+ 'chart.variant': 'pie',
178
+ 'chart.variant.donut.width': null,
179
+ 'chart.variant.threed.depth': 20,
180
+ 'chart.exploded': [],
181
+ 'chart.effect.roundrobin.multiplier': 1,
182
+ 'chart.events.click': null,
183
+ 'chart.events.mousemove': null,
184
+ 'chart.centerpin': null,
185
+ 'chart.centerpin.fill': 'gray',
186
+ 'chart.centerpin.stroke': 'white',
187
+ 'chart.origin': 0 - (Math.PI / 2),
188
+ 'chart.events': true,
189
+ 'chart.labels.colors': []
190
+ }
191
+
192
+
193
+
194
+ /**
195
+ * Calculate the total
196
+ */
197
+ for (var i=0,len=data.length; i<len; i++) {
198
+ this.total += data[i];
199
+
200
+ // This loop also creates the $xxx objects - this isn't related to
201
+ // the code above but just saves doing another loop through the data
202
+ this['$' + i] = {};
203
+ }
204
+
205
+
206
+ /**
207
+ * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
208
+ * done already
209
+ */
210
+ if (!this.canvas.__rgraph_aa_translated__) {
211
+ this.context.translate(0.5,0.5);
212
+
213
+ this.canvas.__rgraph_aa_translated__ = true;
214
+ }
215
+
216
+
217
+
218
+
219
+ // Short variable names
220
+ var RG = RGraph,
221
+ ca = this.canvas,
222
+ co = ca.getContext('2d'),
223
+ prop = this.properties,
224
+ pa = RG.Path,
225
+ pa2 = RG.path2,
226
+ win = window,
227
+ doc = document,
228
+ ma = Math
229
+
230
+
231
+
232
+ /**
233
+ * "Decorate" the object with the generic effects if the effects library has been included
234
+ */
235
+ if (RG.Effects && typeof RG.Effects.decorate === 'function') {
236
+ RG.Effects.decorate(this);
237
+ }
238
+
239
+
240
+
241
+
242
+ /**
243
+ * A generic setter
244
+ */
245
+ this.set =
246
+ this.Set = function (name)
247
+ {
248
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
249
+
250
+ /**
251
+ * the number of arguments is only one and it's an
252
+ * object - parse it for configuration data and return.
253
+ */
254
+ if (arguments.length === 1 && typeof name === 'object') {
255
+ RG.parseObjectStyleConfig(this, name);
256
+ return this;
257
+ }
258
+
259
+
260
+
261
+
262
+
263
+ /**
264
+ * This should be done first - prepend the property name with "chart." if necessary
265
+ */
266
+ if (name.substr(0,6) != 'chart.') {
267
+ name = 'chart.' + name;
268
+ }
269
+
270
+
271
+
272
+
273
+ // Convert uppercase letters to dot+lower case letter
274
+ name = name.replace(/([A-Z])/g, function (str)
275
+ {
276
+ return '.' + String(RegExp.$1).toLowerCase();
277
+ });
278
+
279
+ if (name == 'chart.highlight.style.2d.color') {
280
+ name = 'chart.highlight.style.2d.fill';
281
+ }
282
+
283
+
284
+
285
+
286
+
287
+
288
+ prop[name] = value;
289
+
290
+ return this;
291
+ };
292
+
293
+
294
+
295
+
296
+ /**
297
+ * A generic getter
298
+ */
299
+ this.get =
300
+ this.Get = function (name)
301
+ {
302
+ /**
303
+ * This should be done first - prepend the property name with "chart." if necessary
304
+ */
305
+ if (name.substr(0,6) != 'chart.') {
306
+ name = 'chart.' + name;
307
+ }
308
+
309
+ // Convert uppercase letters to dot+lower case letter
310
+ name = name.replace(/([A-Z])/g, function (str)
311
+ {
312
+ return '.' + String(RegExp.$1).toLowerCase()
313
+ });
314
+
315
+ if (name == 'chart.highlight.style.2d.color') {
316
+ name = 'chart.highlight.style.2d.fill';
317
+ }
318
+
319
+ return prop[name];
320
+ };
321
+
322
+
323
+
324
+
325
+ /**
326
+ * This draws the pie chart
327
+ */
328
+ this.draw =
329
+ this.Draw = function ()
330
+ {
331
+ /**
332
+ * Fire the onbeforedraw event
333
+ */
334
+ RG.FireCustomEvent(this, 'onbeforedraw');
335
+
336
+ // NB: Colors are parsed further down so that the center X/Y can be used
337
+
338
+
339
+ /**
340
+ * This is new in May 2011 and facilitates indiviual gutter settings,
341
+ * eg chart.gutter.left
342
+ */
343
+ this.gutterLeft = prop['chart.gutter.left'];
344
+ this.gutterRight = prop['chart.gutter.right'];
345
+ this.gutterTop = prop['chart.gutter.top'];
346
+ this.gutterBottom = prop['chart.gutter.bottom'];
347
+
348
+ this.radius = this.getRadius();// MUST be first
349
+ this.centerx = (this.graph.width / 2) + this.gutterLeft + prop['chart.centerx.adjust'];
350
+ this.centery = (this.graph.height / 2) + this.gutterTop + prop['chart.centery.adjust'];
351
+ this.subTotal = this.properties['chart.origin'];
352
+ this.angles = [];
353
+ this.coordsText = [];
354
+
355
+ /**
356
+ * Allow specification of a custom radius & center X/Y
357
+ */
358
+ if (typeof prop['chart.radius'] === 'number') this.radius = prop['chart.radius'];
359
+ if (typeof prop['chart.centerx'] === 'number') this.centerx = prop['chart.centerx'];
360
+ if (typeof prop['chart.centery'] === 'number') this.centery = prop['chart.centery'];
361
+
362
+
363
+ if (this.radius <= 0) {
364
+ return;
365
+ }
366
+
367
+ /**
368
+ * Parse the colors for gradients. Its down here so that the center X/Y can be used
369
+ */
370
+ if (!this.colorsParsed) {
371
+
372
+ this.parseColors();
373
+
374
+ // Don't want to do this again
375
+ this.colorsParsed = true;
376
+ }
377
+
378
+
379
+
380
+ /**
381
+ * This sets the label colors. Doing it here saves lots of if() conditions in the draw method
382
+ */
383
+ if (prop['chart.labels.colors'].length < prop['chart.labels'].length) {
384
+ while (prop['chart.labels.colors'].length < prop['chart.labels'].length) {
385
+ prop['chart.labels.colors'].push(prop['chart.labels.colors'][prop['chart.labels.colors'].length - 1]);
386
+ }
387
+ } else {
388
+ if (typeof prop['chart.labels.colors'] === 'undefined') {
389
+ prop['chart.labels.colors'] = [];
390
+ }
391
+
392
+ while (prop['chart.labels.colors'].length < prop['chart.labels'].length) {
393
+ prop['chart.labels.colors'].push(prop['chart.text.color']);
394
+ }
395
+ }
396
+
397
+
398
+
399
+
400
+ if (prop['chart.variant'].indexOf('3d') > 0) {
401
+ return this.draw3d();
402
+ }
403
+
404
+
405
+
406
+
407
+ /**
408
+ * Draw the title
409
+ */
410
+ RG.DrawTitle(
411
+ this,
412
+ prop['chart.title'],
413
+ (ca.height / 2) - this.radius - 5,
414
+ this.centerx,
415
+ prop['chart.title.size'] ? prop['chart.title.size'] : prop['chart.text.size'] + 2
416
+ );
417
+
418
+ /**
419
+ * Draw the shadow if required
420
+ *
421
+ * ???
422
+ */
423
+ //if (prop['chart.shadow'] && false) {
424
+ //
425
+ // var offsetx = doc.all ? prop['chart.shadow.offsetx'] : 0;
426
+ // var offsety = doc.all ? prop['chart.shadow.offsety'] : 0;
427
+ //
428
+ // co.beginPath();
429
+ // co.fillStyle = prop['chart.shadow.color'];
430
+ //
431
+ // co.shadowColor = prop['chart.shadow.color'];
432
+ // co.shadowBlur = prop['chart.shadow.blur'];
433
+ // co.shadowOffsetX = prop['chart.shadow.offsetx'];
434
+ // co.shadowOffsetY = prop['chart.shadow.offsety'];
435
+ //
436
+ // co.arc(this.centerx + offsetx, this.centery + offsety, this.radius, 0, TWOPI, 0);
437
+ //
438
+ // co.fill();
439
+ //
440
+ // // Now turn off the shadow
441
+ // RG.NoShadow(this);
442
+ //}
443
+
444
+ /**
445
+ * The total of the array of values
446
+ */
447
+ this.total = RG.array_sum(this.data);
448
+ var tot = this.total;
449
+ var data = this.data;
450
+
451
+ for (var i=0,len=this.data.length; i<len; i++) {
452
+
453
+ var angle = ((data[i] / tot) * RG.TWOPI);
454
+
455
+ // Draw the segment
456
+ this.DrawSegment(angle,prop['chart.colors'][i],i == (len - 1), i);
457
+ }
458
+
459
+ RG.NoShadow(this);
460
+
461
+ /**
462
+ * Redraw the seperating lines
463
+ */
464
+ if (prop['chart.linewidth'] > 0) {
465
+ this.DrawBorders();
466
+ }
467
+
468
+ /**
469
+ * Now draw the segments again with shadow turned off. This is always performed,
470
+ * not just if the shadow is on.
471
+ */
472
+ var len = this.angles.length;
473
+ var r = this.radius;
474
+
475
+
476
+ for (var action=0; action<2; action+=1) {
477
+ for (var i=0; i<len; i++) {
478
+
479
+ co.beginPath();
480
+
481
+ var segment = this.angles[i];
482
+
483
+ if (action === 1) {
484
+ co.strokeStyle = typeof(prop['chart.strokestyle']) == 'object' ? prop['chart.strokestyle'][i] : prop['chart.strokestyle'];
485
+ }
486
+ prop['chart.colors'][i] ? co.fillStyle = prop['chart.colors'][i] : null;
487
+ co.lineJoin = 'round';
488
+
489
+ co.arc(segment[2],
490
+ segment[3],
491
+ r,
492
+ (segment[0]),
493
+ (segment[1]),
494
+ false);
495
+ if (prop['chart.variant'] == 'donut') {
496
+
497
+ co.arc(
498
+ segment[2],
499
+ segment[3],
500
+ typeof(prop['chart.variant.donut.width']) == 'number' ? r - prop['chart.variant.donut.width'] : r / 2,
501
+ (segment[1]),
502
+ (segment[0]),
503
+ true
504
+ );
505
+
506
+ } else {
507
+ co.lineTo(segment[2], segment[3]);
508
+ }
509
+ co.closePath();
510
+ action === 0 ? co.fill() : co.stroke();
511
+ }
512
+ }
513
+
514
+
515
+
516
+
517
+ /**
518
+ * Draw label sticks
519
+ */
520
+ if (prop['chart.labels.sticks']) {
521
+
522
+ this.DrawSticks();
523
+
524
+ // Redraw the border going around the Pie chart if the stroke style is NOT white
525
+ var strokeStyle = prop['chart.strokestyle'];
526
+ }
527
+
528
+ /**
529
+ * Draw the labels
530
+ */
531
+ if (prop['chart.labels']) {
532
+ this.DrawLabels();
533
+ }
534
+
535
+
536
+ /**
537
+ * Draw centerpin if requested
538
+ */
539
+ if (prop['chart.centerpin']) {
540
+ this.DrawCenterpin();
541
+ }
542
+
543
+
544
+
545
+
546
+ /**
547
+ * Draw ingraph labels
548
+ */
549
+ if (prop['chart.labels.ingraph']) {
550
+ this.DrawInGraphLabels();
551
+ }
552
+
553
+
554
+
555
+
556
+ /**
557
+ * Draw the center label if requested
558
+ */
559
+ if (!RG.isNull(prop['chart.labels.center'])) {
560
+ this.drawCenterLabel(prop['chart.labels.center']);
561
+ }
562
+
563
+
564
+ /**
565
+ * Setup the context menu if required
566
+ */
567
+ if (prop['chart.contextmenu']) {
568
+ RG.ShowContext(this);
569
+ }
570
+
571
+
572
+
573
+ /**
574
+ * If a border is pecified, draw it
575
+ */
576
+ if (prop['chart.border']) {
577
+ co.beginPath();
578
+ co.lineWidth = 5;
579
+ co.strokeStyle = prop['chart.border.color'];
580
+
581
+ co.arc(this.centerx,
582
+ this.centery,
583
+ this.radius - 2,
584
+ 0,
585
+ RG.TWOPI,
586
+ 0);
587
+
588
+ co.stroke();
589
+ }
590
+
591
+ /**
592
+ * Draw the kay if desired
593
+ */
594
+ if (prop['chart.key'] && prop['chart.key'].length) {
595
+ RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
596
+ }
597
+
598
+ RG.NoShadow(this);
599
+
600
+
601
+ /**
602
+ * This function enables resizing
603
+ */
604
+ if (prop['chart.resizable']) {
605
+ RG.AllowResizing(this);
606
+ }
607
+
608
+
609
+ /**
610
+ * This installs the event listeners
611
+ */
612
+ if (prop['chart.events'] == true) {
613
+ RG.InstallEventListeners(this);
614
+ }
615
+
616
+
617
+ /**
618
+ * Fire the onfirstdraw event
619
+ */
620
+ if (this.firstDraw) {
621
+ RG.fireCustomEvent(this, 'onfirstdraw');
622
+ this.firstDraw = false;
623
+ this.firstDrawFunc();
624
+ }
625
+
626
+
627
+
628
+
629
+ /**
630
+ * Fire the RGraph ondraw event
631
+ */
632
+ RG.FireCustomEvent(this, 'ondraw');
633
+
634
+ return this;
635
+ };
636
+
637
+
638
+
639
+ /**
640
+ * Used in chaining. Runs a function there and then - not waiting for
641
+ * the events to fire (eg the onbeforedraw event)
642
+ *
643
+ * @param function func The function to execute
644
+ */
645
+ this.exec = function (func)
646
+ {
647
+ func(this);
648
+
649
+ return this;
650
+ };
651
+
652
+
653
+
654
+
655
+ /**
656
+ * Draws a single segment of the pie chart
657
+ *
658
+ * @param int degrees The number of degrees for this segment
659
+ */
660
+ this.drawSegment =
661
+ this.DrawSegment = function (radians, color, last, index)
662
+ {
663
+ // IE7/8/ExCanvas fix (when there's only one segment the Pie chart doesn't display
664
+ if (RGraph.ISOLD && radians == RG.TWOPI) {
665
+ radians -= 0.0001;
666
+ } else if (RGraph.ISOLD && radians == 0) {
667
+ radians = 0.001;
668
+ }
669
+
670
+ var context = co;
671
+ var canvas = ca;
672
+ var subTotal = this.subTotal;
673
+ radians = radians * prop['chart.effect.roundrobin.multiplier'];
674
+
675
+ co.beginPath();
676
+
677
+ color ? co.fillStyle = color : null;
678
+ co.strokeStyle = prop['chart.strokestyle'];
679
+ co.lineWidth = 0;
680
+
681
+ if (prop['chart.shadow']) {
682
+ RG.SetShadow(this,
683
+ prop['chart.shadow.color'],
684
+ prop['chart.shadow.offsetx'],
685
+ prop['chart.shadow.offsety'],
686
+ prop['chart.shadow.blur']);
687
+ }
688
+
689
+ /**
690
+ * Exploded segments
691
+ */
692
+ if ( (typeof(prop['chart.exploded']) == 'object' && prop['chart.exploded'][index] > 0) || typeof(prop['chart.exploded']) == 'number') {
693
+
694
+ var explosion = typeof(prop['chart.exploded']) == 'number' ? prop['chart.exploded'] : prop['chart.exploded'][index];
695
+ var x = 0;
696
+ var y = 0;
697
+ var h = explosion;
698
+ var t = subTotal + (radians / 2);
699
+ var x = (Math.cos(t) * explosion);
700
+ var y = (Math.sin(t) * explosion);
701
+ var r = this.radius;
702
+
703
+ co.moveTo(this.centerx + x, this.centery + y);
704
+ } else {
705
+ var x = 0;
706
+ var y = 0;
707
+ var r = this.radius;
708
+ }
709
+
710
+ /**
711
+ * Calculate the angles
712
+ */
713
+ var startAngle = subTotal;
714
+ var endAngle = ((subTotal + radians));
715
+
716
+ co.arc(this.centerx + x,
717
+ this.centery + y,
718
+ r,
719
+ startAngle,
720
+ endAngle,
721
+ 0);
722
+
723
+ if (prop['chart.variant'] == 'donut') {
724
+
725
+ co.arc(this.centerx + x,
726
+ this.centery + y,
727
+ typeof(prop['chart.variant.donut.width']) == 'number' ? r - prop['chart.variant.donut.width'] : r / 2,
728
+ endAngle,
729
+ startAngle,
730
+ true);
731
+ } else {
732
+ co.lineTo(this.centerx + x, this.centery + y);
733
+ }
734
+
735
+ co.closePath();
736
+
737
+
738
+ // Keep hold of the angles
739
+ this.angles.push([subTotal, subTotal + radians, this.centerx + x, this.centery + y]);
740
+
741
+
742
+
743
+ //co.stroke();
744
+ co.fill();
745
+
746
+ /**
747
+ * Calculate the segment angle
748
+ */
749
+ this.subTotal += radians;
750
+ };
751
+
752
+
753
+
754
+
755
+ /**
756
+ * Draws the graphs labels
757
+ */
758
+ this.drawLabels =
759
+ this.DrawLabels = function ()
760
+ {
761
+ var hAlignment = 'left';
762
+ var vAlignment = 'center';
763
+ var labels = prop['chart.labels'];
764
+ var context = co;
765
+ var font = prop['chart.text.font'];
766
+ var text_size = prop['chart.text.size'];
767
+ var cx = this.centerx;
768
+ var cy = this.centery;
769
+ var r = this.radius;
770
+
771
+ /**
772
+ * Turn the shadow off
773
+ */
774
+ RG.NoShadow(this);
775
+
776
+ co.fillStyle = 'black';
777
+ co.beginPath();
778
+
779
+ /**
780
+ * Draw the labels
781
+ */
782
+ if (labels && labels.length) {
783
+
784
+ for (i=0; i<this.angles.length; ++i) {
785
+
786
+ var segment = this.angles[i];
787
+
788
+ if (typeof(labels[i]) != 'string' && typeof(labels[i]) != 'number') {
789
+ continue;
790
+ }
791
+
792
+ // Move to the centre
793
+ co.moveTo(cx,cy);
794
+
795
+ var a = segment[0] + ((segment[1] - segment[0]) / 2);
796
+ var angle = ((segment[1] - segment[0]) / 2) + segment[0];
797
+
798
+ /**
799
+ * Handle the additional "explosion" offset
800
+ */
801
+ if (typeof prop['chart.exploded'] === 'object' && prop['chart.exploded'][i] || typeof(prop['chart.exploded']) == 'number') {
802
+
803
+ var t = ((segment[1] - segment[0]) / 2);
804
+ var seperation = typeof(prop['chart.exploded']) == 'number' ? prop['chart.exploded'] : prop['chart.exploded'][i];
805
+
806
+ // Adjust the angles
807
+ var explosion_offsetx = (Math.cos(angle) * seperation);
808
+ var explosion_offsety = (Math.sin(angle) * seperation);
809
+ } else {
810
+ var explosion_offsetx = 0;
811
+ var explosion_offsety = 0;
812
+ }
813
+
814
+ /**
815
+ * Allow for the label sticks
816
+ */
817
+ if (prop['chart.labels.sticks']) {
818
+ explosion_offsetx += (ma.cos(angle) * (typeof prop['chart.labels.sticks.length'] === 'object' ? prop['chart.labels.sticks.length'][i] : prop['chart.labels.sticks.length']) );
819
+ explosion_offsety += (ma.sin(angle) * (typeof prop['chart.labels.sticks.length'] === 'object' ? prop['chart.labels.sticks.length'][i] : prop['chart.labels.sticks.length']) );
820
+ }
821
+
822
+ /**
823
+ * Coords for the text
824
+ */
825
+ var x = cx + explosion_offsetx + ((r + 10)* Math.cos(a)) + (prop['chart.labels.sticks'] ? (a < RG.HALFPI || a > (RG.TWOPI + RG.HALFPI) ? 2 : -2) : 0)
826
+ var y = cy + explosion_offsety + (((r + 10) * Math.sin(a)));
827
+
828
+
829
+
830
+
831
+ /**
832
+ * If sticks are enabled use the endpoints that have been saved
833
+ */
834
+ if (this.coordsSticks && this.coordsSticks[i]) {
835
+ var x = this.coordsSticks[i][4][0] + (x < cx ? -5 : 5);
836
+ var y = this.coordsSticks[i][4][1];
837
+ }
838
+
839
+
840
+ /**
841
+ * Alignment
842
+ */
843
+ //vAlignment = y < cy ? 'center' : 'center';
844
+ vAlignment = 'center';
845
+ hAlignment = x < cx ? 'right' : 'left';
846
+
847
+ co.fillStyle = prop['chart.text.color'];
848
+ if ( typeof(prop['chart.labels.colors']) == 'object' && prop['chart.labels.colors'] && prop['chart.labels.colors'][i]) {
849
+ co.fillStyle = prop['chart.labels.colors'][i];
850
+ }
851
+
852
+
853
+ RG.Text2(this, {'font':font,
854
+ 'size':text_size,
855
+ 'x':x,
856
+ 'y':y,
857
+ 'text':labels[i],
858
+ 'valign':vAlignment,
859
+ 'halign':hAlignment,
860
+ 'tag': 'labels'
861
+ });
862
+ }
863
+
864
+ co.fill();
865
+ }
866
+ };
867
+
868
+
869
+
870
+
871
+
872
+ /**
873
+ * This function draws the pie chart sticks (for the labels)
874
+ */
875
+ this.drawSticks =
876
+ this.DrawSticks = function ()
877
+ {
878
+ var context = co;
879
+ var offset = prop['chart.linewidth'] / 2;
880
+ var exploded = prop['chart.exploded'];
881
+ var sticks = prop['chart.labels.sticks'];
882
+ var cx = this.centerx;
883
+ var cy = this.centery;
884
+ var radius = this.radius;
885
+ var points = [];
886
+
887
+ for (var i=0,len=this.angles.length; i<len; ++i) {
888
+
889
+ var segment = this.angles[i];
890
+
891
+ // This allows the chart.labels.sticks to be an array as well as a boolean
892
+ if (typeof sticks === 'object' && !sticks[i]) {
893
+ continue;
894
+ }
895
+
896
+ var radians = segment[1] - segment[0];
897
+
898
+ co.beginPath();
899
+ co.strokeStyle = prop['chart.labels.sticks.color'];
900
+ co.lineWidth = 1;
901
+
902
+ var midpoint = (segment[0] + (radians / 2));
903
+
904
+ if (typeof exploded === 'object' && exploded[i]) {
905
+ var extra = exploded[i];
906
+ } else if (typeof exploded === 'number') {
907
+ var extra = exploded;
908
+ } else {
909
+ var extra = 0;
910
+ }
911
+
912
+ //context.lineJoin = 'round';
913
+ co.lineWidth = 1;
914
+
915
+ /**
916
+ * Determine the stick length
917
+ */
918
+ var stickLength = typeof prop['chart.labels.sticks.length'] === 'object' ? prop['chart.labels.sticks.length'][i] : prop['chart.labels.sticks.length'];
919
+
920
+
921
+ points[0] = RG.getRadiusEndPoint(cx, cy, midpoint, radius + extra + offset);
922
+ points[1] = RG.getRadiusEndPoint(cx, cy, midpoint, radius + stickLength + extra - 5);
923
+
924
+ points[2] = RG.getRadiusEndPoint(cx, cy, midpoint, radius + stickLength + extra);
925
+
926
+ points[3] = RG.getRadiusEndPoint(cx, cy, midpoint, radius + stickLength + extra);
927
+ points[3][0] += (points[3][0] > cx ? 5 : -5);
928
+
929
+ points[4] = [
930
+ points[2][0] + (points[2][0] > cx ? 5 + prop['chart.labels.sticks.hlength'] : -5 - prop['chart.labels.sticks.hlength']),
931
+ points[2][1]
932
+ ];
933
+
934
+
935
+ co.moveTo(points[0][0], points[0][1]);
936
+ co.quadraticCurveTo(points[2][0], points[2][1], points[4][0], points[4][1]);
937
+
938
+ co.stroke();
939
+
940
+ /**
941
+ * Save the stick end coords
942
+ */
943
+ this.coordsSticks[i] = [points[0],points[1], points[2], points[3], points[4]];
944
+ }
945
+ };
946
+
947
+
948
+
949
+
950
+ /**
951
+ * The (now Pie chart specific) getSegment function
952
+ *
953
+ * @param object e The event object
954
+ */
955
+ this.getShape =
956
+ this.getSegment = function (e)
957
+ {
958
+ RG.FixEventObject(e);
959
+
960
+ // The optional arg provides a way of allowing some accuracy (pixels)
961
+ var accuracy = arguments[1] ? arguments[1] : 0;
962
+
963
+ var canvas = ca;
964
+ var context = co;
965
+ var mouseCoords = RG.getMouseXY(e);
966
+ var mouseX = mouseCoords[0];
967
+ var mouseY = mouseCoords[1];
968
+ var r = this.radius;
969
+ var angles = this.angles;
970
+ var ret = [];
971
+
972
+ for (var i=0,len=angles.length; i<len; ++i) {
973
+
974
+ // DRAW THE SEGMENT AGAIN SO IT CAN BE TESTED //////////////////////////
975
+ co.beginPath();
976
+ co.strokeStyle = 'rgba(0,0,0,0)';
977
+ co.arc(angles[i][2], angles[i][3], this.radius, angles[i][0], angles[i][1], false);
978
+
979
+ if (this.type == 'pie' && prop['chart.variant'] == 'donut') {
980
+ co.arc(angles[i][2], angles[i][3], (typeof(prop['chart.variant.donut.width']) == 'number' ? this.radius - prop['chart.variant.donut.width'] : this.radius / 2), angles[i][1], angles[i][0], true);
981
+ } else {
982
+ co.lineTo(angles[i][2], angles[i][3]);
983
+ }
984
+ co.closePath();
985
+
986
+ if (!co.isPointInPath(mouseX, mouseY)) {
987
+ continue;
988
+ }
989
+
990
+ ////////////////////////////////////////////////////////////////////////
991
+
992
+ ret[0] = angles[i][2];
993
+ ret[1] = angles[i][3];
994
+ ret[2] = this.radius;
995
+ ret[3] = angles[i][0] - RG.TWOPI;
996
+ ret[4] = angles[i][1];
997
+ ret[5] = i;
998
+
999
+
1000
+
1001
+ if (ret[3] < 0) ret[3] += RG.TWOPI;
1002
+ if (ret[4] > RG.TWOPI) ret[4] -= RG.TWOPI;
1003
+
1004
+ /**
1005
+ * Add the tooltip to the returned shape
1006
+ */
1007
+ var tooltip = RG.parseTooltipText ? RG.parseTooltipText(prop['chart.tooltips'], ret[5]) : null;
1008
+
1009
+ /**
1010
+ * Now return textual keys as well as numerics
1011
+ */
1012
+ ret['object'] = this;
1013
+ ret['x'] = ret[0];
1014
+ ret['y'] = ret[1];
1015
+ ret['radius'] = ret[2];
1016
+ ret['angle.start'] = ret[3];
1017
+ ret['angle.end'] = ret[4];
1018
+ ret['index'] = ret[5];
1019
+ ret['tooltip'] = tooltip;
1020
+
1021
+ return ret;
1022
+ }
1023
+
1024
+ return null;
1025
+ };
1026
+
1027
+
1028
+
1029
+
1030
+ this.drawBorders =
1031
+ this.DrawBorders = function ()
1032
+ {
1033
+ if (prop['chart.linewidth'] > 0) {
1034
+
1035
+ co.lineWidth = prop['chart.linewidth'];
1036
+ co.strokeStyle = prop['chart.strokestyle'];
1037
+
1038
+ var r = this.radius;
1039
+
1040
+ for (var i=0,len=this.angles.length; i<len; ++i) {
1041
+
1042
+ var segment = this.angles[i];
1043
+
1044
+ co.beginPath();
1045
+ co.arc(segment[2],
1046
+ segment[3],
1047
+ r,
1048
+ (segment[0]),
1049
+ (segment[0] + 0.001),
1050
+ 0);
1051
+ co.arc(segment[2],
1052
+ segment[3],
1053
+ prop['chart.variant'] == 'donut' ? (typeof(prop['chart.variant.donut.width']) == 'number' ? this.radius - prop['chart.variant.donut.width'] : r / 2): r,
1054
+ segment[0],
1055
+ segment[0] + 0.0001,
1056
+ 0);
1057
+ co.closePath();
1058
+ co.stroke();
1059
+ }
1060
+ }
1061
+ };
1062
+
1063
+
1064
+
1065
+
1066
+ /**
1067
+ * Returns the radius of the pie chart
1068
+ *
1069
+ * [06-02-2012] Maintained for compatibility ONLY.
1070
+ */
1071
+ this.getRadius = function ()
1072
+ {
1073
+ this.graph = {width: ca.width - prop['chart.gutter.left'] - prop['chart.gutter.right'], height: ca.height - prop['chart.gutter.top'] - prop['chart.gutter.bottom']}
1074
+
1075
+ if (typeof(prop['chart.radius']) == 'number') {
1076
+ this.radius = prop['chart.radius'];
1077
+ } else {
1078
+ this.radius = Math.min(this.graph.width, this.graph.height) / 2;
1079
+ }
1080
+
1081
+ return this.radius;
1082
+ };
1083
+
1084
+
1085
+
1086
+
1087
+ /**
1088
+ * A programmatic explode function
1089
+ *
1090
+ * @param object obj The chart object
1091
+ * @param number index The zero-indexed number of the segment
1092
+ * @param number size The size (in pixels) of the explosion
1093
+ */
1094
+ this.explodeSegment =
1095
+ this.Explode = function (index, size)
1096
+ {
1097
+ //this.Set('chart.exploded', []);
1098
+ if (!prop['chart.exploded']) {
1099
+ prop['chart.exploded'] = [];
1100
+ }
1101
+
1102
+ // If chart.exploded is a number - convert it to an array
1103
+ if (typeof(prop['chart.exploded']) == 'number') {
1104
+
1105
+ var original_explode = prop['chart.exploded'];
1106
+ var exploded = prop['chart.exploded'];
1107
+
1108
+ prop['chart.exploded'] = [];
1109
+
1110
+ for (var i=0,len=this.data.length; i<len; ++i) {
1111
+ prop['chart.exploded'][i] = exploded;
1112
+ }
1113
+ }
1114
+
1115
+ prop['chart.exploded'][index] = typeof(original_explode) == 'number' ? original_explode : 0;
1116
+
1117
+ for (var o=0; o<size; ++o) {
1118
+
1119
+ setTimeout(
1120
+ function ()
1121
+ {
1122
+ prop['chart.exploded'][index] += 1;
1123
+ RG.Clear(ca);
1124
+ RG.RedrawCanvas(ca);
1125
+ }, o * (RGraph.ISIE && !RGraph.ISIE10 ? 25 : 16.666));
1126
+ }
1127
+ };
1128
+
1129
+
1130
+
1131
+
1132
+ /**
1133
+ * This function highlights a segment
1134
+ *
1135
+ * @param array segment The segment information that is returned by the pie.getSegment(e) function
1136
+ */
1137
+ this.highlight_segment = function (segment)
1138
+ {
1139
+ co.beginPath();
1140
+ co.strokeStyle = prop['chart.highlight.style.2d.stroke'];
1141
+ co.fillStyle = prop['chart.highlight.style.2d.fill'];
1142
+ co.moveTo(segment[0], segment[1]);
1143
+ co.arc(segment[0], segment[1], segment[2], this.angles[segment[5]][0], this.angles[segment[5]][1], 0);
1144
+ co.lineTo(segment[0], segment[1]);
1145
+ co.closePath();
1146
+
1147
+ co.stroke();
1148
+ co.fill();
1149
+ };
1150
+
1151
+
1152
+
1153
+
1154
+ /**
1155
+ * Each object type has its own Highlight() function which highlights the appropriate shape
1156
+ *
1157
+ * @param object shape The shape to highlight
1158
+ */
1159
+ this.highlight =
1160
+ this.Highlight = function (shape)
1161
+ {
1162
+ if (prop['chart.tooltips.highlight']) {
1163
+ /**
1164
+ * 3D style of highlighting
1165
+ */
1166
+ if (prop['chart.highlight.style'] == '3d') {
1167
+
1168
+ co.lineWidth = 1;
1169
+
1170
+ // This is the extent of the 2D effect. Bigger values will give the appearance of a larger "protusion"
1171
+ var extent = 2;
1172
+
1173
+ // Draw a white-out where the segment is
1174
+ co.beginPath();
1175
+ RG.NoShadow(this);
1176
+ co.fillStyle = 'rgba(0,0,0,0)';
1177
+ co.arc(shape['x'], shape['y'], shape['radius'], shape['angle.start'], shape['angle.end'], false);
1178
+ if (prop['chart.variant'] == 'donut') {
1179
+ co.arc(shape['x'], shape['y'], shape['radius'] / 5, shape['angle.end'], shape['angle.start'], true);
1180
+ } else {
1181
+ co.lineTo(shape['x'], shape['y']);
1182
+ }
1183
+ co.closePath();
1184
+ co.fill();
1185
+
1186
+ // Draw the new segment
1187
+ co.beginPath();
1188
+
1189
+ co.shadowColor = '#666';
1190
+ co.shadowBlur = 3;
1191
+ co.shadowOffsetX = 3;
1192
+ co.shadowOffsetY = 3;
1193
+
1194
+ co.fillStyle = prop['chart.colors'][shape['index']];
1195
+ co.strokeStyle = prop['chart.strokestyle'];
1196
+ co.arc(shape['x'] - extent, shape['y'] - extent, shape['radius'], shape['angle.start'], shape['angle.end'], false);
1197
+ if (prop['chart.variant'] == 'donut') {
1198
+ co.arc(shape['x'] - extent, shape['y'] - extent, shape['radius'] / 2, shape['angle.end'], shape['angle.start'], true)
1199
+ } else {
1200
+ co.lineTo(shape['x'] - extent, shape['y'] - extent);
1201
+ }
1202
+ co.closePath();
1203
+
1204
+ co.stroke();
1205
+ co.fill();
1206
+
1207
+ // Turn off the shadow
1208
+ RG.NoShadow(this);
1209
+
1210
+ /**
1211
+ * If a border is defined, redraw that
1212
+ */
1213
+ if (prop['chart.border']) {
1214
+ co.beginPath();
1215
+ co.strokeStyle = prop['chart.border.color'];
1216
+ co.lineWidth = 5;
1217
+ co.arc(shape['x'] - extent, shape['y'] - extent, shape['radius'] - 2, shape['angle.start'], shape['angle.end'], false);
1218
+ co.stroke();
1219
+ }
1220
+
1221
+
1222
+
1223
+
1224
+ // Default 2D style of highlighting
1225
+ } else {
1226
+
1227
+ co.beginPath();
1228
+
1229
+ co.strokeStyle = prop['chart.highlight.style.2d.stroke'];
1230
+ co.fillStyle = prop['chart.highlight.style.2d.fill'];
1231
+
1232
+ if (prop['chart.variant'].indexOf('donut') -1) {
1233
+ co.arc(shape['x'], shape['y'], shape['radius'], shape['angle.start'], shape['angle.end'], false);
1234
+ co.arc(shape['x'], shape['y'], typeof(prop['chart.variant.donut.width']) == 'number' ? this.radius - prop['chart.variant.donut.width'] : shape['radius'] / 2, shape['angle.end'], shape['angle.start'], true);
1235
+ } else {
1236
+ co.arc(shape['x'], shape['y'], shape['radius'] + 1, shape['angle.start'], shape['angle.end'], false);
1237
+ co.lineTo(shape['x'], shape['y']);
1238
+ }
1239
+ co.closePath();
1240
+
1241
+ //co.stroke();
1242
+ co.fill();
1243
+ }
1244
+ }
1245
+ };
1246
+
1247
+
1248
+
1249
+
1250
+ /**
1251
+ * The getObjectByXY() worker method. The Pie chart is able to use the
1252
+ * getShape() method - so it does.
1253
+ */
1254
+ this.getObjectByXY = function (e)
1255
+ {
1256
+ if (this.getShape(e)) {
1257
+ return this;
1258
+ }
1259
+ };
1260
+
1261
+
1262
+
1263
+
1264
+ /**
1265
+ * Draws the centerpin if requested
1266
+ */
1267
+ this.drawCenterpin =
1268
+ this.DrawCenterpin = function ()
1269
+ {
1270
+ if (typeof(prop['chart.centerpin']) == 'number' && prop['chart.centerpin'] > 0) {
1271
+
1272
+ var cx = this.centerx;
1273
+ var cy = this.centery;
1274
+
1275
+ co.beginPath();
1276
+ co.strokeStyle = prop['chart.centerpin.stroke'] ? prop['chart.centerpin.stroke'] : prop['chart.strokestyle'];
1277
+ co.fillStyle = prop['chart.centerpin.fill'] ? prop['chart.centerpin.fill'] : prop['chart.strokestyle'];
1278
+ co.moveTo(cx, cy);
1279
+ co.arc(cx, cy, prop['chart.centerpin'], 0, RG.TWOPI, false);
1280
+ co.stroke();
1281
+ co.fill();
1282
+ }
1283
+ };
1284
+
1285
+
1286
+
1287
+
1288
+ /**
1289
+ * This function positions a tooltip when it is displayed
1290
+ *
1291
+ * @param obj object The chart object
1292
+ * @param int x The X coordinate specified for the tooltip
1293
+ * @param int y The Y coordinate specified for the tooltip
1294
+ * @param objec tooltip The tooltips DIV element
1295
+ */
1296
+ this.positionTooltip = function (obj, x, y, tooltip, idx)
1297
+ {
1298
+ var coordX = obj.angles[idx][2];
1299
+ var coordY = obj.angles[idx][3];
1300
+ var angleStart = obj.angles[idx][0];
1301
+ var angleEnd = obj.angles[idx][1];
1302
+ var angleCenter = ((angleEnd - angleStart) / 2) + angleStart;
1303
+ var canvasXY = RGraph.getCanvasXY(obj.canvas);
1304
+ var gutterLeft = prop['chart.gutter.left'];
1305
+ var gutterTop = prop['chart.gutter.top'];
1306
+ var width = tooltip.offsetWidth;
1307
+ var height = tooltip.offsetHeight;
1308
+ var x = canvasXY[0] + this.angles[idx][2] + (Math.cos(angleCenter) * (prop['chart.variant'] == 'donut' && typeof(prop['chart.variant.donut.width']) == 'number' ? ((this.radius - prop['chart.variant.donut.width']) + (prop['chart.variant.donut.width'] / 2)) : (this.radius * 0.75)));
1309
+ var y = canvasXY[1] + this.angles[idx][3] + (Math.sin(angleCenter) * (prop['chart.variant'] == 'donut' && typeof(prop['chart.variant.donut.width']) == 'number' ? ((this.radius - prop['chart.variant.donut.width']) + (prop['chart.variant.donut.width'] / 2)) : (this.radius * 0.75)));
1310
+
1311
+
1312
+ // By default any overflow is hidden
1313
+ tooltip.style.overflow = '';
1314
+
1315
+ // The arrow
1316
+ var img = new Image();
1317
+ img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC';
1318
+ img.style.position = 'absolute';
1319
+ img.id = '__rgraph_tooltip_pointer__';
1320
+ img.style.top = (tooltip.offsetHeight - 2) + 'px';
1321
+ tooltip.appendChild(img);
1322
+
1323
+ // Reposition the tooltip if at the edges:
1324
+
1325
+ // LEFT edge
1326
+ if ((x - (width / 2)) < 10) {
1327
+ tooltip.style.left = (x - (width * 0.1)) + 'px';
1328
+ tooltip.style.top = (y - height - 4) + 'px';
1329
+ img.style.left = ((width * 0.1) - 8.5) + 'px';
1330
+
1331
+ // RIGHT edge
1332
+ } else if ((x + (width / 2)) > (doc.body.offsetWidth - 10) ) {
1333
+ tooltip.style.left = (x - (width * 0.9)) + 'px';
1334
+ tooltip.style.top = (y - height - 4) + 'px';
1335
+ img.style.left = ((width * 0.9) - 8.5) + 'px';
1336
+
1337
+ // Default positioning - CENTERED
1338
+ } else {
1339
+ tooltip.style.left = (x - (width / 2)) + 'px';
1340
+ tooltip.style.top = (y - height - 4) + 'px';
1341
+ img.style.left = ((width * 0.5) - 8.5) + 'px';
1342
+ }
1343
+ };
1344
+
1345
+
1346
+
1347
+
1348
+ /**
1349
+ * This draws Ingraph labels
1350
+ */
1351
+ this.drawInGraphLabels =
1352
+ this.DrawInGraphLabels = function ()
1353
+ {
1354
+ var context = co;
1355
+ var cx = this.centerx;
1356
+ var cy = this.centery;
1357
+ var radius = prop['chart.labels.ingraph.radius'];
1358
+
1359
+ //
1360
+ // Is the radius less than 2? If so then it's a factor and not n exact point
1361
+ //
1362
+ if (radius <= 2 && radius > 0) {
1363
+ radiusFactor = radius;
1364
+ } else {
1365
+ radiusFactor = 0.5;
1366
+ }
1367
+
1368
+ if (prop['chart.variant'] == 'donut') {
1369
+ var r = this.radius * (0.5 + (radiusFactor * 0.5));
1370
+
1371
+ if (typeof(prop['chart.variant.donut.width']) == 'number') {
1372
+ var r = (this.radius - prop['chart.variant.donut.width']) + (prop['chart.variant.donut.width'] / 2);
1373
+ }
1374
+ } else {
1375
+ var r = this.radius * radiusFactor;
1376
+ }
1377
+
1378
+ if (radius > 2) {
1379
+ r = radius;
1380
+ }
1381
+
1382
+ for (var i=0,len=this.angles.length; i<len; ++i) {
1383
+
1384
+ // This handles any explosion that the segment may have
1385
+ if (typeof(prop['chart.exploded']) == 'object' && typeof(prop['chart.exploded'][i]) == 'number') {
1386
+ var explosion = prop['chart.exploded'][i];
1387
+ } else if (typeof(prop['chart.exploded']) == 'number') {
1388
+ var explosion = parseInt(prop['chart.exploded']);
1389
+ } else {
1390
+ var explosion = 0;
1391
+ }
1392
+
1393
+ var angleStart = this.angles[i][0];
1394
+ var angleEnd = this.angles[i][1];
1395
+ var angleCenter = ((angleEnd - angleStart) / 2) + angleStart;
1396
+ var coords = RG.getRadiusEndPoint(
1397
+ this.centerx,
1398
+ this.centery,
1399
+ angleCenter,
1400
+ r + (explosion ? explosion : 0)
1401
+ );
1402
+
1403
+ var x = coords[0];
1404
+ var y = coords[1];
1405
+
1406
+ var text = prop['chart.labels.ingraph.specific'] && typeof(prop['chart.labels.ingraph.specific'][i]) == 'string' ? prop['chart.labels.ingraph.specific'][i] : RG.number_format(this, this.data[i], prop['chart.labels.ingraph.units.pre'] , prop['chart.labels.ingraph.units.post']);
1407
+
1408
+ if (text) {
1409
+ co.beginPath();
1410
+
1411
+ var font = typeof prop['chart.labels.ingraph.font'] === 'string' ? prop['chart.labels.ingraph.font'] : prop['chart.text.font'];
1412
+ var size = typeof prop['chart.labels.ingraph.size'] === 'number' ? prop['chart.labels.ingraph.size'] : prop['chart.text.size'] + 2;
1413
+
1414
+ //
1415
+ // Set the colors
1416
+ //
1417
+ co.fillStyle = prop['chart.labels.ingraph.color'] ? prop['chart.labels.ingraph.color'] : 'black';
1418
+
1419
+ RG.Text2(this, {
1420
+ 'font':font,
1421
+ 'size':size,
1422
+ 'x':x,
1423
+ 'y':y,
1424
+ 'text':text,
1425
+ 'valign':'center',
1426
+ 'halign':'center',
1427
+ 'bounding': prop['chart.labels.ingraph.bounding'],
1428
+ 'bounding.fill': prop['chart.labels.ingraph.bounding.fill'],
1429
+ 'tag':'labels.ingraph'
1430
+ });
1431
+ co.stroke();
1432
+ }
1433
+ }
1434
+ };
1435
+
1436
+
1437
+
1438
+
1439
+ //
1440
+ // Draws the center label if required
1441
+ //
1442
+ this.drawCenterLabel = function (label)
1443
+ {
1444
+ var font = prop['chart.labels.center.font'],
1445
+ size = prop['chart.labels.center.size'],
1446
+ color = prop['chart.labels.center.color'],
1447
+ unitsPre = prop['chart.labels.center.units.pre'],
1448
+ unitsPost = prop['chart.labels.center.units.post'],
1449
+ bold = prop['chart.labels.center.bold'],
1450
+ italic = prop['chart.labels.center.italic'];
1451
+
1452
+
1453
+ RG.text2(this, {
1454
+ color: color,
1455
+ bold: bold,
1456
+ italic: italic,
1457
+ font: font,
1458
+ size: size,
1459
+ x: this.centerx,
1460
+ y: this.centery,
1461
+ halign: 'center',
1462
+ valign: 'center',
1463
+ text: RG.numberFormat(this, label,unitsPre, unitsPost)
1464
+ });
1465
+ }
1466
+
1467
+
1468
+
1469
+
1470
+ /**
1471
+ * This returns the angle for a value based around the maximum number
1472
+ *
1473
+ * @param number value The value to get the angle for
1474
+ */
1475
+ this.getAngle = function (value)
1476
+ {
1477
+ if (value > this.total) {
1478
+ return null;
1479
+ }
1480
+
1481
+ var angle = (value / this.total) * RG.TWOPI;
1482
+
1483
+ // Handle the origin (it can br -HALFPI or 0)
1484
+ angle += prop['chart.origin'];
1485
+
1486
+ return angle;
1487
+ };
1488
+
1489
+
1490
+
1491
+
1492
+ /**
1493
+ * This allows for easy specification of gradients
1494
+ */
1495
+ this.parseColors = function ()
1496
+ {
1497
+ // Save the original colors so that they can be restored when the canvas is reset
1498
+ if (this.original_colors.length === 0) {
1499
+ this.original_colors['chart.colors'] = RG.arrayClone(prop['chart.colors']);
1500
+ this.original_colors['chart.key.colors'] = RG.arrayClone(prop['chart.key.colors']);
1501
+ this.original_colors['chart.strokestyle'] = RG.arrayClone(prop['chart.strokestyle']);
1502
+ this.original_colors['chart.highlight.stroke'] = RG.arrayClone(prop['chart.highlight.stroke']);
1503
+ this.original_colors['chart.highlight.style.2d.fill'] = RG.arrayClone(prop['chart.highlight.style.2d.fill']);
1504
+ this.original_colors['chart.highlight.style.stroke'] = RG.arrayClone(prop['chart.highlight.style.2d.stroke']);
1505
+ this.original_colors['chart.ingraph.bounding.fill'] = RG.arrayClone(prop['chart.ingraph.bounding.fill']);
1506
+ this.original_colors['chart.ingraph.color'] = RG.arrayClone(prop['chart.ingraph.color']);
1507
+ }
1508
+
1509
+ for (var i=0; i<prop['chart.colors'].length; ++i) {
1510
+ prop['chart.colors'][i] = this.parseSingleColorForGradient(prop['chart.colors'][i]);
1511
+ }
1512
+
1513
+ var keyColors = prop['chart.key.colors'];
1514
+ if (keyColors) {
1515
+ for (var i=0; i<keyColors.length; ++i) {
1516
+ keyColors[i] = this.parseSingleColorForGradient(keyColors[i]);
1517
+ }
1518
+ }
1519
+
1520
+ prop['chart.strokestyle'] = this.parseSingleColorForGradient(prop['chart.strokestyle']);
1521
+ prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
1522
+ prop['chart.highlight.style.2d.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.style.2d.fill']);
1523
+ prop['chart.highlight.style.2d.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.style.2d.stroke']);
1524
+ prop['chart.labels.ingraph.bounding.fill'] = this.parseSingleColorForGradient(prop['chart.labels.ingraph.bounding.fill']);
1525
+ prop['chart.labels.ingraph.color'] = this.parseSingleColorForGradient(prop['chart.labels.ingraph.color']);
1526
+ };
1527
+
1528
+
1529
+
1530
+
1531
+ /**
1532
+ * Use this function to reset the object to the post-constructor state. Eg reset colors if
1533
+ * need be etc
1534
+ */
1535
+ this.reset = function ()
1536
+ {
1537
+ };
1538
+
1539
+
1540
+
1541
+
1542
+ /**
1543
+ * This parses a single color value
1544
+ */
1545
+ this.parseSingleColorForGradient = function (color)
1546
+ {
1547
+
1548
+ if (!color || typeof(color) != 'string') {
1549
+ return color;
1550
+ }
1551
+
1552
+ if (color.match(/^gradient\((.*)\)$/i)) {
1553
+
1554
+ var parts = RegExp.$1.split(':');
1555
+
1556
+ // If the chart is a donut - the first width should half the total radius
1557
+ if (prop['chart.variant'] == 'donut') {
1558
+ var radius_start = typeof(prop['chart.variant.donut.width']) == 'number' ? this.radius - prop['chart.variant.donut.width'] : this.radius / 2;
1559
+ } else {
1560
+ var radius_start = 0;
1561
+ }
1562
+
1563
+ // Create the gradient
1564
+ var grad = co.createRadialGradient(this.centerx, this.centery, radius_start, this.centerx, this.centery, Math.min(ca.width - prop['chart.gutter.left'] - prop['chart.gutter.right'], ca.height - prop['chart.gutter.top'] - prop['chart.gutter.bottom']) / 2);
1565
+
1566
+
1567
+ var diff = 1 / (parts.length - 1);
1568
+
1569
+ grad.addColorStop(0, RG.trim(parts[0]));
1570
+
1571
+ for (var j=1; j<parts.length; ++j) {
1572
+ grad.addColorStop(j * diff, RG.trim(parts[j]));
1573
+ }
1574
+ }
1575
+
1576
+ return grad ? grad : color;
1577
+ };
1578
+
1579
+
1580
+
1581
+
1582
+ /**
1583
+ * This function handles highlighting an entire data-series for the interactive
1584
+ * key
1585
+ *
1586
+ * @param int index The index of the data series to be highlighted
1587
+ */
1588
+ this.interactiveKeyHighlight = function (index)
1589
+ {
1590
+ if (this.angles && this.angles[index]) {
1591
+
1592
+ var segment = this.angles[index];
1593
+ var x = segment[2];
1594
+ var y = segment[3];
1595
+ var start = segment[0];
1596
+ var end = segment[1];
1597
+
1598
+ co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
1599
+ co.fillStyle = prop['chart.key.interactive.highlight.chart.fill'];
1600
+ co.lineWidth = 2;
1601
+ co.lineJoin = 'bevel';
1602
+
1603
+ co.beginPath();
1604
+ co.moveTo(x, y);
1605
+ co.arc(x, y, this.radius, start, end, false);
1606
+ co.closePath();
1607
+ co.fill();
1608
+ co.stroke();
1609
+ }
1610
+ };
1611
+
1612
+
1613
+
1614
+
1615
+ /**
1616
+ * Using a function to add events makes it easier to facilitate method chaining
1617
+ *
1618
+ * @param string type The type of even to add
1619
+ * @param function func
1620
+ */
1621
+ this.on = function (type, func)
1622
+ {
1623
+ if (type.substr(0,2) !== 'on') {
1624
+ type = 'on' + type;
1625
+ }
1626
+
1627
+ this[type] = func;
1628
+
1629
+ return this;
1630
+ };
1631
+
1632
+
1633
+
1634
+
1635
+ /**
1636
+ * This function runs once only
1637
+ * (put at the end of the file (before any effects))
1638
+ */
1639
+ this.firstDrawFunc = function ()
1640
+ {
1641
+ };
1642
+
1643
+
1644
+
1645
+
1646
+ //
1647
+ // Draw a 3D Pie/Donut chart
1648
+ //
1649
+ this.draw3d = function ()
1650
+ {
1651
+ var scaleX = 1.5,
1652
+ depth = prop['chart.variant.threed.depth'],
1653
+ prop_shadow = prop['chart.shadow'],
1654
+ prop_labels = prop['chart.labels'],
1655
+ prop_labelsSticks = prop['chart.labels.sticks']
1656
+
1657
+ this.set({
1658
+ labels: [],
1659
+ labelsSticks: false,
1660
+ strokestyle: 'rgba(0,0,0,0)'
1661
+ });
1662
+
1663
+ //
1664
+ // Change the variant so that the draw function doesn't keep
1665
+ // coming in here
1666
+ //
1667
+ this.set({
1668
+ variant: this.get('variant').replace(/3d/, '')
1669
+ });
1670
+
1671
+ this.context.setTransform(scaleX, 0, 0, 1, (ca.width * (scaleX) - ca.width) * -0.5, 0);
1672
+
1673
+ for (var i=depth; i>0; i-=1) {
1674
+
1675
+ this.set({
1676
+ centeryAdjust: i
1677
+ });
1678
+
1679
+ if (i === parseInt(depth / 2) ) {
1680
+ this.set({
1681
+ labels: prop_labels,
1682
+ labelsSticks: prop_labelsSticks
1683
+ });
1684
+ }
1685
+
1686
+ if (i === 0) {
1687
+ this.set({
1688
+ shadow: prop_shadow
1689
+ });
1690
+ }
1691
+
1692
+ this.draw();
1693
+
1694
+ // Turn off the shadow after the bottom pie/donut has
1695
+ // been drawn
1696
+ this.set('shadow', false);
1697
+
1698
+ //
1699
+ // If on the middle pie/donut turn the labels and sticks off
1700
+ //
1701
+ if (i <= parseInt(depth / 2) ) {
1702
+ this.set({
1703
+ labels: [],
1704
+ labelsSticks: false
1705
+ });
1706
+ }
1707
+
1708
+ //
1709
+ // Make what we're drawng darker by going over
1710
+ // it in a semi-transparent dark color
1711
+ //
1712
+ if (i > 1) {
1713
+ if (prop['chart.variant'].indexOf('donut') !== -1) {
1714
+
1715
+ for (var j=0; j<this.angles.length; ++j) {
1716
+ pa(this.context,[
1717
+ 'b',
1718
+ 'a', this.angles[j][2], this.angles[j][3], this.radius + 1, this.angles[j][0], this.angles[j][1] * prop['chart.effect.roundrobin.multiplier'], false,
1719
+ 'a', this.angles[j][2], this.angles[j][3], this.radius / 2, this.angles[j][1] * prop['chart.effect.roundrobin.multiplier'], this.angles[j][0], true,
1720
+ 'f', 'rgba(0,0,0,0.15)'
1721
+ ]);
1722
+ }
1723
+
1724
+ // Draw the pie chart darkened segments
1725
+ } else {
1726
+
1727
+ for (var j=0; j<this.angles.length; ++j) {
1728
+
1729
+ pa(this.context,[
1730
+ 'b',
1731
+ 'm', this.angles[j][2], this.angles[j][3],
1732
+ 'a', this.angles[j][2],
1733
+ this.angles[j][3],
1734
+ this.radius + 1,
1735
+ this.angles[j][0],
1736
+ this.angles[j][1] * prop['chart.effect.roundrobin.multiplier'],
1737
+ false,
1738
+ 'c',
1739
+ 'f', 'rgba(0,0,0,0.15)'
1740
+ ]);
1741
+ }
1742
+ }
1743
+ }
1744
+ }
1745
+
1746
+ //
1747
+ // Reset the variant by adding the 3d back on
1748
+ //
1749
+ this.set({
1750
+ variant: this.get('variant') + '3d',
1751
+ shadow: prop_shadow,
1752
+ labels: prop_labels,
1753
+ labelsSticks: prop_labelsSticks
1754
+ });
1755
+
1756
+ // Necessary to allow method chaining
1757
+ return this;
1758
+ };
1759
+
1760
+
1761
+
1762
+
1763
+ /**
1764
+ * Pie chart explode
1765
+ *
1766
+ * Explodes the Pie chart - gradually incrementing the size of the chart.explode property
1767
+ *
1768
+ * @param object Options for the effect
1769
+ * @param function An optional callback function to call when the animation completes
1770
+ */
1771
+ this.explode = function ()
1772
+ {
1773
+ var obj = this;
1774
+ var opt = arguments[0] ? arguments[0] : {};
1775
+ var callback = arguments[1] ? arguments[1] : function () {};
1776
+ var frames = opt.frames ? opt.frames : 30;
1777
+ var frame = 0;
1778
+ var maxExplode = Number(typeof opt.radius === 'number' ? opt.radius : ma.max(ca.width, ca.height));
1779
+ var currentExplode = Number(obj.get('exploded')) || 0;
1780
+ var step = (maxExplode - currentExplode) / frames;
1781
+
1782
+ // chart.exploded
1783
+ var iterator = function ()
1784
+ {
1785
+ obj.set('exploded', currentExplode + (step * frame) );
1786
+
1787
+ RGraph.clear(obj.canvas);
1788
+ RGraph.redrawCanvas(obj.canvas);
1789
+
1790
+ if (frame++ < frames) {
1791
+ RGraph.Effects.updateCanvas(iterator);
1792
+ } else {
1793
+ callback(obj);
1794
+ }
1795
+ }
1796
+
1797
+ iterator();
1798
+
1799
+ return this;
1800
+ };
1801
+
1802
+
1803
+
1804
+
1805
+ /**
1806
+ * Pie chart grow
1807
+ *
1808
+ * Gradually increases the pie chart radius
1809
+ *
1810
+ * @param object OPTIONAL An object of options
1811
+ * @param function OPTIONAL A callback function
1812
+ */
1813
+ this.grow = function ()
1814
+ {
1815
+ var obj = this;
1816
+ var canvas = obj.canvas;
1817
+ var opt = arguments[0] ? arguments[0] : {};
1818
+ var frames = opt.frames || 30;
1819
+ var frame = 0;
1820
+ var callback = arguments[1] ? arguments[1] : function () {};
1821
+ var radius = obj.getRadius();
1822
+
1823
+
1824
+ prop['chart.radius'] = 0;
1825
+
1826
+ var iterator = function ()
1827
+ {
1828
+ obj.set('chart.radius', (frame / frames) * radius);
1829
+
1830
+ RG.redrawCanvas(ca);
1831
+
1832
+ if (frame++ < frames) {
1833
+ RG.Effects.updateCanvas(iterator);
1834
+
1835
+ } else {
1836
+
1837
+ RG.redrawCanvas(obj.canvas);
1838
+
1839
+
1840
+ callback(obj);
1841
+ }
1842
+ };
1843
+
1844
+ iterator();
1845
+
1846
+ return this;
1847
+ };
1848
+
1849
+
1850
+
1851
+
1852
+
1853
+ /**
1854
+ * RoundRobin
1855
+ *
1856
+ * This effect does two things:
1857
+ * 1. Gradually increases the size of each segment
1858
+ * 2. Gradually increases the size of the radius from 0
1859
+ *
1860
+ * @param object OPTIONAL Options for the effect
1861
+ * @param function OPTIONAL A callback function
1862
+ */
1863
+ this.roundrobin =
1864
+ this.roundRobin = function ()
1865
+ {
1866
+ var obj = this;
1867
+ var opt = arguments[0] || {};
1868
+ var callback = arguments[1] || function () {};
1869
+ var frame = 0;
1870
+ var frames = opt.frames || 30;
1871
+ var radius = obj.getRadius();
1872
+
1873
+ obj.Set('chart.events', false);
1874
+
1875
+ var iterator = function ()
1876
+ {
1877
+ obj.set(
1878
+ 'effect.roundrobin.multiplier',
1879
+ RG.Effects.getEasingMultiplier(frames, frame)
1880
+ );
1881
+
1882
+ RGraph.redrawCanvas(ca);
1883
+
1884
+ if (frame++ < frames) {
1885
+ RGraph.Effects.updateCanvas(iterator);
1886
+
1887
+ } else {
1888
+
1889
+ // Re-enable the events and redraw the chart.
1890
+ obj.set('events', true);
1891
+ RGraph.redrawCanvas(obj.canvas);
1892
+
1893
+ callback(obj);
1894
+ }
1895
+ };
1896
+
1897
+ iterator();
1898
+
1899
+ return this;
1900
+ };
1901
+
1902
+
1903
+
1904
+
1905
+ RG.att(ca);
1906
+
1907
+
1908
+
1909
+
1910
+
1911
+
1912
+
1913
+
1914
+
1915
+ /**
1916
+ * Pie chart implode
1917
+ *
1918
+ * Implodes the Pie chart - gradually decreasing the size of the chart.explode property. It starts at the largest of
1919
+ * the canvas width./height
1920
+ *
1921
+ * @param object Optional options for the effect. You can pass in frames here - such as:
1922
+ * myPie.implode({frames: 60}; function () {alert('Done!');})
1923
+ * @param function A callback function which is called when the effect is finished
1924
+ */
1925
+ this.implode = function ()
1926
+ {
1927
+ var obj = this,
1928
+ opt = arguments[0] || {},
1929
+ callback = arguments[1] || function (){},
1930
+ frames = opt.frames || 30,
1931
+ frame = 0,
1932
+ explodedMax = ma.max(ca.width, ca.height),
1933
+ exploded = explodedMax;
1934
+
1935
+
1936
+
1937
+ function iterator ()
1938
+ {
1939
+ exploded = explodedMax - ((frame / frames) * explodedMax);
1940
+
1941
+ // Set the new value
1942
+ obj.Set('exploded', exploded);
1943
+
1944
+ RG.clear(ca);
1945
+ RG.redrawCanvas(ca);
1946
+
1947
+ if (frame++ < frames) {
1948
+ RG.Effects.updateCanvas(iterator);
1949
+ } else {
1950
+ RG.clear(obj.canvas);
1951
+ RG.redrawCanvas(obj.canvas);
1952
+ callback(obj);
1953
+ }
1954
+ }
1955
+
1956
+ iterator();
1957
+
1958
+ return this;
1959
+ };
1960
+
1961
+
1962
+
1963
+
1964
+ /**
1965
+ * Now need to register all chart types. MUST be after the setters/getters are defined
1966
+ */
1967
+ RG.register(this);
1968
+
1969
+
1970
+
1971
+
1972
+ /**
1973
+ * This is the 'end' of the constructor so if the first argument
1974
+ * contains configuration data - handle that.
1975
+ */
1976
+ if (parseConfObjectForOptions) {
1977
+ RG.parseObjectStyleConfig(this, conf.options);
1978
+ }
1979
+ };