rgraph-rails 1.0.5 → 1.0.6

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