rgraph-rails 4.62 → 4.64

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +3 -4
  3. data/lib/rgraph-rails/version.rb +1 -1
  4. data/vendor/assets/javascripts/RGraph.bar.js +240 -3742
  5. data/vendor/assets/javascripts/RGraph.bipolar.js +165 -2005
  6. data/vendor/assets/javascripts/RGraph.common.annotate.js +35 -395
  7. data/vendor/assets/javascripts/RGraph.common.context.js +30 -595
  8. data/vendor/assets/javascripts/RGraph.common.core.js +418 -5359
  9. data/vendor/assets/javascripts/RGraph.common.csv.js +20 -276
  10. data/vendor/assets/javascripts/RGraph.common.deprecated.js +35 -450
  11. data/vendor/assets/javascripts/RGraph.common.dynamic.js +88 -1395
  12. data/vendor/assets/javascripts/RGraph.common.effects.js +90 -1545
  13. data/vendor/assets/javascripts/RGraph.common.key.js +52 -753
  14. data/vendor/assets/javascripts/RGraph.common.resizing.js +37 -563
  15. data/vendor/assets/javascripts/RGraph.common.sheets.js +29 -352
  16. data/vendor/assets/javascripts/RGraph.common.tooltips.js +32 -450
  17. data/vendor/assets/javascripts/RGraph.common.zoom.js +14 -219
  18. data/vendor/assets/javascripts/RGraph.cornergauge.js +71 -0
  19. data/vendor/assets/javascripts/RGraph.drawing.background.js +34 -570
  20. data/vendor/assets/javascripts/RGraph.drawing.circle.js +33 -544
  21. data/vendor/assets/javascripts/RGraph.drawing.image.js +51 -755
  22. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +37 -645
  23. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +36 -633
  24. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +35 -514
  25. data/vendor/assets/javascripts/RGraph.drawing.poly.js +37 -559
  26. data/vendor/assets/javascripts/RGraph.drawing.rect.js +33 -548
  27. data/vendor/assets/javascripts/RGraph.drawing.text.js +36 -664
  28. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +50 -812
  29. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +51 -856
  30. data/vendor/assets/javascripts/RGraph.fuel.js +58 -964
  31. data/vendor/assets/javascripts/RGraph.funnel.js +55 -984
  32. data/vendor/assets/javascripts/RGraph.gantt.js +77 -1354
  33. data/vendor/assets/javascripts/RGraph.gauge.js +85 -1421
  34. data/vendor/assets/javascripts/RGraph.hbar.js +162 -2788
  35. data/vendor/assets/javascripts/RGraph.hprogress.js +80 -1401
  36. data/vendor/assets/javascripts/RGraph.line.js +249 -4248
  37. data/vendor/assets/javascripts/RGraph.meter.js +74 -1280
  38. data/vendor/assets/javascripts/RGraph.modaldialog.js +19 -301
  39. data/vendor/assets/javascripts/RGraph.odo.js +71 -1264
  40. data/vendor/assets/javascripts/RGraph.pie.js +137 -2288
  41. data/vendor/assets/javascripts/RGraph.radar.js +110 -1847
  42. data/vendor/assets/javascripts/RGraph.rose.js +108 -1977
  43. data/vendor/assets/javascripts/RGraph.rscatter.js +80 -1432
  44. data/vendor/assets/javascripts/RGraph.scatter.js +172 -3163
  45. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +60 -1120
  46. data/vendor/assets/javascripts/RGraph.svg.bar.js +66 -1735
  47. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +21 -246
  48. data/vendor/assets/javascripts/RGraph.svg.common.core.js +255 -3937
  49. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +20 -276
  50. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +68 -1303
  51. data/vendor/assets/javascripts/RGraph.svg.common.key.js +19 -205
  52. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +29 -352
  53. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +22 -273
  54. data/vendor/assets/javascripts/RGraph.svg.funnel.js +32 -0
  55. data/vendor/assets/javascripts/RGraph.svg.hbar.js +59 -1400
  56. data/vendor/assets/javascripts/RGraph.svg.line.js +70 -1580
  57. data/vendor/assets/javascripts/RGraph.svg.pie.js +55 -1131
  58. data/vendor/assets/javascripts/RGraph.svg.radar.js +57 -1502
  59. data/vendor/assets/javascripts/RGraph.svg.rose.js +66 -1817
  60. data/vendor/assets/javascripts/RGraph.svg.scatter.js +58 -1261
  61. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +28 -865
  62. data/vendor/assets/javascripts/RGraph.svg.waterfall.js +45 -1252
  63. data/vendor/assets/javascripts/RGraph.thermometer.js +63 -1136
  64. data/vendor/assets/javascripts/RGraph.vprogress.js +83 -1470
  65. data/vendor/assets/javascripts/RGraph.waterfall.js +83 -1347
  66. metadata +5 -4
  67. data/vendor/assets/javascripts/financial-data.js +0 -1067
@@ -1,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);}};