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,1848 +1,111 @@
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
-
15
- /**
16
- * The traditional radar chart constructor
17
- *
18
- * @param string id The ID of the canvas
19
- * @param array data An array of data to represent
20
- */
21
- RGraph.Radar = function (conf)
22
- {
23
- /**
24
- * Allow for object config style
25
- */
26
- if ( typeof conf === 'object'
27
- && typeof conf.data === 'object'
28
- && typeof conf.id === 'string') {
29
-
30
- var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
31
-
32
- // Turn conf.data into a multi-d array if it's not already
33
- if (typeof conf.data[0] === 'number' || typeof conf.data[0] === 'string') {
34
- conf.data = [conf.data];
35
- }
36
-
37
- } else {
38
-
39
- var conf = {id: conf, data: []};
40
-
41
- // Arguments style: var foo = new RGraph.Radar('cvs', [1,2,3], [1,2,3], [1,2,3]);
42
- if (typeof arguments[1] === 'object' && typeof arguments[1][0] === 'number') {
43
- for (var i=1; i<arguments.length; ++i) {
44
- conf.data.push(RGraph.arrayClone(arguments[i]));
45
- }
46
-
47
- // Arguments style: var foo = new RGraph.Radar('cvs', [[1,2,3], [1,2,3], [1,2,3]]);
48
- } else if ( typeof arguments[1] === 'object'
49
- && typeof arguments[1][0] === 'object'
50
- && typeof arguments[1][0][0] === 'number') {
51
-
52
- conf.data = RGraph.arrayClone(arguments[1]);
53
- }
54
- }
55
-
56
-
57
-
58
-
59
- this.id = conf.id;
60
- this.canvas = document.getElementById(conf.id);
61
- this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null;
62
- this.canvas.__object__ = this;
63
- this.type = 'radar';
64
- this.isRGraph = true;
65
- this.data = [];
66
- this.max = 0;
67
- this.uid = RGraph.CreateUID();
68
- this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
69
- this.colorsParsed = false;
70
- this.coords = [];
71
- this.coordsText = [];
72
- this.original_data = [];
73
- this.original_colors = [];
74
- this.firstDraw = true; // After the first draw this will be false
75
-
76
- /**
77
- * Add the data to the .original_data array and work out the max value
78
- *
79
- * 2/5/14 Now also use this loop to ensure that the data pieces
80
- * are numbers
81
- */
82
- for (var i=0,len=conf.data.length; i<len; ++i) {
83
-
84
- // Convert strings to numbers
85
- for (var j=0; j<conf.data[i].length; ++j) {
86
- if (typeof conf.data[i][j] === 'string') {
87
- conf.data[i][j] = parseFloat(conf.data[i][j]);
88
- }
89
- }
90
-
91
- this.original_data.push(RGraph.arrayClone(conf.data[i]));
92
- this.data.push(RGraph.arrayClone(conf.data[i]));
93
- this.max = Math.max(this.max, RGraph.arrayMax(conf.data[i]));
94
- }
95
-
96
-
97
- this.properties =
98
- {
99
- 'chart.strokestyle': '#aaa',
100
- 'chart.gutter.left': 25,
101
- 'chart.gutter.right': 25,
102
- 'chart.gutter.top': 25,
103
- 'chart.gutter.bottom': 25,
104
- 'chart.linewidth': 1,
105
- 'chart.colors': ['rgba(255,255,0,0.25)','rgba(0,255,255,0.25)','rgba(255,0,0,0.5)', 'red', 'green', 'blue', 'pink', 'aqua','brown','orange','grey'],
106
- 'chart.colors.alpha': null,
107
- 'chart.circle': 0,
108
- 'chart.circle.fill': 'red',
109
- 'chart.circle.stroke': 'black',
110
-
111
- 'chart.labels': [],
112
- 'chart.labels.color': null,
113
- 'chart.labels.offset': 10,
114
- 'chart.labels.axes': '',
115
- 'chart.labels.background.fill': 'white',
116
- 'chart.labels.boxed': false,
117
- 'chart.labels.axes.bold': [],
118
- 'chart.labels.axes.boxed': null, // This defaults to true - but that's set in the Draw() method
119
- 'chart.labels.axes.boxed.zero': true,
120
- 'chart.labels.axes.boxed.background': 'rgba(255,255,255,0.9)',
121
- 'chart.labels.specific': [],
122
-
123
- 'chart.labels.count': 5,
124
- 'chart.background.circles': true,
125
- 'chart.background.circles.count': null,
126
- 'chart.background.circles.color': '#ddd',
127
- 'chart.background.circles.poly': true,
128
- 'chart.background.circles.spokes': 24,
129
- 'chart.text.size': 12,
130
- 'chart.text.size.scale': null,
131
- 'chart.text.font': 'Segoe UI, Arial, Verdana, sans-serif',
132
- 'chart.text.color': 'black',
133
- 'chart.text.accessible': true,
134
- 'chart.text.accessible.overflow': 'visible',
135
- 'chart.text.accessible.pointerevents': true,
136
- 'chart.title': '',
137
- 'chart.title.background': null,
138
- 'chart.title.hpos': null,
139
- 'chart.title.vpos': null,
140
- 'chart.title.color': 'black',
141
- 'chart.title.bold': true,
142
- 'chart.title.font': null,
143
- 'chart.title.x': null,
144
- 'chart.title.y': null,
145
- 'chart.title.halign': null,
146
- 'chart.title.valign': null,
147
- 'chart.linewidth': 1,
148
- 'chart.key': null,
149
- 'chart.key.background': 'white',
150
- 'chart.key.shadow': false,
151
- 'chart.key.shadow.color': '#666',
152
- 'chart.key.shadow.blur': 3,
153
- 'chart.key.shadow.offsetx': 2,
154
- 'chart.key.shadow.offsety': 2,
155
- 'chart.key.position': 'graph',
156
- 'chart.key.halign': 'right',
157
- 'chart.key.position.gutter.boxed': false,
158
- 'chart.key.position.x': null,
159
- 'chart.key.position.y': null,
160
- 'chart.key.color.shape': 'square',
161
- 'chart.key.rounded': true,
162
- 'chart.key.linewidth': 1,
163
- 'chart.key.colors': null,
164
- 'chart.key.interactive': false,
165
- 'chart.key.interactive.highlight.chart.stroke': 'rgba(255,0,0,0.3)',
166
- 'chart.key.interactive.highlight.label': 'rgba(255,0,0,0.2)',
167
- 'chart.key.text.color': 'black',
168
- 'chart.contextmenu': null,
169
- 'chart.annotatable': false,
170
- 'chart.annotate.color': 'black',
171
- 'chart.zoom.factor': 1.5,
172
- 'chart.zoom.fade.in': true,
173
- 'chart.zoom.fade.out': true,
174
- 'chart.zoom.hdir': 'right',
175
- 'chart.zoom.vdir': 'down',
176
- 'chart.zoom.frames': 25,
177
- 'chart.zoom.delay': 16.666,
178
- 'chart.zoom.shadow': true,
179
- 'chart.zoom.background': true,
180
- 'chart.zoom.action': 'zoom',
181
- 'chart.tooltips.effect': 'fade',
182
- 'chart.tooltips.event': 'onmousemove',
183
- 'chart.tooltips.css.class': 'RGraph_tooltip',
184
- 'chart.tooltips.highlight': true,
185
- 'chart.highlight.stroke': 'gray',
186
- 'chart.highlight.fill': 'rgba(255,255,255,0.7)',
187
- 'chart.highlight.point.radius': 2,
188
- 'chart.resizable': false,
189
- 'chart.resize.handle.adjust': [0,0],
190
- 'chart.resize.handle.background': null,
191
- 'chart.ymax': null,
192
- 'chart.accumulative': false,
193
- 'chart.radius': null,
194
- 'chart.events.click': null,
195
- 'chart.events.mousemove': null,
196
- 'chart.scale.decimals': 0,
197
- 'chart.scale.point': '.',
198
- 'chart.scale.thousand': ',',
199
- 'chart.units.pre': '',
200
- 'chart.units.post': '',
201
- 'chart.tooltips': null,
202
- 'chart.tooltips.event': 'onmousemove',
203
- 'chart.centerx': null,
204
- 'chart.centery': null,
205
- 'chart.radius': null,
206
- 'chart.numxticks': 5,
207
- 'chart.numyticks': 5,
208
- 'chart.axes.color': 'rgba(0,0,0,0)',
209
- 'chart.highlights': false,
210
- 'chart.highlights.stroke': '#ddd',
211
- 'chart.highlights.fill': null,
212
- 'chart.highlights.radius': 3,
213
- 'chart.fill.click': null,
214
- 'chart.fill.mousemove': null,
215
- 'chart.fill.tooltips': null,
216
- 'chart.fill.highlight.fill': 'rgba(255,255,255,0.7)',
217
- 'chart.fill.highlight.stroke': 'rgba(0,0,0,0)',
218
- 'chart.fill.mousemove.redraw': false,
219
- 'chart.animation.trace.clip': 1,
220
- 'chart.clearto': 'rgba(0,0,0,0)'
221
- }
222
-
223
-
224
-
225
- // Must have at least 3 points
226
- for (var dataset=0; dataset<this.data.length; ++dataset) {
227
- if (this.data[dataset].length < 3) {
228
- alert('[RADAR] You must specify at least 3 data points');
229
- return;
230
- }
231
- }
232
-
233
-
234
- /**
235
- * Linearize the data and then create the $ objects
236
- */
237
- var idx = 0;
238
- for (var dataset=0; dataset<this.data.length; ++dataset) {
239
- for (var i=0,len=this.data[dataset].length; i<len; ++i) {
240
- this['$' + (idx++)] = {};
241
- }
242
- }
243
-
244
-
245
-
246
- /**
247
- * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
248
- * done already
249
- */
250
- if (!this.canvas.__rgraph_aa_translated__) {
251
- this.context.translate(0.5,0.5);
252
-
253
- this.canvas.__rgraph_aa_translated__ = true;
254
- }
255
-
256
-
257
-
258
-
259
- // Short variable names
260
- var RG = RGraph,
261
- ca = this.canvas,
262
- co = ca.getContext('2d'),
263
- prop = this.properties,
264
- pa2 = RG.path2,
265
- win = window,
266
- doc = document,
267
- ma = Math
268
-
269
-
270
-
271
- /**
272
- * "Decorate" the object with the generic effects if the effects library has been included
273
- */
274
- if (RG.Effects && typeof RG.Effects.decorate === 'function') {
275
- RG.Effects.decorate(this);
276
- }
277
-
278
-
279
-
280
-
281
- /**
282
- * A simple setter
283
- *
284
- * @param string name The name of the property to set
285
- * @param string value The value of the property
286
- */
287
- this.set =
288
- this.Set = function (name, value)
289
- {
290
- var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
291
-
292
- /**
293
- * the number of arguments is only one and it's an
294
- * object - parse it for configuration data and return.
295
- */
296
- if (arguments.length === 1 && typeof name === 'object') {
297
- RG.parseObjectStyleConfig(this, name);
298
- return this;
299
- }
300
-
301
-
302
-
303
-
304
-
305
- /**
306
- * This should be done first - prepend the propertyy name with "chart." if necessary
307
- */
308
- if (name.substr(0,6) != 'chart.') {
309
- name = 'chart.' + name;
310
- }
311
-
312
-
313
-
314
-
315
- // Convert uppercase letters to dot+lower case letter
316
- while(name.match(/([A-Z])/)) {
317
- name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
318
- }
319
-
320
-
321
-
322
-
323
-
324
-
325
- if (name == 'chart.text.diameter') {
326
- name = 'chart.text.size';
327
- }
328
-
329
- /**
330
- * If the name is chart.color, set chart.colors too
331
- */
332
- if (name == 'chart.color') {
333
- this.properties['chart.colors'] = [value];
334
- }
335
-
336
-
337
-
338
-
339
-
340
-
341
- prop[name] = value;
342
-
343
- return this;
344
- };
345
-
346
-
347
-
348
-
349
-
350
- /**
351
- * A simple getter
352
- *
353
- * @param string name The name of the property to get
354
- */
355
- this.get =
356
- this.Get = function (name)
357
- {
358
- /**
359
- * This should be done first - prepend the property name with "chart." if necessary
360
- */
361
- if (name.substr(0,6) != 'chart.') {
362
- name = 'chart.' + name;
363
- }
364
-
365
- // Convert uppercase letters to dot+lower case letter
366
- while(name.match(/([A-Z])/)) {
367
- name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
368
- }
369
-
370
- if (name == 'chart.text.diameter') {
371
- name = 'chart.text.size';
372
- }
373
-
374
- return prop[name];
375
- };
376
-
377
-
378
-
379
-
380
- /**
381
- * The draw method which does all the brunt of the work
382
- */
383
- this.draw =
384
- this.Draw = function ()
385
- {
386
- /**
387
- * Fire the onbeforedraw event
388
- */
389
- RG.FireCustomEvent(this, 'onbeforedraw');
390
-
391
- // NB: Colors are parsed further down
392
-
393
- // Reset the coords array to stop it growing
394
- this.coords = [];
395
- this.coords2 = [];
396
- this.coordsText = [];
397
-
398
- /**
399
- * Reset the data to the original_data
400
- */
401
- this.data = RG.arrayClone(this.original_data);
402
-
403
- // Loop thru the data array if chart.accumulative is enable checking to see if all the
404
- // datasets have the same number of elements.
405
- if (prop['chart.accumulative']) {
406
- for (var i=0; i<this.data.length; ++i) {
407
- if (this.data[i].length != this.data[0].length) {
408
- alert('[RADAR] Error! When the radar has chart.accumulative set to true all the datasets must have the same number of elements');
409
- }
410
- }
411
- }
412
-
413
-
414
- /**
415
- * This defaults to true, but needs to be an array with a size matching the number of
416
- * labels.
417
- */
418
- if (RG.isNull(prop['chart.labels.axes.boxed'])) {
419
- prop['chart.labels.axes.boxed'] = [];
420
- for (var i=0; i<(prop['chart.labels.specific'].length || prop['chart.labels.count'] || 5); ++i) {
421
- prop['chart.labels.axes.boxed'][i] = false;
422
- }
423
- }
424
-
425
-
426
-
427
-
428
- /**
429
- * This is new in May 2011 and facilitates indiviual gutter settings,
430
- * eg chart.gutter.left
431
- */
432
- this.gutterLeft = prop['chart.gutter.left'];
433
- this.gutterRight = prop['chart.gutter.right'];
434
- this.gutterTop = prop['chart.gutter.top'];
435
- this.gutterBottom = prop['chart.gutter.bottom'];
436
-
437
- this.centerx = ((ca.width - this.gutterLeft - this.gutterRight) / 2) + this.gutterLeft;
438
- this.centery = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop;
439
- this.radius = Math.min(ca.width - this.gutterLeft - this.gutterRight, ca.height - this.gutterTop - this.gutterBottom) / 2;
440
-
441
-
442
-
443
- /**
444
- * Allow these to be set by hand
445
- */
446
- if (typeof prop['chart.centerx'] == 'number') this.centerx = 2 * prop['chart.centerx'];
447
- if (typeof prop['chart.centery'] == 'number') this.centery = 2 * prop['chart.centery'];
448
- if (typeof prop['chart.radius'] == 'number') this.radius = prop['chart.radius'];
449
-
450
-
451
- /**
452
- * Parse the colors for gradients. Its down here so that the center X/Y can be used
453
- */
454
- if (!this.colorsParsed) {
455
-
456
- this.parseColors();
457
-
458
- // Don't want to do this again
459
- this.colorsParsed = true;
460
- }
461
-
462
-
463
-
464
- // Work out the maximum value and the sum
465
- if (!prop['chart.ymax']) {
466
-
467
- // this.max is calculated in the constructor
468
-
469
- // Work out this.max again if the chart is (now) set to be accumulative
470
- if (prop['chart.accumulative']) {
471
-
472
- var accumulation = [];
473
- var len = this.original_data[0].length
474
-
475
- for (var i=1; i<this.original_data.length; ++i) {
476
- if (this.original_data[i].length != len) {
477
- alert('[RADAR] Error! Stacked Radar chart datasets must all be the same size!');
478
- }
479
-
480
- for (var j=0; j<this.original_data[i].length; ++j) {
481
- this.data[i][j] += this.data[i - 1][j];
482
- this.max = Math.max(this.max, this.data[i][j]);
483
- }
484
- }
485
- }
486
-
487
-
488
- this.scale2 = RG.getScale2(this, {'max':typeof(prop['chart.ymax']) == 'number' ? prop['chart.ymax'] : this.max,
489
- 'min':0,
490
- 'scale.decimals':Number(prop['chart.scale.decimals']),
491
- 'scale.point':prop['chart.scale.point'],
492
- 'scale.thousand':prop['chart.scale.thousand'],
493
- 'scale.round':prop['chart.scale.round'],
494
- 'units.pre':prop['chart.units.pre'],
495
- 'units.post':prop['chart.units.post'],
496
- 'ylabels.count':prop['chart.labels.count']
497
- });
498
- this.max = this.scale2.max;
499
-
500
- } else {
501
- var ymax = prop['chart.ymax'];
502
-
503
- this.scale2 = RG.getScale2(this, {'max':ymax,
504
- 'min':0,
505
- 'strict':true,
506
- 'scale.decimals':Number(prop['chart.scale.decimals']),
507
- 'scale.point':prop['chart.scale.point'],
508
- 'scale.thousand':prop['chart.scale.thousand'],
509
- 'scale.round':prop['chart.scale.round'],
510
- 'units.pre':prop['chart.units.pre'],
511
- 'units.post':prop['chart.units.post'],
512
- 'ylabels.count':prop['chart.labels.count']
513
- });
514
- this.max = this.scale2.max;
515
- }
516
-
517
- this.drawBackground();
518
- this.drawAxes();
519
- this.drawCircle();
520
- this.drawLabels();
521
-
522
-
523
- /**
524
- * Allow clipping
525
- */
526
- co.save();
527
- co.beginPath();
528
- co.arc(this.centerx, this.centery, this.radius * 2, -RG.HALFPI, (RG.TWOPI * prop['chart.animation.trace.clip']) - RG.HALFPI, false);
529
- co.lineTo(this.centerx, this.centery);
530
- co.closePath();
531
- co.clip();
532
-
533
- this.DrawChart();
534
- this.DrawHighlights();
535
- co.restore();
536
-
537
- //
538
- // Draw the axis labels
539
- //
540
- this.drawAxisLabels();
541
-
542
- // Draw the title
543
- if (prop['chart.title']) {
544
- RG.DrawTitle(this, prop['chart.title'], this.gutterTop, null, prop['chart.title.diameter'] ? prop['chart.title.diameter'] : null)
545
- }
546
-
547
- // Draw the key if necessary
548
- // obj, key, colors
549
- if (prop['chart.key']) {
550
- RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
551
- }
552
-
553
- /**
554
- * Show the context menu
555
- */
556
- if (prop['chart.contextmenu']) {
557
- RG.ShowContext(this);
558
- }
559
-
560
-
561
- /**
562
- * This function enables resizing
563
- */
564
- if (prop['chart.resizable']) {
565
- RG.AllowResizing(this);
566
- }
567
-
568
-
569
- /**
570
- * This installs the event listeners
571
- */
572
- RG.InstallEventListeners(this);
573
-
574
- /**
575
- * This installs the Radar chart specific area listener
576
- */
577
- if ( (prop['chart.fill.click'] || prop['chart.fill.mousemove'] || !RG.is_null(prop['chart.fill.tooltips'])) && !this.__fill_click_listeners_installed__) {
578
- this.AddFillListeners();
579
- this.__fill_click_listeners_installed__ = true;
580
- }
581
-
582
-
583
-
584
- /**
585
- * Fire the onfirstdraw event
586
- */
587
- if (this.firstDraw) {
588
- RG.fireCustomEvent(this, 'onfirstdraw');
589
- this.firstDraw = false;
590
- this.firstDrawFunc();
591
- }
592
-
593
-
594
-
595
-
596
- /**
597
- * Fire the RGraph ondraw event
598
- */
599
- RGraph.FireCustomEvent(this, 'ondraw');
600
-
601
- return this;
602
- };
603
-
604
-
605
-
606
- /**
607
- * Used in chaining. Runs a function there and then - not waiting for
608
- * the events to fire (eg the onbeforedraw event)
609
- *
610
- * @param function func The function to execute
611
- */
612
- this.exec = function (func)
613
- {
614
- func(this);
615
-
616
- return this;
617
- };
618
-
619
-
620
-
621
-
622
- /**
623
- * Draws the background circles
624
- */
625
- this.drawBackground =
626
- this.DrawBackground = function ()
627
- {
628
- var color = prop['chart.background.circles.color'];
629
- var poly = prop['chart.background.circles.poly'];
630
- var spacing = prop['chart.background.circles.spacing'];
631
- var spokes = prop['chart.background.circles.spokes'];
632
-
633
-
634
-
635
-
636
- // Set the linewidth for the grid (so that repeated redrawing works OK)
637
- co.lineWidth = 1;
638
-
639
-
640
-
641
-
642
- /**
643
- * Draws the background circles
644
- */
645
- if (prop['chart.background.circles'] && poly == false) {
646
-
647
-
648
-
649
-
650
-
651
- // Draw the concentric circles
652
- co.strokeStyle = color;
653
- co.beginPath();
654
-
655
- var numrings = typeof(prop['chart.background.circles.count']) == 'number' ? prop['chart.background.circles.count'] : prop['chart.labels.count'];
656
-
657
- // TODO Currently set to 5 - needs changing
658
- for (var r=0; r<=this.radius; r+=(this.radius / numrings)) {
659
- co.moveTo(this.centerx, this.centery);
660
- co.arc(this.centerx, this.centery,r, 0, RG.TWOPI, false);
661
- }
662
- co.stroke();
663
-
664
-
665
-
666
-
667
-
668
- /**
669
- * Draw the diagonals/spokes
670
- */
671
- co.strokeStyle = color;
672
-
673
- for (var i=0; i<360; i+=(360 / spokes)) {
674
- co.beginPath();
675
- co.arc(this.centerx,
676
- this.centery,
677
- this.radius,
678
- (i / 360) * RG.TWOPI,
679
- ((i+0.001) / 360) * RG.TWOPI,
680
- false); // The 0.01 avoids a bug in Chrome 6
681
- co.lineTo(this.centerx, this.centery);
682
- co.stroke();
683
- }
684
-
685
-
686
-
687
-
688
-
689
-
690
- /**
691
- * The background"circles" are actually drawn as a poly based on how many points there are
692
- * (ie hexagons if there are 6 points, squares if the are four etc)
693
- */
694
- } else if (prop['chart.background.circles'] && poly == true) {
695
-
696
- /**
697
- * Draw the diagonals/spokes
698
- */
699
- co.strokeStyle = color;
700
- var increment = 360 / this.data[0].length
701
-
702
- for (var i=0; i<360; i+=increment) {
703
- co.beginPath();
704
- co.arc(this.centerx,
705
- this.centery,
706
- this.radius,
707
- ((i / 360) * RG.TWOPI) - RG.HALFPI,
708
- (((i + 0.001) / 360) * RG.TWOPI) - RG.HALFPI,
709
- false); // The 0.001 avoids a bug in Chrome 6
710
- co.lineTo(this.centerx, this.centery);
711
- co.stroke();
712
- }
713
-
714
-
715
- /**
716
- * Draw the lines that go around the Radar chart
717
- */
718
- co.strokeStyle = color;
719
-
720
- var numrings = typeof(prop['chart.background.circles.count']) == 'number' ? prop['chart.background.circles.count'] : prop['chart.labels.count'];
721
-
722
- for (var r=0; r<=this.radius; r+=(this.radius / numrings)) {
723
- co.beginPath();
724
- for (var a=0; a<=360; a+=(360 / this.data[0].length)) {
725
- co.arc(this.centerx,
726
- this.centery,
727
- r,
728
- RG.degrees2Radians(a) - RG.HALFPI,
729
- RG.degrees2Radians(a) + 0.001 - RG.HALFPI,
730
- false);
731
- }
732
- co.closePath();
733
- co.stroke();
734
- }
735
- }
736
- };
737
-
738
-
739
-
740
-
741
- /**
742
- * Draws the axes
743
- */
744
- this.drawAxes =
745
- this.DrawAxes = function ()
746
- {
747
- co.strokeStyle = prop['chart.axes.color'];
748
-
749
- var halfsize = this.radius;
750
-
751
- co.beginPath();
752
- /**
753
- * The Y axis
754
- */
755
- co.moveTo(Math.round(this.centerx), this.centery + this.radius);
756
- co.lineTo(Math.round(this.centerx), this.centery - this.radius);
757
-
758
-
759
- // Draw the bits at either end of the Y axis
760
- co.moveTo(this.centerx - 5, Math.round(this.centery + this.radius));
761
- co.lineTo(this.centerx + 5, Math.round(this.centery + this.radius));
762
- co.moveTo(this.centerx - 5, Math.round(this.centery - this.radius));
763
- co.lineTo(this.centerx + 5, Math.round(this.centery - this.radius));
764
-
765
- // Draw Y axis tick marks
766
- for (var y=(this.centery - this.radius); y<(this.centery + this.radius); y+=(this.radius/prop['chart.numyticks'])) {
767
- co.moveTo(this.centerx - 3, Math.round(y));
768
- co.lineTo(this.centerx + 3, Math.round(y));
769
- }
770
-
771
- /**
772
- * The X axis
773
- */
774
- co.moveTo(this.centerx - this.radius, Math.round(this.centery));
775
- co.lineTo(this.centerx + this.radius, Math.round(this.centery));
776
-
777
- // Draw the bits at the end of the X axis
778
- co.moveTo(Math.round(this.centerx - this.radius), this.centery - 5);
779
- co.lineTo(Math.round(this.centerx - this.radius), this.centery + 5);
780
- co.moveTo(Math.round(this.centerx + this.radius), this.centery - 5);
781
- co.lineTo(Math.round(this.centerx + this.radius), this.centery + 5);
782
-
783
- // Draw X axis tick marks
784
- for (var x=(this.centerx - this.radius); x<(this.centerx + this.radius); x+=(this.radius/prop['chart.numxticks'])) {
785
- co.moveTo(Math.round(x), this.centery - 3);
786
- co.lineTo(Math.round(x), this.centery + 3);
787
- }
788
-
789
- // Stroke it
790
- co.stroke();
791
- };
792
-
793
-
794
-
795
-
796
- /**
797
- * The function which actually draws the radar chart
798
- */
799
- this.drawChart =
800
- this.DrawChart = function ()
801
- {
802
- var alpha = prop['chart.colors.alpha'];
803
-
804
- if (typeof(alpha) == 'number') {
805
- var oldAlpha = co.globalAlpha;
806
- co.globalAlpha = alpha;
807
- }
808
-
809
- var numDatasets = this.data.length;
810
-
811
- for (var dataset=0; dataset<this.data.length; ++dataset) {
812
-
813
- co.beginPath();
814
-
815
- var coords_dataset = [];
816
-
817
- for (var i=0; i<this.data[dataset].length; ++i) {
818
-
819
- var coords = this.GetCoordinates(dataset, i);
820
-
821
- if (coords_dataset == null) {
822
- coords_dataset = [];
823
- }
824
-
825
- coords_dataset.push(coords);
826
- this.coords.push(coords);
827
- }
828
-
829
- this.coords2[dataset] = coords_dataset;
830
-
831
-
832
- /**
833
- * Now go through the coords and draw the chart itself
834
- *
835
- * 18/5/2012 - chart.strokestyle can now be an array of colors as well as a single color
836
- */
837
-
838
- co.strokeStyle = (typeof(prop['chart.strokestyle']) == 'object' && prop['chart.strokestyle'][dataset]) ? prop['chart.strokestyle'][dataset] : prop['chart.strokestyle'];
839
- co.fillStyle = prop['chart.colors'][dataset] ? prop['chart.colors'][dataset] : 'rgba(0,0,0,0)';
840
- if (co.fillStyle === 'transparent') {
841
- co.fillStyle = 'rgba(0,0,0,0)';
842
- }
843
- co.lineWidth = prop['chart.linewidth'];
844
-
845
- for (i=0; i<coords_dataset.length; ++i) {
846
- if (i == 0) {
847
- co.moveTo(coords_dataset[i][0], coords_dataset[i][1]);
848
- } else {
849
- co.lineTo(coords_dataset[i][0], coords_dataset[i][1]);
850
- }
851
- }
852
-
853
-
854
- // If on the second or greater dataset, backtrack
855
- if (prop['chart.accumulative'] && dataset > 0) {
856
-
857
- // This goes back to the start coords of this particular dataset
858
- co.lineTo(coords_dataset[0][0], coords_dataset[0][1]);
859
-
860
- //Now move down to the end point of the previous dataset
861
- co.moveTo(last_coords[0][0], last_coords[0][1]);
862
-
863
- for (var i=coords_dataset.length - 1; i>=0; --i) {
864
- co.lineTo(last_coords[i][0], last_coords[i][1]);
865
- }
866
- }
867
-
868
- // This is used by the next iteration of the loop
869
- var last_coords = coords_dataset;
870
-
871
- co.closePath();
872
-
873
- co.stroke();
874
- co.fill();
875
- }
876
-
877
- // Reset the globalAlpha
878
- if (typeof(alpha) == 'number') {
879
- co.globalAlpha = oldAlpha;
880
- }
881
- };
882
-
883
-
884
-
885
-
886
- /**
887
- * Gets the coordinates for a particular mark
888
- *
889
- * @param number i The index of the data (ie which one it is)
890
- * @return array A two element array of the coordinates
891
- */
892
- this.getCoordinates =
893
- this.GetCoordinates = function (dataset, index)
894
- {
895
- // The number of data points
896
- var len = this.data[dataset].length;
897
-
898
- // The magnitude of the data (NOT the x/y coords)
899
- var mag = (this.data[dataset][index] / this.max) * this.radius;
900
-
901
- /**
902
- * Get the angle
903
- */
904
- var angle = (RG.TWOPI / len) * index; // In radians
905
- angle -= RG.HALFPI;
906
-
907
-
908
- /**
909
- * Work out the X/Y coordinates
910
- */
911
- var x = Math.cos(angle) * mag;
912
- var y = Math.sin(angle) * mag;
913
-
914
- /**
915
- * Put the coordinate in the right quadrant
916
- */
917
- x = this.centerx + x;
918
- y = this.centery + y;
919
-
920
- return [x,y];
921
- };
922
-
923
-
924
-
925
-
926
- /**
927
- * This function adds the labels to the chart
928
- */
929
- this.drawLabels =
930
- this.DrawLabels = function ()
931
- {
932
- var labels = prop['chart.labels'];
933
-
934
- if (labels && labels.length > 0) {
935
-
936
- co.lineWidth = 1;
937
- co.strokeStyle = 'gray';
938
- co.fillStyle = prop['chart.labels.color'] || prop['chart.text.color'];
939
-
940
- var bgFill = prop['chart.labels.background.fill'],
941
- bold = prop['chart.labels.bold'],
942
- bgBoxed = prop['chart.labels.boxed'],
943
- offset = prop['chart.labels.offset'],
944
- font = prop['chart.text.font'],
945
- size = prop['chart.text.size'],
946
- radius = this.radius,
947
- color = prop['chart.labels.color'] || prop['chart.text.color']
948
-
949
- for (var i=0; i<labels.length; ++i) {
950
-
951
- var angle = (RG.TWOPI / prop['chart.labels'].length) * i;
952
- angle -= RG.HALFPI;
953
-
954
- var x = this.centerx + (ma.cos(angle) * (radius + offset));
955
- var y = this.centery + (ma.sin(angle) * (radius + offset));
956
-
957
- /**
958
- * Horizontal alignment
959
- */
960
- var halign = x < this.centerx ? 'right' : 'left' ;
961
- if (i == 0 || (i / labels.length) == 0.5) halign = 'center';
962
-
963
- if (labels[i] && labels[i].length) {
964
-
965
- RG.text2(this, {
966
- 'color': color,
967
- 'font':font,
968
- 'size':size,
969
- 'x':x,
970
- 'y':y,
971
- 'text':labels[i],
972
- 'valign':'center',
973
- 'halign':halign,
974
- 'bounding':bgBoxed,
975
- 'boundingFill':bgFill,
976
- 'bold':bold,
977
- 'tag': 'labels'
978
- });
979
- }
980
- }
981
- }
982
- };
983
-
984
-
985
-
986
-
987
- /**
988
- * Draws the circle. No arguments as it gets the information from the object properties.
989
- */
990
- this.drawCircle =
991
- this.DrawCircle = function ()
992
- {
993
- var circle = {};
994
- circle.limit = prop['chart.circle'];
995
- circle.fill = prop['chart.circle.fill'];
996
- circle.stroke = prop['chart.circle.stroke'];
997
-
998
- if (circle.limit) {
999
-
1000
- var r = (circle.limit / this.max) * this.radius;
1001
-
1002
- co.fillStyle = circle.fill;
1003
- co.strokeStyle = circle.stroke;
1004
-
1005
- co.beginPath();
1006
- co.arc(this.centerx, this.centery, r, 0, RG.TWOPI, 0);
1007
- co.fill();
1008
- co.stroke();
1009
- }
1010
- };
1011
-
1012
-
1013
-
1014
-
1015
- /**
1016
- * Unsuprisingly, draws the labels
1017
- */
1018
- this.drawAxisLabels =
1019
- this.DrawAxisLabels = function ()
1020
- {
1021
- /**
1022
- * Draw specific axis labels
1023
- */
1024
- if (RG.isArray(prop['chart.labels.specific']) && prop['chart.labels.specific'].length) {
1025
- this.drawSpecificAxisLabels();
1026
- return;
1027
- }
1028
-
1029
- co.lineWidth = 1;
1030
-
1031
- // Set the color to black
1032
- co.fillStyle = 'black';
1033
- co.strokeStyle = 'black';
1034
-
1035
- var r = this.radius,
1036
- font = prop['chart.text.font'],
1037
- size = typeof(prop['chart.text.size.scale']) == 'number' ? prop['chart.text.size.scale'] : prop['chart.text.size'],
1038
- axes = prop['chart.labels.axes'].toLowerCase(),
1039
- color = prop['chart.labels.axes.boxed.background'],
1040
- drawzero = false,
1041
- units_pre = prop['chart.units.pre'],
1042
- units_post = prop['chart.units.post'],
1043
- decimals = prop['chart.scale.decimals'],
1044
- bold = prop['chart.labels.axes.bold'],
1045
- boxed = prop['chart.labels.axes.boxed'],
1046
- centerx = this.centerx,
1047
- centery = this.centery,
1048
- scale = this.scale;
1049
-
1050
- co.fillStyle = prop['chart.text.color'];
1051
-
1052
- // The "North" axis labels
1053
- if (axes.indexOf('n') > -1) {
1054
- for (var i=0; i<this.scale2.labels.length; ++i) {
1055
- RG.Text2(this, {
1056
- 'bold':bold[i],
1057
- 'font':font,
1058
- 'size':size,
1059
- 'x':centerx,
1060
- 'y':centery - (r * ((i+1)/this.scale2.labels.length)),
1061
- 'text':this.scale2.labels[i],
1062
- 'valign':'center',
1063
- 'halign':'center',
1064
- 'bounding':boxed[i] || color,
1065
- 'boundingFill':color,
1066
- 'boundingStroke':'rgba(0,0,0,0)',
1067
- 'tag': 'scale'
1068
- });
1069
- }
1070
-
1071
- drawzero = true;
1072
- }
1073
-
1074
- // The "South" axis labels
1075
- if (axes.indexOf('s') > -1) {
1076
- for (var i=0; i<this.scale2.labels.length; ++i) {
1077
- RG.Text2(this, {
1078
- 'bold':bold[i],
1079
- 'font':font,
1080
- 'size':size,
1081
- 'x':centerx,
1082
- 'y':centery + (r * ((i+1)/this.scale2.labels.length)),
1083
- 'text':this.scale2.labels[i],
1084
- 'valign':'center',
1085
- 'halign':'center',
1086
- 'bounding':boxed[i] || color,
1087
- 'boundingFill':color,
1088
- 'boundingStroke':'rgba(0,0,0,0)',
1089
- 'tag': 'scale'
1090
- });
1091
- }
1092
-
1093
- drawzero = true;
1094
- }
1095
-
1096
- // The "East" axis labels
1097
- if (axes.indexOf('e') > -1) {
1098
-
1099
- for (var i=0; i<this.scale2.labels.length; ++i) {
1100
- RG.Text2(this, {
1101
- 'bold':bold[i],
1102
- 'font':font,
1103
- 'size':size,
1104
- 'x':centerx + (r * ((i+1)/this.scale2.labels.length)),
1105
- 'y':centery,
1106
- 'text':this.scale2.labels[i],
1107
- 'valign':'center',
1108
- 'halign':'center',
1109
- 'bounding':boxed[i]|| color,
1110
- 'boundingFill':color,
1111
- 'boundingStroke':'rgba(0,0,0,0)',
1112
- 'tag': 'scale'
1113
- });
1114
- }
1115
-
1116
- drawzero = true;
1117
- }
1118
-
1119
- // The "West" axis labels
1120
- if (axes.indexOf('w') > -1) {
1121
-
1122
- for (var i=0; i<this.scale2.labels.length; ++i) {
1123
- RG.Text2(this, {
1124
- 'bold':bold[i],
1125
- 'font':font,
1126
- 'size':size,
1127
- 'x':centerx - (r * ((i+1)/this.scale2.labels.length)),
1128
- 'y':centery,
1129
- 'text':this.scale2.labels[i],
1130
- 'valign':'center',
1131
- 'halign':'center',
1132
- 'bounding':boxed[i]|| color,
1133
- 'boundingFill':color,
1134
- 'boundingStroke':'rgba(0,0,0,0)',
1135
- 'tag': 'scale'
1136
- });
1137
- }
1138
-
1139
- drawzero = true;
1140
- }
1141
-
1142
- if (drawzero) {
1143
- RG.Text2(this, {
1144
- font:font,
1145
- size:size,
1146
- x:centerx,
1147
- y:centery,
1148
- text:RG.numberFormat(this, Number(0).toFixed(), units_pre, units_post),
1149
- valign:'center',
1150
- halign:'center',
1151
- bounding:prop['chart.labels.axes.boxed.zero'],
1152
- boundingFill:color,
1153
- boundingStroke:'rgba(0,0,0,0)',
1154
- bold:prop['chart.labels.axes.bold.zero'],
1155
- tag: 'scale'
1156
- });
1157
- }
1158
- };
1159
-
1160
-
1161
-
1162
-
1163
- /**
1164
- * Draws specific axis labels
1165
- */
1166
- this.drawSpecificAxisLabels =
1167
- this.DrawSpecificAxisLabels = function ()
1168
- {
1169
- /**
1170
- * Specific axis labels
1171
- */
1172
- var labels = prop['chart.labels.specific'];
1173
- var bold = RG.array_pad(prop['chart.labels.axes.bold'],labels.length);
1174
- var boxed = RG.array_pad(prop['chart.labels.axes.boxed'],labels.length);
1175
- var reversed_labels = RG.array_reverse(labels);
1176
- var reversed_bold = RG.array_reverse(bold);
1177
- var reversed_boxed = RG.array_reverse(boxed);
1178
- var font = prop['chart.text.font'];
1179
- var size = typeof(prop['chart.text.size.scale']) == 'number' ? prop['chart.text.size.scale'] : prop['chart.text.size'];
1180
- var axes = prop['chart.labels.axes'].toLowerCase();
1181
-
1182
- co.fillStyle = prop['chart.text.color'];
1183
-
1184
- for (var i=0; i<labels.length; ++i) {
1185
-
1186
- if (axes.indexOf('n') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':reversed_bold[i],'font':font,'size':size,'x':this.centerx,'y':this.centery - this.radius + ((this.radius / labels.length) * i),'text':reversed_labels[i],'valign':'center','halign':'center','bounding':reversed_boxed[i],'boundingFill':'white'});
1187
- if (axes.indexOf('s') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':bold[i],'font':font,'size':size,'x':this.centerx,'y':this.centery + ((this.radius / labels.length) * (i+1)),'text':labels[i],'valign':'center','halign':'center','bounding':boxed[i],'boundingFill':'white'});
1188
-
1189
- if (axes.indexOf('w') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':reversed_bold[i],'font':font,'size':size,'x':this.centerx - this.radius + ((this.radius / labels.length) * i),'y':this.centery,'text':reversed_labels[i],'valign':'center','halign':'center','bounding':reversed_boxed[i],'boundingFill':'white'});
1190
- if (axes.indexOf('e') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':bold[i],'font':font,'size':size,'x':this.centerx + ((this.radius / labels.length) * (i+1)),'y':this.centery,'text':labels[i],'valign':'center','halign':'center','bounding':boxed[i],'boundingFill':'white'});
1191
- }
1192
- };
1193
-
1194
-
1195
-
1196
-
1197
- /**
1198
- * This method eases getting the focussed point (if any)
1199
- *
1200
- * @param event e The event object
1201
- */
1202
- this.getShape =
1203
- this.getPoint = function (e)
1204
- {
1205
- for (var i=0; i<this.coords.length; ++i) {
1206
-
1207
- var x = this.coords[i][0];
1208
- var y = this.coords[i][1];
1209
- var tooltips = prop['chart.tooltips'];
1210
- var index = Number(i);
1211
- var mouseXY = RG.getMouseXY(e);
1212
- var mouseX = mouseXY[0];
1213
- var mouseY = mouseXY[1];
1214
-
1215
- if ( mouseX < (x + 5)
1216
- && mouseX > (x - 5)
1217
- && mouseY > (y - 5)
1218
- && mouseY < (y + 5)
1219
- ) {
1220
-
1221
- var tooltip = RG.parseTooltipText(prop['chart.tooltips'], index);
1222
-
1223
- return {0: this, 'object': this,
1224
- 1: x, 'x': x,
1225
- 2: y, 'y': y,
1226
- 3: null, 'dataset': null,
1227
- 4: index, 'index': i,
1228
- 'tooltip': tooltip
1229
- }
1230
- }
1231
- }
1232
- };
1233
-
1234
-
1235
-
1236
-
1237
- /**
1238
- * Each object type has its own Highlight() function which highlights the appropriate shape
1239
- *
1240
- * @param object shape The shape to highlight
1241
- */
1242
- this.highlight =
1243
- this.Highlight = function (shape)
1244
- {
1245
- if (typeof prop['chart.highlight.style'] === 'function') {
1246
- (prop['chart.highlight.style'])(shape);
1247
- } else {
1248
- RG.Highlight.Point(this, shape);
1249
- }
1250
- };
1251
-
1252
-
1253
-
1254
-
1255
- /**
1256
- * The getObjectByXY() worker method. Don't call this call:
1257
- *
1258
- * RGraph.ObjectRegistry.getObjectByXY(e)
1259
- *
1260
- * @param object e The event object
1261
- */
1262
- this.getObjectByXY = function (e)
1263
- {
1264
- var mouseXY = RG.getMouseXY(e);
1265
-
1266
- if (
1267
- mouseXY[0] > (this.centerx - this.radius)
1268
- && mouseXY[0] < (this.centerx + this.radius)
1269
- && mouseXY[1] > (this.centery - this.radius)
1270
- && mouseXY[1] < (this.centery + this.radius)
1271
- ) {
1272
-
1273
- return this;
1274
- }
1275
- };
1276
-
1277
-
1278
-
1279
-
1280
- /**
1281
- * This function positions a tooltip when it is displayed
1282
- *
1283
- * @param obj object The chart object
1284
- * @param int x The X coordinate specified for the tooltip
1285
- * @param int y The Y coordinate specified for the tooltip
1286
- * @param objec tooltip The tooltips DIV element
1287
- *
1288
- this.positionTooltip = function (obj, x, y, tooltip, idx)
1289
- {
1290
- var dataset = tooltip.__dataset__;
1291
- var index = tooltip.__index__;
1292
- var coordX = this.coords[index][0];
1293
- var coordY = this.coords[index][1];
1294
- var canvasXY = RG.getCanvasXY(obj.canvas);
1295
- var gutterLeft = this.gutterLeft;
1296
- var gutterTop = this.gutterTop;
1297
- var width = tooltip.offsetWidth;
1298
- var height = tooltip.offsetHeight;
1299
- var mouseXY = RG.getMouseXY(window.event);
1300
-
1301
- // Set the top position
1302
- tooltip.style.left = 0;
1303
- tooltip.style.top = window.event.pageY - height - 5 + 'px';
1304
-
1305
- // By default any overflow is hidden
1306
- tooltip.style.overflow = '';
1307
-
1308
- // Reposition the tooltip if at the edges:
1309
-
1310
- // LEFT edge
1311
- if (canvasXY[0] + mouseXY[0] - (width / 2) < 0) {
1312
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
1313
-
1314
- // RIGHT edge
1315
- } else if (canvasXY[0] + mouseXY[0] + (width / 2) > doc.body.offsetWidth) {
1316
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
1317
-
1318
- // Default positioning - CENTERED
1319
- } else {
1320
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
1321
- }
1322
- };*/
1323
-
1324
-
1325
-
1326
-
1327
- /**
1328
- * This draws highlights on the points
1329
- */
1330
- this.drawHighlights =
1331
- this.DrawHighlights = function ()
1332
- {
1333
- if (prop['chart.highlights']) {
1334
-
1335
- var sequentialIdx = 0;
1336
- var dataset = 0;
1337
- var index = 0;
1338
- var radius = prop['chart.highlights.radius'];
1339
-
1340
-
1341
-
1342
- for (var dataset=0; dataset <this.data.length; ++dataset) {
1343
- for (var index=0; index<this.data[dataset].length; ++index) {
1344
- co.beginPath();
1345
- co.strokeStyle = prop['chart.highlights.stroke'];
1346
- co.fillStyle = prop['chart.highlights.fill'] ? prop['chart.highlights.fill'] : ((typeof(prop['chart.strokestyle']) == 'object' && prop['chart.strokestyle'][dataset]) ? prop['chart.strokestyle'][dataset] : prop['chart.strokestyle']);
1347
- co.arc(this.coords[sequentialIdx][0], this.coords[sequentialIdx][1], radius, 0, RG.TWOPI, false);
1348
- co.stroke();
1349
- co.fill();
1350
- ++sequentialIdx;
1351
- }
1352
- }
1353
-
1354
- }
1355
- };
1356
-
1357
-
1358
-
1359
-
1360
- /**
1361
- * This function returns the radius (ie the distance from the center) for a particular
1362
- * value. Note that if you want the angle for a point you can use getAngle(index)
1363
- *
1364
- * @param number value The value you want the radius for
1365
- */
1366
- this.getRadius = function (value)
1367
- {
1368
- if (value < 0 || value > this.max) {
1369
- return null;
1370
- }
1371
-
1372
- // Radar doesn't support minimum value
1373
- var radius = (value / this.max) * this.radius;
1374
-
1375
- return radius;
1376
- };
1377
-
1378
-
1379
-
1380
-
1381
- /**
1382
- * This function returns the angle (in radians) for a particular index.
1383
- *
1384
- * @param number numitems The total number of items
1385
- * @param number index The zero index number of the item to get the angle for
1386
- */
1387
- this.getAngle = function (numitems, index)
1388
- {
1389
- var angle = (RG.TWOPI / numitems) * index;
1390
- angle -= RG.HALFPI;
1391
-
1392
- return angle;
1393
- };
1394
-
1395
-
1396
-
1397
-
1398
- /**
1399
- * This allows for easy specification of gradients
1400
- */
1401
- this.parseColors = function ()
1402
- {
1403
- // Save the original colors so that they can be restored when the canvas is reset
1404
- if (this.original_colors.length === 0) {
1405
- this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
1406
- this.original_colors['chart.key.colors'] = RG.array_clone(prop['chart.key.colors']);
1407
- this.original_colors['chart.title.color'] = RG.array_clone(prop['chart.title.color']);
1408
- this.original_colors['chart.text.color'] = RG.array_clone(prop['chart.text.color']);
1409
- this.original_colors['chart.highlight.stroke'] = RG.array_clone(prop['chart.highlight.stroke']);
1410
- this.original_colors['chart.highlight.fill'] = RG.array_clone(prop['chart.highlight.fill']);
1411
- this.original_colors['chart.circle.fill'] = RG.array_clone(prop['chart.circle.fill']);
1412
- this.original_colors['chart.circle.stroke'] = RG.array_clone(prop['chart.circle.stroke']);
1413
- }
1414
-
1415
- for (var i=0; i<prop['chart.colors'].length; ++i) {
1416
- prop['chart.colors'][i] = this.parseSingleColorForGradient(prop['chart.colors'][i]);
1417
- }
1418
-
1419
- var keyColors = prop['chart.key.colors'];
1420
-
1421
- if (typeof(keyColors) != 'null' && keyColors && keyColors.length) {
1422
- for (var i=0; i<prop['chart.key.colors'].length; ++i) {
1423
- prop['chart.key.colors'][i] = this.parseSingleColorForGradient(prop['chart.key.colors'][i]);
1424
- }
1425
- }
1426
-
1427
- prop['chart.title.color'] = this.parseSingleColorForGradient(prop['chart.title.color']);
1428
- prop['chart.text.color'] = this.parseSingleColorForGradient(prop['chart.text.color']);
1429
- prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
1430
- prop['chart.highlight.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.fill']);
1431
- prop['chart.circle.fill'] = this.parseSingleColorForGradient(prop['chart.circle.fill']);
1432
- prop['chart.circle.stroke'] = this.parseSingleColorForGradient(prop['chart.circle.stroke']);
1433
- };
1434
-
1435
-
1436
-
1437
-
1438
- /**
1439
- * Use this function to reset the object to the post-constructor state. Eg reset colors if
1440
- * need be etc
1441
- */
1442
- this.reset = function ()
1443
- {
1444
- };
1445
-
1446
-
1447
-
1448
-
1449
- /**
1450
- * This parses a single color value
1451
- */
1452
- this.parseSingleColorForGradient = function (color)
1453
- {
1454
- if (!color || typeof(color) != 'string') {
1455
- return color;
1456
- }
1457
-
1458
- if (color.match(/^gradient\((.*)\)$/i)) {
1459
-
1460
- var parts = RegExp.$1.split(':');
1461
-
1462
- // Create the gradient
1463
- var grad = co.createRadialGradient(this.centerx, this.centery, 0, this.centerx, this.centery, this.radius);
1464
-
1465
- var diff = 1 / (parts.length - 1);
1466
-
1467
- grad.addColorStop(0, RG.trim(parts[0]));
1468
-
1469
- for (var j=1; j<parts.length; ++j) {
1470
- grad.addColorStop(j * diff, RG.trim(parts[j]));
1471
- }
1472
- }
1473
-
1474
- return grad ? grad : color;
1475
- };
1476
-
1477
-
1478
-
1479
-
1480
- this.addFillListeners =
1481
- this.AddFillListeners = function (e)
1482
- {
1483
- var obj = this;
1484
-
1485
- var func = function (e)
1486
- {
1487
- //var canvas = e.target;
1488
- //var context = canvas.getContext('2d');
1489
- var coords = this.coords;
1490
- var coords2 = this.coords2;
1491
- var mouseXY = RG.getMouseXY(e);
1492
- var dataset = 0;
1493
-
1494
- if (e.type == 'mousemove' && prop['chart.fill.mousemove.redraw']) {
1495
- RG.RedrawCanvas(ca);
1496
- }
1497
-
1498
- for (var dataset=(obj.coords2.length-1); dataset>=0; --dataset) {
1499
-
1500
- // Draw the path again so that it can be checked
1501
- co.beginPath();
1502
- co.moveTo(obj.coords2[dataset][0][0], obj.coords2[dataset][0][1]);
1503
- for (var j=0; j<obj.coords2[dataset].length; ++j) {
1504
- co.lineTo(obj.coords2[dataset][j][0], obj.coords2[dataset][j][1]);
1505
- }
1506
-
1507
- // Draw a line back to the starting point
1508
- co.lineTo(obj.coords2[dataset][0][0], obj.coords2[dataset][0][1]);
1509
-
1510
- // Go thru the previous datasets coords in reverse order
1511
- if (prop['chart.accumulative'] && dataset > 0) {
1512
- co.lineTo(obj.coords2[dataset - 1][0][0], obj.coords2[dataset - 1][0][1]);
1513
- for (var j=(obj.coords2[dataset - 1].length - 1); j>=0; --j) {
1514
- co.lineTo(obj.coords2[dataset - 1][j][0], obj.coords2[dataset - 1][j][1]);
1515
- }
1516
- }
1517
-
1518
- co.closePath();
1519
-
1520
- if (co.isPointInPath(mouseXY[0], mouseXY[1])) {
1521
- var inPath = true;
1522
- break;
1523
- }
1524
- }
1525
-
1526
- // Call the events
1527
- if (inPath) {
1528
-
1529
- var fillTooltips = prop['chart.fill.tooltips'];
1530
-
1531
- /**
1532
- * Click event
1533
- */
1534
- if (e.type == 'click') {
1535
- if (prop['chart.fill.click']) {
1536
- prop['chart.fill.click'](e, dataset);
1537
- }
1538
-
1539
- if (prop['chart.fill.tooltips'] && prop['chart.fill.tooltips'][dataset]) {
1540
- obj.DatasetTooltip(e, dataset);
1541
- }
1542
- }
1543
-
1544
-
1545
-
1546
- /**
1547
- * Mousemove event
1548
- */
1549
- if (e.type == 'mousemove') {
1550
-
1551
- if (prop['chart.fill.mousemove']) {
1552
- prop['chart.fill.mousemove'](e, dataset);
1553
- }
1554
-
1555
- if (!RG.is_null(fillTooltips)) {
1556
- e.target.style.cursor = 'pointer';
1557
- }
1558
-
1559
- if (prop['chart.fill.tooltips'] && prop['chart.fill.tooltips'][dataset]) {
1560
- e.target.style.cursor = 'pointer';
1561
- }
1562
- }
1563
-
1564
- e.stopPropagation();
1565
-
1566
- } else if (e.type == 'mousemove') {
1567
- ca.style.cursor = 'default';
1568
- }
1569
- };
1570
-
1571
- /**
1572
- * Add the click listener
1573
- */
1574
- if (prop['chart.fill.click'] || !RG.is_null(prop['chart.fill.tooltips'])) {
1575
- ca.addEventListener('click', func, false);
1576
- }
1577
-
1578
- /**
1579
- * Add the mousemove listener
1580
- */
1581
- if (prop['chart.fill.mousemove'] || !RG.is_null(prop['chart.fill.tooltips'])) {
1582
- ca.addEventListener('mousemove', func, false);
1583
- }
1584
- };
1585
-
1586
-
1587
-
1588
-
1589
- /**
1590
- * This highlights a specific dataset on the chart
1591
- *
1592
- * @param number dataset The index of the dataset (which starts at zero)
1593
- */
1594
- this.highlightDataset =
1595
- this.HighlightDataset = function (dataset)
1596
- {
1597
- co.beginPath();
1598
- for (var j=0; j<this.coords2[dataset].length; ++j) {
1599
- if (j == 0) {
1600
- co.moveTo(this.coords2[dataset][0][0], this.coords2[dataset][0][1]);
1601
- } else {
1602
- co.lineTo(this.coords2[dataset][j][0], this.coords2[dataset][j][1]);
1603
- }
1604
- }
1605
-
1606
- co.lineTo(this.coords2[dataset][0][0], this.coords2[dataset][0][1]);
1607
-
1608
- if (prop['chart.accumulative'] && dataset > 0) {
1609
- co.lineTo(this.coords2[dataset - 1][0][0], this.coords2[dataset - 1][0][1]);
1610
- for (var j=(this.coords2[dataset - 1].length - 1); j>=0; --j) {
1611
- co.lineTo(this.coords2[dataset - 1][j][0], this.coords2[dataset - 1][j][1]);
1612
- }
1613
- }
1614
-
1615
- co.strokeStyle = prop['chart.fill.highlight.stroke'];
1616
- co.fillStyle = prop['chart.fill.highlight.fill'];
1617
-
1618
- co.stroke();
1619
- co.fill();
1620
- };
1621
-
1622
-
1623
-
1624
-
1625
- /**
1626
- * Shows a tooltip for a dataset (a "fill" tooltip), You can pecify these
1627
- * with chart.fill.tooltips
1628
- */
1629
- this.datasetTooltip =
1630
- this.DatasetTooltip = function (e, dataset)
1631
- {
1632
- // Highlight the dataset
1633
- this.HighlightDataset(dataset);
1634
-
1635
- // Use the First datapoints coords for the Y position of the tooltip NOTE The X position is changed in the
1636
- // obj.positionTooltip() method so set the index to be the first one
1637
- var text = prop['chart.fill.tooltips'][dataset];
1638
- var x = 0;
1639
- var y = this.coords2[dataset][0][1] + RG.getCanvasXY(ca)[1];
1640
-
1641
-
1642
- // Show a tooltip
1643
- RG.Tooltip(this, text, x, y, 0, e);
1644
- };
1645
-
1646
-
1647
-
1648
-
1649
- /**
1650
- * This function handles highlighting an entire data-series for the interactive
1651
- * key
1652
- *
1653
- * @param int index The index of the data series to be highlighted
1654
- */
1655
- this.interactiveKeyHighlight = function (index)
1656
- {
1657
- var coords = this.coords2[index];
1658
-
1659
- if (coords) {
1660
-
1661
- var pre_linewidth = co.lineWidth;
1662
- var pre_linecap = co.lineCap;
1663
-
1664
-
1665
-
1666
-
1667
- // ------------------------------------------ //
1668
-
1669
- co.lineWidth = prop['chart.linewidth'] + 10;
1670
- co.lineCap = 'round';
1671
- co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
1672
-
1673
-
1674
- co.beginPath();
1675
- for (var i=0,len=coords.length; i<len; i+=1) {
1676
- if (i == 0) {
1677
- co.moveTo(coords[i][0], coords[i][1]);
1678
- } else {
1679
- co.lineTo(coords[i][0], coords[i][1]);
1680
- }
1681
- }
1682
- co.closePath();
1683
- co.stroke();
1684
-
1685
- // ------------------------------------------ //
1686
-
1687
-
1688
-
1689
-
1690
- // Reset the lineCap and lineWidth
1691
- co.lineWidth = pre_linewidth;
1692
- co.lineCap = pre_linecap;
1693
- }
1694
- };
1695
-
1696
-
1697
-
1698
-
1699
- /**
1700
- * Using a function to add events makes it easier to facilitate method chaining
1701
- *
1702
- * @param string type The type of even to add
1703
- * @param function func
1704
- */
1705
- this.on = function (type, func)
1706
- {
1707
- if (type.substr(0,2) !== 'on') {
1708
- type = 'on' + type;
1709
- }
1710
-
1711
- if (typeof this[type] !== 'function') {
1712
- this[type] = func;
1713
- } else {
1714
- RG.addCustomEventListener(this, type, func);
1715
- }
1716
-
1717
- return this;
1718
- };
1719
-
1720
-
1721
-
1722
-
1723
- /**
1724
- * This function runs once only
1725
- * (put at the end of the file (before any effects))
1726
- */
1727
- this.firstDrawFunc = function ()
1728
- {
1729
- };
1730
-
1731
-
1732
-
1733
-
1734
- /**
1735
- * Radar chart grow
1736
- *
1737
- * This effect gradually increases the magnitude of the points on the radar chart
1738
- *
1739
- * @param object Options for the effect
1740
- * @param function An optional callback that is run when the effect is finished
1741
- */
1742
- this.grow = function ()
1743
- {
1744
- var obj = this;
1745
- var callback = arguments[1] ? arguments[1] : function () {};
1746
- var opt = arguments[0] ? arguments[0] : {};
1747
- var frames = opt.frames ? opt.frames : 30;
1748
- var frame = 0;
1749
- var data = RG.array_clone(obj.data);
1750
-
1751
- function iterator ()
1752
- {
1753
- for (var i=0,len=data.length; i<len; ++i) {
1754
-
1755
- //if (obj.original_data[i] == null) {
1756
- // obj.original_data[i] = [];
1757
- //}
1758
-
1759
- for (var j=0,len2=data[i].length; j<len2; ++j) {
1760
- obj.original_data[i][j] = (frame / frames) * data[i][j];
1761
- }
1762
- }
1763
-
1764
- RGraph.clear(obj.canvas);
1765
- RGraph.redrawCanvas(obj.canvas);
1766
-
1767
- if (frame < frames) {
1768
- frame++;
1769
- RGraph.Effects.updateCanvas(iterator);
1770
- } else {
1771
- callback(obj);
1772
- }
1773
- }
1774
-
1775
- iterator();
1776
-
1777
- return this;
1778
- };
1779
-
1780
-
1781
-
1782
-
1783
- /**
1784
- * Trace (Radar chart)
1785
- *
1786
- * This is a Trace effect for the Radar chart
1787
- *
1788
- * @param object Options for the effect. Currently only "frames" is available.
1789
- * @param function A function that is called when the ffect is complete
1790
- */
1791
- this.trace = function ()
1792
- {
1793
- var obj = this;
1794
- var opt = arguments[0] || {};
1795
- var frames = opt.frames || 60;
1796
- var frame = 0;
1797
- var callback = arguments[1] || function () {};
1798
-
1799
- obj.Set('animation.trace.clip', 0);
1800
-
1801
-
1802
- var iterator = function ()
1803
- {
1804
- if (frame < frames) {
1805
-
1806
- obj.Set('animation.trace.clip', frame / frames);
1807
-
1808
- frame++;
1809
- RG.redrawCanvas(obj.canvas);
1810
- RG.Effects.updateCanvas(iterator);
1811
-
1812
- } else {
1813
-
1814
- obj.Set('animation.trace.clip', 1);
1815
- RG.redrawCanvas(obj.canvas);
1816
- callback(obj);
1817
- }
1818
- };
1819
-
1820
- iterator();
1821
-
1822
- return this;
1823
- };
1824
-
1825
-
1826
-
1827
-
1828
- RG.att(ca);
1829
-
1830
-
1831
-
1832
-
1833
- /**
1834
- * Always register the object
1835
- */
1836
- RG.Register(this);
1837
-
1838
-
1839
-
1840
-
1841
- /**
1842
- * This is the 'end' of the constructor so if the first argument
1843
- * contains configuration data - handle that.
1844
- */
1845
- if (parseConfObjectForOptions) {
1846
- RG.parseObjectStyleConfig(this, conf.options);
1847
- }
1848
- };
2
+ RGraph=window.RGraph||{isRGraph:true};RGraph.Radar=function(conf)
3
+ {if(typeof conf==='object'&&typeof conf.data==='object'&&typeof conf.id==='string'){var parseConfObjectForOptions=true;if(typeof conf.data[0]==='number'||typeof conf.data[0]==='string'){conf.data=[conf.data];}}else{var conf={id:conf,data:[]};if(typeof arguments[1]==='object'&&typeof arguments[1][0]==='number'){for(var i=1;i<arguments.length;++i){conf.data.push(RGraph.arrayClone(arguments[i]));}}else if(typeof arguments[1]==='object'&&typeof arguments[1][0]==='object'&&typeof arguments[1][0][0]==='number'){conf.data=RGraph.arrayClone(arguments[1]);}}
4
+ this.id=conf.id;this.canvas=document.getElementById(conf.id);this.context=this.canvas.getContext?this.canvas.getContext("2d"):null;this.canvas.__object__=this;this.type='radar';this.isRGraph=true;this.data=[];this.max=0;this.uid=RGraph.CreateUID();this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID();this.colorsParsed=false;this.coords=[];this.coordsText=[];this.original_data=[];this.original_colors=[];this.firstDraw=true;for(var i=0,len=conf.data.length;i<len;++i){for(var j=0;j<conf.data[i].length;++j){if(typeof conf.data[i][j]==='string'){conf.data[i][j]=parseFloat(conf.data[i][j]);}}
5
+ this.original_data.push(RGraph.arrayClone(conf.data[i]));this.data.push(RGraph.arrayClone(conf.data[i]));this.max=Math.max(this.max,RGraph.arrayMax(conf.data[i]));}
6
+ this.properties={'chart.strokestyle':'#aaa','chart.gutter.left':25,'chart.gutter.right':25,'chart.gutter.top':25,'chart.gutter.bottom':25,'chart.linewidth':1,'chart.colors':['rgba(255,255,0,0.25)','rgba(0,255,255,0.25)','rgba(255,0,0,0.5)','red','green','blue','pink','aqua','brown','orange','grey'],'chart.colors.alpha':null,'chart.circle':0,'chart.circle.fill':'red','chart.circle.stroke':'black','chart.labels':[],'chart.labels.color':null,'chart.labels.offset':10,'chart.labels.axes':'','chart.labels.background.fill':'white','chart.labels.boxed':false,'chart.labels.axes.bold':[],'chart.labels.axes.boxed':null,'chart.labels.axes.boxed.zero':true,'chart.labels.axes.boxed.background':'rgba(255,255,255,0.9)','chart.labels.specific':[],'chart.labels.count':5,'chart.background.circles':true,'chart.background.circles.count':null,'chart.background.circles.color':'#ddd','chart.background.circles.poly':true,'chart.background.circles.spokes':24,'chart.text.size':12,'chart.text.size.scale':null,'chart.text.font':'Segoe UI, Arial, Verdana, sans-serif','chart.text.color':'black','chart.text.accessible':true,'chart.text.accessible.overflow':'visible','chart.text.accessible.pointerevents':true,'chart.title':'','chart.title.background':null,'chart.title.hpos':null,'chart.title.vpos':null,'chart.title.color':'black','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.linewidth':1,'chart.key':null,'chart.key.background':'white','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':'graph','chart.key.halign':'right','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':'rgba(255,0,0,0.3)','chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)','chart.key.text.color':'black','chart.contextmenu':null,'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.tooltips.effect':'fade','chart.tooltips.event':'onmousemove','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.highlight':true,'chart.highlight.stroke':'gray','chart.highlight.fill':'rgba(255,255,255,0.7)','chart.highlight.point.radius':2,'chart.resizable':false,'chart.resize.handle.adjust':[0,0],'chart.resize.handle.background':null,'chart.ymax':null,'chart.accumulative':false,'chart.radius':null,'chart.events.click':null,'chart.events.mousemove':null,'chart.scale.decimals':0,'chart.scale.point':'.','chart.scale.thousand':',','chart.units.pre':'','chart.units.post':'','chart.tooltips':null,'chart.tooltips.event':'onmousemove','chart.centerx':null,'chart.centery':null,'chart.radius':null,'chart.numxticks':5,'chart.numyticks':5,'chart.axes.color':'rgba(0,0,0,0)','chart.highlights':false,'chart.highlights.stroke':'#ddd','chart.highlights.fill':null,'chart.highlights.radius':3,'chart.fill.click':null,'chart.fill.mousemove':null,'chart.fill.tooltips':null,'chart.fill.highlight.fill':'rgba(255,255,255,0.7)','chart.fill.highlight.stroke':'rgba(0,0,0,0)','chart.fill.mousemove.redraw':false,'chart.animation.trace.clip':1,'chart.clearto':'rgba(0,0,0,0)'}
7
+ for(var dataset=0;dataset<this.data.length;++dataset){if(this.data[dataset].length<3){alert('[RADAR] You must specify at least 3 data points');return;}}
8
+ var idx=0;for(var dataset=0;dataset<this.data.length;++dataset){for(var i=0,len=this.data[dataset].length;i<len;++i){this['$'+(idx++)]={};}}
9
+ if(!this.canvas.__rgraph_aa_translated__){this.context.translate(0.5,0.5);this.canvas.__rgraph_aa_translated__=true;}
10
+ var RG=RGraph,ca=this.canvas,co=ca.getContext('2d'),prop=this.properties,pa2=RG.path2,win=window,doc=document,ma=Math
11
+ if(RG.Effects&&typeof RG.Effects.decorate==='function'){RG.Effects.decorate(this);}
12
+ this.set=this.Set=function(name,value)
13
+ {var value=typeof arguments[1]==='undefined'?null:arguments[1];if(arguments.length===1&&typeof name==='object'){RG.parseObjectStyleConfig(this,name);return this;}
14
+ if(name.substr(0,6)!='chart.'){name='chart.'+name;}
15
+ while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
16
+ if(name=='chart.text.diameter'){name='chart.text.size';}
17
+ if(name=='chart.color'){this.properties['chart.colors']=[value];}
18
+ prop[name]=value;return this;};this.get=this.Get=function(name)
19
+ {if(name.substr(0,6)!='chart.'){name='chart.'+name;}
20
+ while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
21
+ if(name=='chart.text.diameter'){name='chart.text.size';}
22
+ return prop[name];};this.draw=this.Draw=function()
23
+ {RG.FireCustomEvent(this,'onbeforedraw');this.coords=[];this.coords2=[];this.coordsText=[];this.data=RG.arrayClone(this.original_data);if(prop['chart.accumulative']){for(var i=0;i<this.data.length;++i){if(this.data[i].length!=this.data[0].length){alert('[RADAR] Error! When the radar has chart.accumulative set to true all the datasets must have the same number of elements');}}}
24
+ if(RG.isNull(prop['chart.labels.axes.boxed'])){prop['chart.labels.axes.boxed']=[];for(var i=0;i<(prop['chart.labels.specific'].length||prop['chart.labels.count']||5);++i){prop['chart.labels.axes.boxed'][i]=false;}}
25
+ 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.centerx=((ca.width-this.gutterLeft-this.gutterRight)/2)+this.gutterLeft;this.centery=((ca.height-this.gutterTop-this.gutterBottom)/2)+this.gutterTop;this.radius=Math.min(ca.width-this.gutterLeft-this.gutterRight,ca.height-this.gutterTop-this.gutterBottom)/2;if(typeof prop['chart.centerx']=='number')this.centerx=2*prop['chart.centerx'];if(typeof prop['chart.centery']=='number')this.centery=2*prop['chart.centery'];if(typeof prop['chart.radius']=='number')this.radius=prop['chart.radius'];if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
26
+ if(!prop['chart.ymax']){if(prop['chart.accumulative']){var accumulation=[];var len=this.original_data[0].length
27
+ for(var i=1;i<this.original_data.length;++i){if(this.original_data[i].length!=len){alert('[RADAR] Error! Stacked Radar chart datasets must all be the same size!');}
28
+ for(var j=0;j<this.original_data[i].length;++j){this.data[i][j]+=this.data[i-1][j];this.max=Math.max(this.max,this.data[i][j]);}}}
29
+ this.scale2=RG.getScale2(this,{'max':typeof(prop['chart.ymax'])=='number'?prop['chart.ymax']:this.max,'min':0,'scale.decimals':Number(prop['chart.scale.decimals']),'scale.point':prop['chart.scale.point'],'scale.thousand':prop['chart.scale.thousand'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post'],'ylabels.count':prop['chart.labels.count']});this.max=this.scale2.max;}else{var ymax=prop['chart.ymax'];this.scale2=RG.getScale2(this,{'max':ymax,'min':0,'strict':true,'scale.decimals':Number(prop['chart.scale.decimals']),'scale.point':prop['chart.scale.point'],'scale.thousand':prop['chart.scale.thousand'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post'],'ylabels.count':prop['chart.labels.count']});this.max=this.scale2.max;}
30
+ this.drawBackground();this.drawAxes();this.drawCircle();this.drawLabels();co.save();co.beginPath();co.arc(this.centerx,this.centery,this.radius*2,-RG.HALFPI,(RG.TWOPI*prop['chart.animation.trace.clip'])-RG.HALFPI,false);co.lineTo(this.centerx,this.centery);co.closePath();co.clip();this.DrawChart();this.DrawHighlights();co.restore();this.drawAxisLabels();if(prop['chart.title']){RG.DrawTitle(this,prop['chart.title'],this.gutterTop,null,prop['chart.title.diameter']?prop['chart.title.diameter']:null)}
31
+ if(prop['chart.key']){RG.DrawKey(this,prop['chart.key'],prop['chart.colors']);}
32
+ if(prop['chart.contextmenu']){RG.ShowContext(this);}
33
+ if(prop['chart.resizable']){RG.AllowResizing(this);}
34
+ RG.InstallEventListeners(this);if((prop['chart.fill.click']||prop['chart.fill.mousemove']||!RG.is_null(prop['chart.fill.tooltips']))&&!this.__fill_click_listeners_installed__){this.AddFillListeners();this.__fill_click_listeners_installed__=true;}
35
+ if(this.firstDraw){this.firstDraw=false;RG.fireCustomEvent(this,'onfirstdraw');this.firstDrawFunc();}
36
+ RGraph.FireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
37
+ {func(this);return this;};this.drawBackground=this.DrawBackground=function()
38
+ {var color=prop['chart.background.circles.color'];var poly=prop['chart.background.circles.poly'];var spacing=prop['chart.background.circles.spacing'];var spokes=prop['chart.background.circles.spokes'];co.lineWidth=1;if(prop['chart.background.circles']&&poly==false){co.strokeStyle=color;co.beginPath();var numrings=typeof(prop['chart.background.circles.count'])=='number'?prop['chart.background.circles.count']:prop['chart.labels.count'];for(var r=0;r<=this.radius;r+=(this.radius/numrings)){co.moveTo(this.centerx,this.centery);co.arc(this.centerx,this.centery,r,0,RG.TWOPI,false);}
39
+ co.stroke();co.strokeStyle=color;for(var i=0;i<360;i+=(360/spokes)){co.beginPath();co.arc(this.centerx,this.centery,this.radius,(i/360)*RG.TWOPI,((i+0.001)/360)*RG.TWOPI,false);co.lineTo(this.centerx,this.centery);co.stroke();}}else if(prop['chart.background.circles']&&poly==true){co.strokeStyle=color;var increment=360/this.data[0].length
40
+ for(var i=0;i<360;i+=increment){co.beginPath();co.arc(this.centerx,this.centery,this.radius,((i/360)*RG.TWOPI)-RG.HALFPI,(((i+0.001)/360)*RG.TWOPI)-RG.HALFPI,false);co.lineTo(this.centerx,this.centery);co.stroke();}
41
+ co.strokeStyle=color;var numrings=typeof(prop['chart.background.circles.count'])=='number'?prop['chart.background.circles.count']:prop['chart.labels.count'];for(var r=0;r<=this.radius;r+=(this.radius/numrings)){co.beginPath();for(var a=0;a<=360;a+=(360/this.data[0].length)){co.arc(this.centerx,this.centery,r,RG.degrees2Radians(a)-RG.HALFPI,RG.degrees2Radians(a)+0.001-RG.HALFPI,false);}
42
+ co.closePath();co.stroke();}}};this.drawAxes=this.DrawAxes=function()
43
+ {co.strokeStyle=prop['chart.axes.color'];var halfsize=this.radius;co.beginPath();co.moveTo(Math.round(this.centerx),this.centery+this.radius);co.lineTo(Math.round(this.centerx),this.centery-this.radius);co.moveTo(this.centerx-5,Math.round(this.centery+this.radius));co.lineTo(this.centerx+5,Math.round(this.centery+this.radius));co.moveTo(this.centerx-5,Math.round(this.centery-this.radius));co.lineTo(this.centerx+5,Math.round(this.centery-this.radius));for(var y=(this.centery-this.radius);y<(this.centery+this.radius);y+=(this.radius/prop['chart.numyticks'])){co.moveTo(this.centerx-3,Math.round(y));co.lineTo(this.centerx+3,Math.round(y));}
44
+ co.moveTo(this.centerx-this.radius,Math.round(this.centery));co.lineTo(this.centerx+this.radius,Math.round(this.centery));co.moveTo(Math.round(this.centerx-this.radius),this.centery-5);co.lineTo(Math.round(this.centerx-this.radius),this.centery+5);co.moveTo(Math.round(this.centerx+this.radius),this.centery-5);co.lineTo(Math.round(this.centerx+this.radius),this.centery+5);for(var x=(this.centerx-this.radius);x<(this.centerx+this.radius);x+=(this.radius/prop['chart.numxticks'])){co.moveTo(Math.round(x),this.centery-3);co.lineTo(Math.round(x),this.centery+3);}
45
+ co.stroke();};this.drawChart=this.DrawChart=function()
46
+ {var alpha=prop['chart.colors.alpha'];if(typeof(alpha)=='number'){var oldAlpha=co.globalAlpha;co.globalAlpha=alpha;}
47
+ var numDatasets=this.data.length;for(var dataset=0;dataset<this.data.length;++dataset){co.beginPath();var coords_dataset=[];for(var i=0;i<this.data[dataset].length;++i){var coords=this.GetCoordinates(dataset,i);if(coords_dataset==null){coords_dataset=[];}
48
+ coords_dataset.push(coords);this.coords.push(coords);}
49
+ this.coords2[dataset]=coords_dataset;co.strokeStyle=(typeof(prop['chart.strokestyle'])=='object'&&prop['chart.strokestyle'][dataset])?prop['chart.strokestyle'][dataset]:prop['chart.strokestyle'];co.fillStyle=prop['chart.colors'][dataset]?prop['chart.colors'][dataset]:'rgba(0,0,0,0)';if(co.fillStyle==='transparent'){co.fillStyle='rgba(0,0,0,0)';}
50
+ co.lineWidth=prop['chart.linewidth'];for(i=0;i<coords_dataset.length;++i){if(i==0){co.moveTo(coords_dataset[i][0],coords_dataset[i][1]);}else{co.lineTo(coords_dataset[i][0],coords_dataset[i][1]);}}
51
+ if(prop['chart.accumulative']&&dataset>0){co.lineTo(coords_dataset[0][0],coords_dataset[0][1]);co.moveTo(last_coords[0][0],last_coords[0][1]);for(var i=coords_dataset.length-1;i>=0;--i){co.lineTo(last_coords[i][0],last_coords[i][1]);}}
52
+ var last_coords=coords_dataset;co.closePath();co.stroke();co.fill();}
53
+ if(typeof(alpha)=='number'){co.globalAlpha=oldAlpha;}};this.getCoordinates=this.GetCoordinates=function(dataset,index)
54
+ {var len=this.data[dataset].length;var mag=(this.data[dataset][index]/this.max)*this.radius;var angle=(RG.TWOPI/len)*index;angle-=RG.HALFPI;var x=Math.cos(angle)*mag;var y=Math.sin(angle)*mag;x=this.centerx+x;y=this.centery+y;return[x,y];};this.drawLabels=this.DrawLabels=function()
55
+ {var labels=prop['chart.labels'];if(labels&&labels.length>0){co.lineWidth=1;co.strokeStyle='gray';co.fillStyle=prop['chart.labels.color']||prop['chart.text.color'];var bgFill=prop['chart.labels.background.fill'],bold=prop['chart.labels.bold'],bgBoxed=prop['chart.labels.boxed'],offset=prop['chart.labels.offset'],font=prop['chart.text.font'],size=prop['chart.text.size'],radius=this.radius,color=prop['chart.labels.color']||prop['chart.text.color']
56
+ for(var i=0;i<labels.length;++i){var angle=(RG.TWOPI/prop['chart.labels'].length)*i;angle-=RG.HALFPI;var x=this.centerx+(ma.cos(angle)*(radius+offset));var y=this.centery+(ma.sin(angle)*(radius+offset));var halign=x<this.centerx?'right':'left';if(i==0||(i/labels.length)==0.5)halign='center';if(labels[i]&&labels[i].length){RG.text2(this,{'color':color,'font':font,'size':size,'x':x,'y':y,'text':labels[i],'valign':'center','halign':halign,'bounding':bgBoxed,'boundingFill':bgFill,'bold':bold,'tag':'labels'});}}}};this.drawCircle=this.DrawCircle=function()
57
+ {var circle={};circle.limit=prop['chart.circle'];circle.fill=prop['chart.circle.fill'];circle.stroke=prop['chart.circle.stroke'];if(circle.limit){var r=(circle.limit/this.max)*this.radius;co.fillStyle=circle.fill;co.strokeStyle=circle.stroke;co.beginPath();co.arc(this.centerx,this.centery,r,0,RG.TWOPI,0);co.fill();co.stroke();}};this.drawAxisLabels=this.DrawAxisLabels=function()
58
+ {if(RG.isArray(prop['chart.labels.specific'])&&prop['chart.labels.specific'].length){this.drawSpecificAxisLabels();return;}
59
+ co.lineWidth=1;co.fillStyle='black';co.strokeStyle='black';var r=this.radius,font=prop['chart.text.font'],size=typeof(prop['chart.text.size.scale'])=='number'?prop['chart.text.size.scale']:prop['chart.text.size'],axes=prop['chart.labels.axes'].toLowerCase(),color=prop['chart.labels.axes.boxed.background'],drawzero=false,units_pre=prop['chart.units.pre'],units_post=prop['chart.units.post'],decimals=prop['chart.scale.decimals'],bold=prop['chart.labels.axes.bold'],boxed=prop['chart.labels.axes.boxed'],centerx=this.centerx,centery=this.centery,scale=this.scale;co.fillStyle=prop['chart.text.color'];if(axes.indexOf('n')>-1){for(var i=0;i<this.scale2.labels.length;++i){RG.Text2(this,{'bold':bold[i],'font':font,'size':size,'x':centerx,'y':centery-(r*((i+1)/this.scale2.labels.length)),'text':this.scale2.labels[i],'valign':'center','halign':'center','bounding':boxed[i]||color,'boundingFill':color,'boundingStroke':'rgba(0,0,0,0)','tag':'scale'});}
60
+ drawzero=true;}
61
+ if(axes.indexOf('s')>-1){for(var i=0;i<this.scale2.labels.length;++i){RG.Text2(this,{'bold':bold[i],'font':font,'size':size,'x':centerx,'y':centery+(r*((i+1)/this.scale2.labels.length)),'text':this.scale2.labels[i],'valign':'center','halign':'center','bounding':boxed[i]||color,'boundingFill':color,'boundingStroke':'rgba(0,0,0,0)','tag':'scale'});}
62
+ drawzero=true;}
63
+ if(axes.indexOf('e')>-1){for(var i=0;i<this.scale2.labels.length;++i){RG.Text2(this,{'bold':bold[i],'font':font,'size':size,'x':centerx+(r*((i+1)/this.scale2.labels.length)),'y':centery,'text':this.scale2.labels[i],'valign':'center','halign':'center','bounding':boxed[i]||color,'boundingFill':color,'boundingStroke':'rgba(0,0,0,0)','tag':'scale'});}
64
+ drawzero=true;}
65
+ if(axes.indexOf('w')>-1){for(var i=0;i<this.scale2.labels.length;++i){RG.Text2(this,{'bold':bold[i],'font':font,'size':size,'x':centerx-(r*((i+1)/this.scale2.labels.length)),'y':centery,'text':this.scale2.labels[i],'valign':'center','halign':'center','bounding':boxed[i]||color,'boundingFill':color,'boundingStroke':'rgba(0,0,0,0)','tag':'scale'});}
66
+ drawzero=true;}
67
+ if(drawzero){RG.Text2(this,{font:font,size:size,x:centerx,y:centery,text:RG.numberFormat(this,Number(0).toFixed(),units_pre,units_post),valign:'center',halign:'center',bounding:prop['chart.labels.axes.boxed.zero'],boundingFill:color,boundingStroke:'rgba(0,0,0,0)',bold:prop['chart.labels.axes.bold.zero'],tag:'scale'});}};this.drawSpecificAxisLabels=this.DrawSpecificAxisLabels=function()
68
+ {var labels=prop['chart.labels.specific'];var bold=RG.array_pad(prop['chart.labels.axes.bold'],labels.length);var boxed=RG.array_pad(prop['chart.labels.axes.boxed'],labels.length);var reversed_labels=RG.array_reverse(labels);var reversed_bold=RG.array_reverse(bold);var reversed_boxed=RG.array_reverse(boxed);var font=prop['chart.text.font'];var size=typeof(prop['chart.text.size.scale'])=='number'?prop['chart.text.size.scale']:prop['chart.text.size'];var axes=prop['chart.labels.axes'].toLowerCase();co.fillStyle=prop['chart.text.color'];for(var i=0;i<labels.length;++i){if(axes.indexOf('n')>-1)RG.Text2(this,{'tag':'labels.specific','bold':reversed_bold[i],'font':font,'size':size,'x':this.centerx,'y':this.centery-this.radius+((this.radius/labels.length)*i),'text':reversed_labels[i],'valign':'center','halign':'center','bounding':reversed_boxed[i],'boundingFill':'white'});if(axes.indexOf('s')>-1)RG.Text2(this,{'tag':'labels.specific','bold':bold[i],'font':font,'size':size,'x':this.centerx,'y':this.centery+((this.radius/labels.length)*(i+1)),'text':labels[i],'valign':'center','halign':'center','bounding':boxed[i],'boundingFill':'white'});if(axes.indexOf('w')>-1)RG.Text2(this,{'tag':'labels.specific','bold':reversed_bold[i],'font':font,'size':size,'x':this.centerx-this.radius+((this.radius/labels.length)*i),'y':this.centery,'text':reversed_labels[i],'valign':'center','halign':'center','bounding':reversed_boxed[i],'boundingFill':'white'});if(axes.indexOf('e')>-1)RG.Text2(this,{'tag':'labels.specific','bold':bold[i],'font':font,'size':size,'x':this.centerx+((this.radius/labels.length)*(i+1)),'y':this.centery,'text':labels[i],'valign':'center','halign':'center','bounding':boxed[i],'boundingFill':'white'});}};this.getShape=this.getPoint=function(e)
69
+ {for(var i=0;i<this.coords.length;++i){var x=this.coords[i][0];var y=this.coords[i][1];var tooltips=prop['chart.tooltips'];var index=Number(i);var mouseXY=RG.getMouseXY(e);var mouseX=mouseXY[0];var mouseY=mouseXY[1];if(mouseX<(x+5)&&mouseX>(x-5)&&mouseY>(y-5)&&mouseY<(y+5)){var tooltip=RG.parseTooltipText(prop['chart.tooltips'],index);return{0:this,'object':this,1:x,'x':x,2:y,'y':y,3:null,'dataset':null,4:index,'index':i,'tooltip':tooltip}}}};this.highlight=this.Highlight=function(shape)
70
+ {if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else{RG.Highlight.Point(this,shape);}};this.getObjectByXY=function(e)
71
+ {var mouseXY=RG.getMouseXY(e);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)){return this;}};this.drawHighlights=this.DrawHighlights=function()
72
+ {if(prop['chart.highlights']){var sequentialIdx=0;var dataset=0;var index=0;var radius=prop['chart.highlights.radius'];for(var dataset=0;dataset<this.data.length;++dataset){for(var index=0;index<this.data[dataset].length;++index){co.beginPath();co.strokeStyle=prop['chart.highlights.stroke'];co.fillStyle=prop['chart.highlights.fill']?prop['chart.highlights.fill']:((typeof(prop['chart.strokestyle'])=='object'&&prop['chart.strokestyle'][dataset])?prop['chart.strokestyle'][dataset]:prop['chart.strokestyle']);co.arc(this.coords[sequentialIdx][0],this.coords[sequentialIdx][1],radius,0,RG.TWOPI,false);co.stroke();co.fill();++sequentialIdx;}}}};this.getRadius=function(value)
73
+ {if(value<0||value>this.max){return null;}
74
+ var radius=(value/this.max)*this.radius;return radius;};this.getAngle=function(numitems,index)
75
+ {var angle=(RG.TWOPI/numitems)*index;angle-=RG.HALFPI;return angle;};this.parseColors=function()
76
+ {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.title.color']=RG.array_clone(prop['chart.title.color']);this.original_colors['chart.text.color']=RG.array_clone(prop['chart.text.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']);this.original_colors['chart.circle.fill']=RG.array_clone(prop['chart.circle.fill']);this.original_colors['chart.circle.stroke']=RG.array_clone(prop['chart.circle.stroke']);}
77
+ for(var i=0;i<prop['chart.colors'].length;++i){prop['chart.colors'][i]=this.parseSingleColorForGradient(prop['chart.colors'][i]);}
78
+ var keyColors=prop['chart.key.colors'];if(typeof(keyColors)!='null'&&keyColors&&keyColors.length){for(var i=0;i<prop['chart.key.colors'].length;++i){prop['chart.key.colors'][i]=this.parseSingleColorForGradient(prop['chart.key.colors'][i]);}}
79
+ prop['chart.title.color']=this.parseSingleColorForGradient(prop['chart.title.color']);prop['chart.text.color']=this.parseSingleColorForGradient(prop['chart.text.color']);prop['chart.highlight.stroke']=this.parseSingleColorForGradient(prop['chart.highlight.stroke']);prop['chart.highlight.fill']=this.parseSingleColorForGradient(prop['chart.highlight.fill']);prop['chart.circle.fill']=this.parseSingleColorForGradient(prop['chart.circle.fill']);prop['chart.circle.stroke']=this.parseSingleColorForGradient(prop['chart.circle.stroke']);};this.reset=function()
80
+ {};this.parseSingleColorForGradient=function(color)
81
+ {if(!color||typeof(color)!='string'){return color;}
82
+ 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]));}}
83
+ return grad?grad:color;};this.addFillListeners=this.AddFillListeners=function(e)
84
+ {var obj=this;var func=function(e)
85
+ {var coords=this.coords;var coords2=this.coords2;var mouseXY=RG.getMouseXY(e);var dataset=0;if(e.type=='mousemove'&&prop['chart.fill.mousemove.redraw']){RG.RedrawCanvas(ca);}
86
+ for(var dataset=(obj.coords2.length-1);dataset>=0;--dataset){co.beginPath();co.moveTo(obj.coords2[dataset][0][0],obj.coords2[dataset][0][1]);for(var j=0;j<obj.coords2[dataset].length;++j){co.lineTo(obj.coords2[dataset][j][0],obj.coords2[dataset][j][1]);}
87
+ co.lineTo(obj.coords2[dataset][0][0],obj.coords2[dataset][0][1]);if(prop['chart.accumulative']&&dataset>0){co.lineTo(obj.coords2[dataset-1][0][0],obj.coords2[dataset-1][0][1]);for(var j=(obj.coords2[dataset-1].length-1);j>=0;--j){co.lineTo(obj.coords2[dataset-1][j][0],obj.coords2[dataset-1][j][1]);}}
88
+ co.closePath();if(co.isPointInPath(mouseXY[0],mouseXY[1])){var inPath=true;break;}}
89
+ if(inPath){var fillTooltips=prop['chart.fill.tooltips'];if(e.type=='click'){if(prop['chart.fill.click']){prop['chart.fill.click'](e,dataset);}
90
+ if(prop['chart.fill.tooltips']&&prop['chart.fill.tooltips'][dataset]){obj.DatasetTooltip(e,dataset);}}
91
+ if(e.type=='mousemove'){if(prop['chart.fill.mousemove']){prop['chart.fill.mousemove'](e,dataset);}
92
+ if(!RG.is_null(fillTooltips)){e.target.style.cursor='pointer';}
93
+ if(prop['chart.fill.tooltips']&&prop['chart.fill.tooltips'][dataset]){e.target.style.cursor='pointer';}}
94
+ e.stopPropagation();}else if(e.type=='mousemove'){ca.style.cursor='default';}};if(prop['chart.fill.click']||!RG.is_null(prop['chart.fill.tooltips'])){ca.addEventListener('click',func,false);}
95
+ if(prop['chart.fill.mousemove']||!RG.is_null(prop['chart.fill.tooltips'])){ca.addEventListener('mousemove',func,false);}};this.highlightDataset=this.HighlightDataset=function(dataset)
96
+ {co.beginPath();for(var j=0;j<this.coords2[dataset].length;++j){if(j==0){co.moveTo(this.coords2[dataset][0][0],this.coords2[dataset][0][1]);}else{co.lineTo(this.coords2[dataset][j][0],this.coords2[dataset][j][1]);}}
97
+ co.lineTo(this.coords2[dataset][0][0],this.coords2[dataset][0][1]);if(prop['chart.accumulative']&&dataset>0){co.lineTo(this.coords2[dataset-1][0][0],this.coords2[dataset-1][0][1]);for(var j=(this.coords2[dataset-1].length-1);j>=0;--j){co.lineTo(this.coords2[dataset-1][j][0],this.coords2[dataset-1][j][1]);}}
98
+ co.strokeStyle=prop['chart.fill.highlight.stroke'];co.fillStyle=prop['chart.fill.highlight.fill'];co.stroke();co.fill();};this.datasetTooltip=this.DatasetTooltip=function(e,dataset)
99
+ {this.HighlightDataset(dataset);var text=prop['chart.fill.tooltips'][dataset];var x=0;var y=this.coords2[dataset][0][1]+RG.getCanvasXY(ca)[1];RG.Tooltip(this,text,x,y,0,e);};this.interactiveKeyHighlight=function(index)
100
+ {var coords=this.coords2[index];if(coords){var pre_linewidth=co.lineWidth;var pre_linecap=co.lineCap;co.lineWidth=prop['chart.linewidth']+10;co.lineCap='round';co.strokeStyle=prop['chart.key.interactive.highlight.chart.stroke'];co.beginPath();for(var i=0,len=coords.length;i<len;i+=1){if(i==0){co.moveTo(coords[i][0],coords[i][1]);}else{co.lineTo(coords[i][0],coords[i][1]);}}
101
+ co.closePath();co.stroke();co.lineWidth=pre_linewidth;co.lineCap=pre_linecap;}};this.on=function(type,func)
102
+ {if(type.substr(0,2)!=='on'){type='on'+type;}
103
+ if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
104
+ return this;};this.firstDrawFunc=function()
105
+ {};this.grow=function()
106
+ {var obj=this;var callback=arguments[1]?arguments[1]:function(){};var opt=arguments[0]?arguments[0]:{};var frames=opt.frames?opt.frames:30;var frame=0;var data=RG.array_clone(obj.data);function iterator()
107
+ {for(var i=0,len=data.length;i<len;++i){for(var j=0,len2=data[i].length;j<len2;++j){obj.original_data[i][j]=(frame/frames)*data[i][j];}}
108
+ RGraph.clear(obj.canvas);RGraph.redrawCanvas(obj.canvas);if(frame<frames){frame++;RGraph.Effects.updateCanvas(iterator);}else{callback(obj);}}
109
+ iterator();return this;};this.trace=function()
110
+ {var obj=this;var opt=arguments[0]||{};var frames=opt.frames||60;var frame=0;var callback=arguments[1]||function(){};obj.Set('animation.trace.clip',0);var iterator=function()
111
+ {if(frame<frames){obj.Set('animation.trace.clip',frame/frames);frame++;RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iterator);}else{obj.Set('animation.trace.clip',1);RG.redrawCanvas(obj.canvas);callback(obj);}};iterator();return this;};RG.att(ca);RG.Register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}};