rgraph-rails 1.0.5 → 1.0.6

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 +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
- };