rgraph-rails 4.62 → 4.64

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