rgraph-rails 4.62 → 4.64

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 (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);}};