rgraph-rails 1.0.7 → 1.0.8

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/lib/rgraph-rails/version.rb +1 -1
  4. data/license.txt +4 -16
  5. data/vendor/assets/javascripts/RGraph.bar.js +3734 -241
  6. data/vendor/assets/javascripts/RGraph.bipolar.js +2005 -115
  7. data/vendor/assets/javascripts/RGraph.common.annotate.js +395 -35
  8. data/vendor/assets/javascripts/RGraph.common.context.js +595 -30
  9. data/vendor/assets/javascripts/RGraph.common.core.js +5282 -405
  10. data/vendor/assets/javascripts/RGraph.common.csv.js +276 -19
  11. data/vendor/assets/javascripts/RGraph.common.deprecated.js +450 -35
  12. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1395 -86
  13. data/vendor/assets/javascripts/RGraph.common.effects.js +1545 -90
  14. data/vendor/assets/javascripts/RGraph.common.key.js +753 -54
  15. data/vendor/assets/javascripts/RGraph.common.resizing.js +563 -37
  16. data/vendor/assets/javascripts/RGraph.common.sheets.js +352 -29
  17. data/vendor/assets/javascripts/RGraph.common.tooltips.js +450 -32
  18. data/vendor/assets/javascripts/RGraph.common.zoom.js +219 -14
  19. data/vendor/assets/javascripts/RGraph.drawing.background.js +570 -35
  20. data/vendor/assets/javascripts/RGraph.drawing.circle.js +544 -35
  21. data/vendor/assets/javascripts/RGraph.drawing.image.js +755 -52
  22. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +645 -41
  23. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +633 -37
  24. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +514 -36
  25. data/vendor/assets/javascripts/RGraph.drawing.poly.js +559 -39
  26. data/vendor/assets/javascripts/RGraph.drawing.rect.js +548 -35
  27. data/vendor/assets/javascripts/RGraph.drawing.text.js +664 -36
  28. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +812 -50
  29. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +856 -51
  30. data/vendor/assets/javascripts/RGraph.fuel.js +964 -58
  31. data/vendor/assets/javascripts/RGraph.funnel.js +984 -55
  32. data/vendor/assets/javascripts/RGraph.gantt.js +1354 -77
  33. data/vendor/assets/javascripts/RGraph.gauge.js +1421 -87
  34. data/vendor/assets/javascripts/RGraph.hbar.js +2562 -146
  35. data/vendor/assets/javascripts/RGraph.hprogress.js +1401 -80
  36. data/vendor/assets/javascripts/RGraph.line.js +4226 -244
  37. data/vendor/assets/javascripts/RGraph.meter.js +1280 -74
  38. data/vendor/assets/javascripts/RGraph.modaldialog.js +301 -19
  39. data/vendor/assets/javascripts/RGraph.odo.js +1264 -71
  40. data/vendor/assets/javascripts/RGraph.pie.js +2288 -137
  41. data/vendor/assets/javascripts/RGraph.radar.js +1847 -110
  42. data/vendor/assets/javascripts/RGraph.rose.js +1977 -108
  43. data/vendor/assets/javascripts/RGraph.rscatter.js +1432 -80
  44. data/vendor/assets/javascripts/RGraph.scatter.js +3036 -168
  45. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1120 -60
  46. data/vendor/assets/javascripts/RGraph.svg.bar.js +1067 -0
  47. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +247 -0
  48. data/vendor/assets/javascripts/RGraph.svg.common.core.js +3363 -0
  49. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +277 -0
  50. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +1304 -0
  51. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +353 -0
  52. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +233 -0
  53. data/vendor/assets/javascripts/RGraph.svg.hbar.js +1141 -0
  54. data/vendor/assets/javascripts/RGraph.svg.line.js +1486 -0
  55. data/vendor/assets/javascripts/RGraph.svg.pie.js +781 -0
  56. data/vendor/assets/javascripts/RGraph.svg.radar.js +1326 -0
  57. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +817 -0
  58. data/vendor/assets/javascripts/RGraph.thermometer.js +1135 -62
  59. data/vendor/assets/javascripts/RGraph.vprogress.js +1470 -83
  60. data/vendor/assets/javascripts/RGraph.waterfall.js +1347 -80
  61. metadata +15 -3
@@ -0,0 +1,1326 @@
1
+ // version: 2017-01-02
2
+ /**
3
+ * o--------------------------------------------------------------------------------o
4
+ * | This file is part of the RGraph package - you can learn more at: |
5
+ * | |
6
+ * | http://www.rgraph.net |
7
+ * | |
8
+ * | RGraph is licensed under the Open Source MIT license. That means that it's |
9
+ * | totally free to use! |
10
+ * o--------------------------------------------------------------------------------o
11
+ */
12
+
13
+ RGraph = window.RGraph || {isRGraph: true};
14
+ RGraph.SVG = RGraph.SVG || {};
15
+
16
+ // Module pattern
17
+ (function (win, doc, undefined)
18
+ {
19
+ var RG = RGraph,
20
+ ua = navigator.userAgent,
21
+ ma = Math,
22
+ win = window,
23
+ doc = document;
24
+
25
+
26
+
27
+ RG.SVG.Radar = function (conf)
28
+ {
29
+ this.id = conf.id;
30
+ this.uid = RG.SVG.createUID();
31
+ this.container = document.getElementById(this.id);
32
+ this.svg = RG.SVG.createSVG({container: this.container});
33
+ this.isRGraph = true;
34
+ this.width = Number(this.svg.getAttribute('width'));
35
+ this.height = Number(this.svg.getAttribute('height'));
36
+ this.data = RG.SVG.arrayClone(conf.data);
37
+ this.originalData = RG.SVG.arrayClone(conf.data);
38
+ this.type = 'radar';
39
+ this.coords = [];
40
+ this.coords2 = [];
41
+ this.angles = [];
42
+ this.angles2 = [];
43
+ this.colorsParsed = false;
44
+ this.originalColors = {};
45
+ this.gradientCounter = 1;
46
+ this.nodes = [];
47
+ this.shadowNodes = [];
48
+ this.max = 0;
49
+ this.redraw = false;
50
+ this.highlight_hotspot = null;
51
+
52
+ // Add this object to the ObjectRegistry
53
+ RG.SVG.OR.add(this);
54
+
55
+ // Set the DIV container to be inline-block
56
+ this.container.style.display = 'inline-block';
57
+
58
+
59
+
60
+
61
+
62
+ this.properties =
63
+ {
64
+ centerx: null,
65
+ centery: null,
66
+ radius: null,
67
+
68
+ gutterLeft: 35,
69
+ gutterRight: 35,
70
+ gutterTop: 35,
71
+ gutterBottom: 35,
72
+
73
+ backgroundGrid: true,
74
+ backgroundGridColor: '#ddd',
75
+ backgroundGridRadialsCount: null,
76
+ backgroundGridConcentricsCount: 5,
77
+ backgroundGridLinewidth: 1,
78
+
79
+ colors: [
80
+ 'red', 'black', 'orange', 'green', '#6ff', '#ccc',
81
+ 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal'
82
+ ],
83
+ filled: false,
84
+ filledOpacity: 0.25,
85
+ filledAccumulative: true,
86
+
87
+ textColor: 'black',
88
+ textFont: 'sans-serif',
89
+ textSize: 12,
90
+ textBold: false,
91
+ textItalic: false,
92
+
93
+ labels: [],
94
+
95
+ scaleVisible: true,
96
+ scaleUnitsPre: '',
97
+ scaleUnitsPost: '',
98
+ scaleMax: null,
99
+ scaleMin: 0,
100
+ scalePoint: '.',
101
+ scaleThousand: ',',
102
+ scaleRound: false,
103
+ scaleDecimals: 0,
104
+ scaleFormatter: null,
105
+ scaleBold: null,
106
+ scaleItalic: null,
107
+ scaleColor: null,
108
+ scaleSize: null,
109
+ scaleFont: null,
110
+ scaleLabelsCount: 5,
111
+
112
+ linewidth: 1,
113
+
114
+ tooltips: null,
115
+ tooltipsOverride: null,
116
+ tooltipsEffect: 'fade',
117
+ tooltipsCssClass: 'RGraph_tooltip',
118
+ tooltipsEvent: 'mousemove',
119
+
120
+ highlightStroke: 'rgba(0,0,0,0)',
121
+ highlightFill: 'rgba(255,255,255,0.7)',
122
+ highlightLinewidth: 1,
123
+
124
+ tickmarks: 'circle',
125
+ tickmarksLinewidth: 1,
126
+ tickmarksSize: 6,
127
+ tickmarksFill: 'white',
128
+
129
+ title: '',
130
+ titleSize: 16,
131
+ titleX: null,
132
+ titleY: null,
133
+ titleHalign: 'center',
134
+ titleValign: 'bottom',
135
+ titleColor: 'black',
136
+ titleFont: null,
137
+ titleBold: false,
138
+ titleItalic: false,
139
+
140
+ titleSubtitle: '',
141
+ titleSubtitleSize: 10,
142
+ titleSubtitleX: null,
143
+ titleSubtitleY: null,
144
+ titleSubtitleHalign: 'center',
145
+ titleSubtitleValign: 'top',
146
+ titleSubtitleColor: '#aaa',
147
+ titleSubtitleFont: null,
148
+ titleSubtitleBold: false,
149
+ titleSubtitleItalic: false,
150
+
151
+ grouping: 'normal', // Can also be stcked
152
+
153
+ shadow: false,
154
+ shadowOffsetx: 2,
155
+ shadowOffsety: 2,
156
+ shadowBlur: 2,
157
+ shadowOpacity: 0.25,
158
+
159
+ attribution: true,
160
+ attributionX: null,
161
+ attributionY: null,
162
+ attributionHref: 'http://www.rgraph.net/svg/index.html',
163
+ attributionHalign: 'right',
164
+ attributionValign: 'bottom',
165
+ attributionSize: 8,
166
+ attributionColor: 'gray',
167
+ attributionFont: 'sans-serif',
168
+ attributionItalic: false,
169
+ attributionBold: false
170
+ };
171
+
172
+
173
+
174
+
175
+
176
+
177
+ /**
178
+ * "Decorate" the object with the generic effects if the effects library has been included
179
+ */
180
+ if (RG.SVG.FX && typeof RG.SVG.FX.decorate === 'function') {
181
+ RG.SVG.FX.decorate(this);
182
+ }
183
+
184
+
185
+
186
+
187
+ var prop = this.properties;
188
+
189
+
190
+
191
+
192
+ //
193
+ // A setter that the constructor uses (at the end)
194
+ // to set all of the properties
195
+ //
196
+ // @param string name The name of the property to set
197
+ // @param string value The value to set the property to
198
+ //
199
+ this.set = function (name, value)
200
+ {
201
+ if (arguments.length === 1 && typeof name === 'object') {
202
+ for (i in arguments[0]) {
203
+ if (typeof i === 'string') {
204
+ this.set(i, arguments[0][i]);
205
+ }
206
+ }
207
+ } else {
208
+ this.properties[name] = value;
209
+ }
210
+
211
+ return this;
212
+ };
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+ //
222
+ // The draw method draws the Bar chart
223
+ //
224
+ this.draw = function ()
225
+ {
226
+ // Fire the beforedraw event
227
+ RG.SVG.fireCustomEvent(this, 'onbeforedraw');
228
+
229
+
230
+
231
+ // Reset the data back to the original values
232
+ this.data = RG.SVG.arrayClone(this.originalData);
233
+
234
+ //
235
+ // The datasets have to have the same number of elements
236
+ //
237
+ if (this.data.length > 1) {
238
+
239
+ var len = this.data[0].length;
240
+
241
+ for (var i=1; i<this.data.length; ++i) {
242
+ if (this.data[i].length !== len) {
243
+ alert('[ERROR] The Radar chart datasets must have the same number of elements!');
244
+ }
245
+ }
246
+ }
247
+
248
+
249
+
250
+ // Reset the coords array to stop them growing
251
+ this.angles = [];
252
+ this.coords = [];
253
+ this.coords2 = [];
254
+
255
+
256
+
257
+
258
+
259
+ // Create the defs tag if necessary
260
+ RG.SVG.createDefs(this);
261
+
262
+
263
+
264
+
265
+ this.graphWidth = this.width - prop.gutterLeft - prop.gutterRight;
266
+ this.graphHeight = this.height - prop.gutterTop - prop.gutterBottom;
267
+
268
+
269
+
270
+ // Work out the center point
271
+ this.centerx = (this.graphWidth / 2) + prop.gutterLeft;
272
+ this.centery = (this.graphHeight / 2) + prop.gutterTop;
273
+ this.radius = ma.min(this.graphWidth, this.graphHeight) / 2;
274
+
275
+
276
+
277
+ // Allow the user to override the calculated centerx/y/radius
278
+ this.centerx = typeof prop.centerx === 'number' ? prop.centerx : this.centerx;
279
+ this.centery = typeof prop.centery === 'number' ? prop.centery : this.centery;
280
+ this.radius = typeof prop.radius === 'number' ? prop.radius : this.radius;
281
+
282
+ //
283
+ // Allow the centerx/centery/radius to be a plus/minus
284
+ //
285
+ if (typeof prop.radius === 'string' && prop.radius.match(/^\+|-\d+$/) ) this.radius += parseFloat(prop.radius);
286
+ if (typeof prop.centerx === 'string' && prop.centerx.match(/^\+|-\d+$/) ) this.centery += parseFloat(prop.centerx);
287
+ if (typeof prop.centery === 'string' && prop.centery.match(/^\+|-\d+$/) ) this.centerx += parseFloat(prop.centery);
288
+
289
+
290
+
291
+
292
+
293
+ /**
294
+ * Add the data to the .originalData array and work out the max value
295
+ *
296
+ * 2/5/14 Now also use this loop to ensure that the data pieces
297
+ * are numbers
298
+ */
299
+ if (RG.SVG.isArray(this.data) && (typeof this.data[0] === 'number' || typeof this.data[0] === 'string')) {
300
+ this.data = [this.data];
301
+ }
302
+
303
+ // Convert strings to numbers
304
+ for (var i=0; i<this.data.length; ++i) {
305
+
306
+ for (var j=0; j<this.data[i].length; ++j) {
307
+
308
+ if (typeof this.data[i][j] === 'string') {
309
+ this.data[i][j] = RG.SVG.stringsToNumbers(this.data[i][j]);
310
+ }
311
+ }
312
+ }
313
+
314
+
315
+
316
+
317
+
318
+
319
+ // Modify the datasets to represent the stacked data
320
+ // (if its stacked)
321
+ if (prop.filled && prop.filledAccumulative) {
322
+ for (var dataset=1; dataset<this.data.length; ++dataset) {
323
+ for (var i=0; i<this.data[dataset].length; ++i) {
324
+ this.data[dataset][i] += this.data[dataset - 1][i];
325
+ }
326
+ }
327
+ }
328
+
329
+
330
+
331
+
332
+
333
+ // Get the max value
334
+ this.getMaxValue();
335
+
336
+
337
+
338
+
339
+
340
+
341
+
342
+ /**
343
+ * Parse the colors. This allows for simple gradient syntax
344
+ *
345
+ * ** must be after the cx/cy/r has been calcuated **
346
+ */
347
+ if (!this.colorsParsed) {
348
+ this.parseColors();
349
+
350
+ // Don't want to do this again
351
+ this.colorsParsed = true;
352
+ }
353
+
354
+ //
355
+ // Get the scale
356
+ //
357
+
358
+ this.scale = RG.SVG.getScale({
359
+ object: this,
360
+ numlabels: typeof prop.scaleLabelsCount === 'number' ? prop.scaleLabelsCount : prop.backgroundGridConcentricCount,
361
+ unitsPre: prop.scaleUnitsPre,
362
+ unitsPost: prop.scaleUnitsPost,
363
+ max: typeof prop.scaleMax === 'number' ? prop.scaleMax : this.max,
364
+ min: prop.scaleMin,
365
+ point: prop.scalePoint,
366
+ round: prop.scaleRound,
367
+ thousand: prop.scaleThousand,
368
+ decimals: prop.scaleDecimals,
369
+ strict: typeof prop.scaleMax === 'number',
370
+ formatter: prop.scaleFormatter
371
+ });
372
+
373
+ this.max = this.scale.max;
374
+
375
+
376
+
377
+ // Draw the background 'grid'
378
+ this.drawBackground();
379
+
380
+
381
+
382
+ // Draw the chart
383
+ this.drawRadar();
384
+
385
+
386
+
387
+ // Draw the tickmarks for the chart
388
+ this.drawTickmarks();
389
+
390
+
391
+
392
+ // Draw the labels
393
+ this.drawLabels();
394
+
395
+
396
+
397
+ // Draw the title and subtitle
398
+ RG.SVG.drawTitle(this);
399
+
400
+
401
+
402
+ // Add the tooltip hotspots
403
+ this.addTooltipHotspots();
404
+
405
+
406
+
407
+
408
+ // Add the attribution link. If you're adding this elsewhere on your page/site
409
+ // and you don't want it displayed then there are options available to not
410
+ // show it.
411
+ RG.SVG.attribution(this);
412
+
413
+ // Create the shadow definition if needed
414
+ if (prop.shadow) {
415
+ RG.SVG.setShadow({
416
+ object: this,
417
+ offsetx: prop.shadowOffsetx,
418
+ offsety: prop.shadowOffsety,
419
+ blur: prop.shadowBlur,
420
+ opacity: prop.shadowOpacity,
421
+ id: 'dropShadow'
422
+ });
423
+ }
424
+
425
+
426
+
427
+ // Add the event listener that clears the highlight if
428
+ // there is any. Must be MOUSEDOWN (ie before the click event)
429
+ var obj = this;
430
+ document.body.addEventListener('mousedown', function (e)
431
+ {
432
+ RG.SVG.removeHighlight(obj);
433
+ }, false);
434
+
435
+
436
+
437
+ // Fire the draw event
438
+ RG.SVG.fireCustomEvent(this, 'ondraw');
439
+
440
+
441
+
442
+ return this;
443
+ };
444
+
445
+
446
+
447
+
448
+
449
+
450
+
451
+
452
+ //
453
+ // Draw the background grid
454
+ //
455
+ this.drawBackground = function ()
456
+ {
457
+ if (prop.backgroundGrid) {
458
+
459
+ // Create the background grid group tag
460
+ var grid = RG.SVG.create({
461
+ svg: this.svg,
462
+ type: 'g',
463
+ attr: {
464
+ className: 'rgraph_radar_grid',
465
+ fill: 'rgba(0,0,0,0)',
466
+ stroke: prop.backgroundGridColor
467
+ }
468
+ });
469
+
470
+ // Draw the concentric "rings" grid lines that are
471
+ // arranged around the centerx/centery
472
+
473
+ var origin = 0 - (RG.SVG.TRIG.PI / 2),
474
+ radials = (typeof prop.backgroundGridRadialsCount === 'number' ? prop.backgroundGridRadialsCount : this.data[0].length),
475
+ concentrics = prop.backgroundGridConcentricsCount,
476
+ step = RG.SVG.TRIG.TWOPI / radials;
477
+
478
+
479
+
480
+
481
+
482
+ // First draw the radial lines that emanate from the
483
+ // center outwards
484
+ if (radials > 0) {
485
+
486
+ for (var i=0,len=radials; i<len; ++i) {
487
+
488
+ var coords = RG.SVG.TRIG.toCartesian({
489
+ cx: this.centerx,
490
+ cy: this.centery,
491
+ r: this.radius,
492
+ angle: origin + (i * step)
493
+ });
494
+
495
+ var str = 'M {1} {2} L {3} {4}'.format(
496
+ this.centerx,
497
+ this.centery,
498
+ coords.x,
499
+ coords.y
500
+ );
501
+
502
+ RG.SVG.create({
503
+ svg: this.svg,
504
+ type: 'path',
505
+ parent: grid,
506
+ attr: {
507
+ d: str,
508
+ stroke: prop.backgroundGridColor,
509
+ 'stroke-width': prop.backgroundGridLinewidth
510
+ }
511
+ });
512
+ }
513
+ }
514
+
515
+
516
+
517
+
518
+
519
+ // Draw the concentrics
520
+ if (concentrics > 0) {
521
+ for (var j=1; j<=concentrics; j++) {
522
+ for (var i=0,len=radials,path=[]; i<len; ++i) {
523
+
524
+ var coords = RG.SVG.TRIG.toCartesian({
525
+ cx: this.centerx,
526
+ cy: this.centery,
527
+ r: this.radius * (j/concentrics),
528
+ angle: origin + (i * step)
529
+ });
530
+
531
+ path.push('{1} {2} {3}'.format(
532
+ i === 0 ? 'M' : 'L',
533
+ coords.x,
534
+ coords.y
535
+ ));
536
+
537
+ }
538
+
539
+ // Now add the path to the scene
540
+ RG.SVG.create({
541
+ svg: this.svg,
542
+ type: 'path',
543
+ parent: grid,
544
+ attr: {
545
+ d: path.join(' ') + ' z',
546
+ fill: 'transparent',
547
+ stroke: prop.backgroundGridColor,
548
+ 'stroke-width': prop.backgroundGridLinewidth
549
+ }
550
+ });
551
+ }
552
+ }
553
+ }
554
+ };
555
+
556
+
557
+
558
+
559
+
560
+
561
+
562
+
563
+ //
564
+ // Draws the radar
565
+ //
566
+ this.drawRadar = function (opt)
567
+ {
568
+ for (var dataset=0,len=this.data.length; dataset<len; ++dataset) {
569
+
570
+ // Ensure these exist
571
+ this.coords2[dataset] = [];
572
+ this.angles2[dataset] = [];
573
+
574
+ // Initialise the path
575
+ var path = [];
576
+
577
+ for (var i=0,len2=this.data[dataset].length; i<len2; ++i) {
578
+
579
+ var value = this.data[dataset][i];
580
+
581
+ var xy = RG.SVG.TRIG.toCartesian({
582
+ cx: this.centerx,
583
+ cy: this.centery,
584
+ r: this.getRadius(this.data[dataset][i]),
585
+ angle: (RG.SVG.TRIG.TWOPI / len2) * i - RG.SVG.TRIG.HALFPI
586
+ });
587
+
588
+ xy.r = (( (value - prop.scaleMin) / (this.max - prop.scaleMin) ) ) * this.radius;
589
+ xy.angle = (RG.SVG.TRIG.TWOPI / len2) * i - RG.SVG.TRIG.HALFPI;
590
+
591
+ path.push('{1}{2} {3}'.format(
592
+ i === 0 ? 'M' : 'L',
593
+ xy.x,
594
+ xy.y
595
+ ));
596
+
597
+ // Save the coordinates and angle
598
+ this.angles.push({
599
+ cx: this.centerx,
600
+ cy: this.centery,
601
+ r: xy.r,
602
+ angle: xy.angle
603
+ });
604
+ this.angles2[dataset].push({
605
+ cx: this.centerx,
606
+ cy: this.centery,
607
+ r: xy.r,
608
+ angle: xy.angle
609
+ });
610
+
611
+ this.coords.push([
612
+ xy.x,
613
+ xy.y
614
+ ]);
615
+ this.coords2[dataset].push([
616
+ xy.x,
617
+ xy.y
618
+ ]);
619
+ }
620
+
621
+ // If a stacked filled charts then add the reverse path
622
+ if (dataset > 0 && prop.filled && prop.filledAccumulative) {
623
+
624
+ // Add a line completing the "circle"
625
+ path.push('L {1} {2}'.format(
626
+ this.coords2[dataset][0][0],
627
+ this.coords2[dataset][0][1]
628
+ ));
629
+
630
+ // Move to the previous dataset
631
+ path.push('M {1} {2}'.format(
632
+ this.coords2[dataset - 1][0][0],
633
+ this.coords2[dataset - 1][0][1]
634
+ ));
635
+
636
+ // Now backtrack over the previous dataset
637
+ for (var i=this.coords2[dataset - 1].length - 1; i>=0; --i) {
638
+ path.push('L {1} {2}'.format(
639
+ this.coords2[dataset - 1][i][0],
640
+ this.coords2[dataset - 1][i][1]
641
+ ));
642
+ }
643
+
644
+ this.redraw = true;
645
+
646
+ } else {
647
+ // Add the closepath
648
+ path.push('z');
649
+ }
650
+
651
+
652
+ var path = RG.SVG.create({
653
+ svg: this.svg,
654
+ type: 'path',
655
+ attr: {
656
+ d: path.join(" "),
657
+ stroke: prop.colors[dataset],
658
+ fill: prop.filled ? prop.colors[dataset] : 'transparent',
659
+ 'fill-opacity': prop.filledOpacity,
660
+ 'stroke-width': prop.linewidth,
661
+ filter: prop.shadow ? 'url(#dropShadow)' : '',
662
+ }
663
+ });
664
+
665
+ path.setAttribute('data-dataset', dataset);
666
+ }
667
+
668
+
669
+ // Redraw the chart (this only runs if necessary
670
+ this.redrawRadar();
671
+ };
672
+
673
+
674
+
675
+
676
+
677
+
678
+
679
+
680
+ //
681
+ // Redraws the chart if required
682
+ //
683
+ this.redrawRadar = function ()
684
+ {
685
+ if (this.redraw) {
686
+
687
+ this.redraw = false;
688
+
689
+ // Loop through ths coordinates
690
+ for (var dataset = 0; dataset<this.coords2.length; ++dataset) {
691
+
692
+ var path = [];
693
+
694
+ for (var i=0; i<this.coords2[dataset].length; ++i) {
695
+ if (i === 0) {
696
+ path.push('M {1} {2}'.format(
697
+ this.coords2[dataset][i][0],
698
+ this.coords2[dataset][i][1]
699
+ ));
700
+ } else {
701
+ path.push('L {1} {2}'.format(
702
+ this.coords2[dataset][i][0],
703
+ this.coords2[dataset][i][1]
704
+ ))
705
+ }
706
+ }
707
+
708
+ path.push('z')
709
+
710
+ RG.SVG.create({
711
+ svg: this.svg,
712
+ type: 'path',
713
+ attr: {
714
+ d: path.join(" "),
715
+ stroke: prop.colors[dataset],
716
+ fill: 'transparent',
717
+ 'stroke-width': prop.linewidth
718
+ }
719
+ });
720
+ }
721
+ }
722
+ };
723
+
724
+
725
+
726
+
727
+
728
+
729
+
730
+
731
+ //
732
+ // Draw the tickmarks
733
+ //
734
+ this.drawTickmarks = function ()
735
+ {
736
+ var group = RG.SVG.create({
737
+ svg: this.svg,
738
+ type: 'g',
739
+ attr: {
740
+ }
741
+ });
742
+
743
+ for (var i=0; i<this.coords2.length; ++i) {
744
+ for (var j=0; j<this.coords2[i].length; ++j) {
745
+ if (prop.tickmarks === 'circle' || prop.tickmarks === 'filledcircle' ) {
746
+ var c = RG.SVG.create({
747
+ svg: this.svg,
748
+ type: 'circle',
749
+ fparent: group,
750
+ attr: {
751
+ cx: this.coords2[i][j][0],
752
+ cy: this.coords2[i][j][1],
753
+ r: prop.tickmarksSize,
754
+ fill: prop.tickmarks === 'filledcircle' ? prop.colors[i] : prop.tickmarksFill,
755
+ stroke: prop.colors[i],
756
+ 'stroke-width': prop.tickmarksLinewidth
757
+ }
758
+ });
759
+
760
+ c.setAttribute('data-dataset', i);
761
+ c.setAttribute('data-index', j);
762
+
763
+
764
+ } else if (prop.tickmarks === 'rect' || prop.tickmarks === 'filledrect') {
765
+
766
+ var halfTickmarkSize = prop.tickmarksSize / 2;
767
+ var fill = typeof prop.tickmarksFill === 'object' && prop.tickmarksFill[i] ? prop.tickmarksFill[i] : prop.tickmarksFill;
768
+
769
+ var s = RG.SVG.create({
770
+ svg: this.svg,
771
+ type: 'rect',
772
+ fparent: group,
773
+ attr: {
774
+ x: this.coords2[i][j][0] - halfTickmarkSize,
775
+ y: this.coords2[i][j][1] - halfTickmarkSize,
776
+ width: prop.tickmarksSize,
777
+ height: prop.tickmarksSize,
778
+ fill: prop.tickmarks === 'filledrect' ? prop.colors[i] : fill,
779
+ stroke: prop.colors[i],
780
+ 'stroke-width': prop.tickmarksLinewidth
781
+ }
782
+ });
783
+
784
+ s.setAttribute('data-dataset', i);
785
+ s.setAttribute('data-index', j);
786
+ }
787
+ }
788
+ }
789
+ };
790
+
791
+
792
+
793
+
794
+
795
+
796
+
797
+
798
+ //
799
+ // Draw the labels
800
+ //
801
+ this.drawLabels = function ()
802
+ {
803
+ var angles = this.angles2,
804
+ prop = this.properties,
805
+ labels = prop.labels;
806
+
807
+ for (var i=0,len=labels.length; i<len; ++i) {
808
+
809
+ if (!labels[i]) {
810
+ continue;
811
+ }
812
+
813
+ var endpoint = RG.SVG.TRIG.getRadiusEndPoint({
814
+ angle: RG.SVG.TRIG.TWOPI / labels.length * i - RG.SVG.TRIG.HALFPI,
815
+ r: this.radius + 15
816
+ });
817
+
818
+ var x = endpoint[0] + this.centerx,
819
+ y = endpoint[1] + this.centery;
820
+
821
+ //
822
+ // Horizontal alignment
823
+
824
+ if ((i / len) < 0.5) {
825
+ halign = 'left';
826
+ } else {
827
+ halign = 'right';
828
+ }
829
+
830
+ //
831
+ // Vertical alignment
832
+ //
833
+ if ((i / len) < 0.25 || (i / len) > 0.75) {
834
+ valign = 'bottom';
835
+ } else {
836
+ valign = 'top';
837
+ }
838
+
839
+ // Specify the alignment for labels which are on the axes
840
+ if ( (i / len) === 0 ) {halign = 'center';}
841
+ if ( (i / len) === 0.25 ) {valign = 'center';}
842
+ if ( (i / len) === 0.5 ) {halign = 'center';}
843
+ if ( (i / len) === 0.75 ) {valign = 'center';}
844
+
845
+
846
+ RG.SVG.text({
847
+ object: this,
848
+ svg: this.svg,
849
+ text: labels[i],
850
+ size: typeof prop.labelsSize === 'number' ? prop.labelsSize : prop.textSize,
851
+ x: x,
852
+ y: y,
853
+ halign: halign,
854
+ valign: 'center',
855
+ color: prop.labelsColor || prop.textColor,
856
+ bold: typeof prop.labelsBold === 'boolean' ? prop.labelsBold : prop.textBold,
857
+ italic: typeof prop.labelsItalic === 'boolean' ? prop.labelsItalic : prop.textItalic,
858
+ font: prop.labelsFont || prop.textFont
859
+ });
860
+ }
861
+
862
+
863
+
864
+
865
+
866
+
867
+
868
+
869
+
870
+
871
+
872
+
873
+ // Draw the scale if required
874
+ if (prop.scaleVisible) {
875
+ for (var i=0; i<this.scale.labels.length; ++i) {
876
+
877
+ var x = this.centerx;
878
+ var y = this.centery - (this.radius / this.scale.labels.length * (i+1) );
879
+
880
+
881
+ RG.SVG.text({
882
+ object: this,
883
+ svg: this.svg,
884
+ text: this.scale.labels[i],
885
+ size: prop.scaleSize || prop.textSize - 2,
886
+ x: x,
887
+ y: y,
888
+ halign: 'center',
889
+ valign: 'center',
890
+ background: 'rgba(255,255,255,0.7)',
891
+ padding:2,
892
+ color: prop.scaleColor || prop.textColor,
893
+ bold: typeof prop.scaleBold === 'boolean' ? prop.scaleBold : prop.textBold,
894
+ italic: typeof prop.scaleItalic === 'boolean' ? prop.scaleItalic : prop.textItalic,
895
+ font: prop.scaleFont || prop.textFont
896
+ });
897
+ }
898
+
899
+ // Draw the zero label
900
+ var str = RG.SVG.numberFormat({
901
+ object: this,
902
+ num: this.scale.min.toFixed(prop.scaleDecimals),
903
+ prepend: prop.scaleUnitsPre,
904
+ append: prop.scaleUnitsPost,
905
+ point: prop.scalePoint,
906
+ thousand: prop.scaleThousand,
907
+ formatter: prop.scaleFormatter
908
+ });
909
+
910
+
911
+ RG.SVG.text({
912
+ object: this,
913
+ svg: this.svg,
914
+ text: str,
915
+ size: prop.scaleSize || prop.textSize - 2,
916
+ x: this.centerx,
917
+ y: this.centery,
918
+ halign: 'center',
919
+ valign: 'center',
920
+ background: 'rgba(255,255,255,0.7)',
921
+ padding:2,
922
+ color: prop.scaleColor || prop.textColor,
923
+ bold: typeof prop.scaleBold === 'boolean' ? prop.scaleBold : prop.textBold,
924
+ italic: typeof prop.scaleItalic === 'boolean' ? prop.scaleItalic : prop.textItalic,
925
+ font: prop.scaleFont || prop.textFont
926
+ });
927
+ }
928
+ };
929
+
930
+
931
+
932
+
933
+
934
+
935
+
936
+
937
+ /**
938
+ * This function can be used to highlight a segment on the chart
939
+ *
940
+ * @param object segment The segment to highlight
941
+ */
942
+ this.highlight = function (circle)
943
+ {
944
+ if (typeof prop.tickmarks === 'string' && prop.tickmarks) {
945
+
946
+ circle.setAttribute('fill', prop.highlightFill);
947
+ circle.setAttribute('stroke', prop.highlightStroke);
948
+ circle.setAttribute('stroke-width', prop.highlightLinewidth);
949
+
950
+ window.addEventListener ('mousedown', function (e)
951
+ {
952
+ circle.setAttribute('fill', 'transparent');
953
+ circle.setAttribute('stroke', 'transparent');
954
+ circle.setAttribute('stroke-width', 0);
955
+
956
+ RG.SVG.REG.set('highlight', this);
957
+ }, false);
958
+
959
+ this.highlight_hotspot = circle;
960
+ }
961
+ };
962
+
963
+
964
+
965
+
966
+
967
+
968
+
969
+
970
+ // Add the hide function
971
+ this.hideHighlight = function ()
972
+ {
973
+ if (this.highlight_hotspot) {
974
+ this.highlight_hotspot.setAttribute('fill', 'transparent');
975
+ this.highlight_hotspot.setAttribute('stroke', 'transparent');
976
+ this.highlight_hotspot.setAttribute('stroke-width', 0);
977
+
978
+ this.highlight_hotspot = null
979
+ }
980
+ };
981
+
982
+
983
+
984
+
985
+
986
+
987
+
988
+
989
+ /**
990
+ * This allows for easy specification of gradients
991
+ */
992
+ this.parseColors = function ()
993
+ {
994
+ // Save the original colors so that they can be restored when the canvas is reset
995
+ if (!Object.keys(this.originalColors).length) {
996
+ this.originalColors = {
997
+ colors: RG.SVG.arrayClone(prop.colors),
998
+ highlightFill: RG.SVG.arrayClone(prop.highlightFill)
999
+ }
1000
+ }
1001
+
1002
+
1003
+ // colors
1004
+ var colors = prop.colors;
1005
+
1006
+ if (colors) {
1007
+ for (var i=0; i<colors.length; ++i) {
1008
+ colors[i] = RG.SVG.parseColorRadial({
1009
+ object: this,
1010
+ color: colors[i]
1011
+ });
1012
+ }
1013
+ }
1014
+
1015
+ // Highlight fill
1016
+ prop.highlightFill = RG.SVG.parseColorRadial({
1017
+ object: this,
1018
+ color: prop.highlightFill
1019
+ });
1020
+ };
1021
+
1022
+
1023
+
1024
+
1025
+
1026
+
1027
+
1028
+
1029
+ //
1030
+ // Get the maximum value
1031
+ //
1032
+ this.getMaxValue = function ()
1033
+ {
1034
+ var max = 0;
1035
+
1036
+ if (prop.filled && prop.filledAccumulative) {
1037
+ this.max = RG.SVG.arrayMax(this.data[this.data.length - 1]);
1038
+ } else {
1039
+ for (var dataset=0,max=0; dataset<this.data.length; ++dataset) {
1040
+ this.max = ma.max(this.max, RG.SVG.arrayMax(this.data[dataset]));
1041
+ }
1042
+ }
1043
+ };
1044
+
1045
+
1046
+
1047
+
1048
+
1049
+
1050
+
1051
+
1052
+ //
1053
+ // Gets the radius of a value
1054
+ //
1055
+ //@param number The value to get the radius for
1056
+ //
1057
+ this.getRadius = function (value)
1058
+ {
1059
+ return ( (value - prop.scaleMin) / (this.scale.max - prop.scaleMin) ) * this.radius;
1060
+ };
1061
+
1062
+
1063
+
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+ //
1070
+ // Adds the circular hotspot that facilitate tooltips
1071
+ // (to a single point)
1072
+ //
1073
+ this.addTooltipHotspots = function ()
1074
+ {
1075
+ if (prop.tooltips && prop.tooltips.length > 0) {
1076
+
1077
+ // Make the tooltipsEvent default to click
1078
+ if (prop.tooltipsEvent !== 'mousemove') {
1079
+ prop.tooltipsEvent = 'click';
1080
+ }
1081
+
1082
+ var group = RG.SVG.create({
1083
+ svg: this.svg,
1084
+ type: 'g',
1085
+ attr: {
1086
+ className: 'rgraph-radar-tooltip-hotspots'
1087
+ }
1088
+ });
1089
+
1090
+ for (var dataset=0,seq=0; dataset<this.coords2.length; ++dataset) {
1091
+ for (var i=0; i<this.coords2[dataset].length; ++i) {
1092
+
1093
+ var circle = RG.SVG.create({
1094
+ svg: this.svg,
1095
+ type: 'circle',
1096
+ parent: group,
1097
+ attr: {
1098
+ cx: this.coords2[dataset][i][0],
1099
+ cy: this.coords2[dataset][i][1],
1100
+ r: prop.tickmarksSize,
1101
+ fill: 'transparent',
1102
+ stroke: 'transparent',
1103
+ 'stroke-width': 0
1104
+ },
1105
+ style: {
1106
+ cursor: 'pointer'
1107
+ }
1108
+ });
1109
+
1110
+ (function (dataset, index, seq, obj)
1111
+ {
1112
+ circle.addEventListener(prop.tooltipsEvent, function (e)
1113
+ {
1114
+ var tooltip = RG.SVG.REG.get('tooltip');
1115
+
1116
+ if (tooltip && tooltip.__sequentialIndex__ === seq) {
1117
+ return;
1118
+ }
1119
+
1120
+ RG.SVG.hideTooltip();
1121
+ obj.hideHighlight();
1122
+
1123
+ // Show the tooltip
1124
+ RG.SVG.tooltip({
1125
+ object: obj,
1126
+ dataset: dataset,
1127
+ index: index,
1128
+ sequentialIndex: seq,
1129
+ text: prop.tooltips[seq],
1130
+ event: e
1131
+ });
1132
+
1133
+ // Highlight the rect that has been clicked on
1134
+ obj.highlight(this);
1135
+
1136
+ if (prop.tooltipsEvent === 'mousemove') {
1137
+ highlight.style.cursor = 'pointer';
1138
+ }
1139
+
1140
+ }, false);
1141
+
1142
+ // Install the event listener that changes the
1143
+ // cursor if necessary
1144
+ if (prop.tooltipsEvent === 'click') {
1145
+ circle.addEventListener('mousemove', function (e)
1146
+ {
1147
+ e.target.style.cursor = 'pointer';
1148
+ }, false);
1149
+ }
1150
+
1151
+ }(dataset, i, seq++, this));
1152
+ }
1153
+ }
1154
+ }
1155
+ };
1156
+
1157
+
1158
+
1159
+
1160
+
1161
+
1162
+
1163
+
1164
+ //
1165
+ // A roundRobin effect for the Pie chart
1166
+ //
1167
+ // @param object Options for the effect
1168
+ // @param function An optional callback function to call when
1169
+ // the effect is complete
1170
+ //
1171
+ this.roundRobin = function ()
1172
+ {
1173
+ /*
1174
+ var obj = this,
1175
+ opt = arguments[0] || {},
1176
+ data = RG.SVG.arrayClone(this.data),
1177
+ prop = this.properties,
1178
+ frame = 1,
1179
+ frames = opt.frames || 30,
1180
+ callback = typeof opt.callback === 'function' ? opt.callback : function () {},
1181
+ dataSum = RG.SVG.arraySum(this.data),
1182
+ textColor = prop.textColor;
1183
+
1184
+ // Set the text color to transparent
1185
+ this.properties.textColor = 'rgba(0,0,0,0)';
1186
+
1187
+
1188
+ // Draw the chart first
1189
+ obj.draw();
1190
+
1191
+ // Now get the resulting angles
1192
+ angles = RG.SVG.arrayClone(obj.angles);
1193
+
1194
+
1195
+ function iterator ()
1196
+ {
1197
+ prop.roundRobinMultiplier = 1 / frames * frame++;
1198
+
1199
+ for (var i=0; i<obj.angles.length; ++i) {
1200
+
1201
+ var value = obj.data[i];
1202
+
1203
+
1204
+
1205
+ // NB This was an absolute git to work out for some reason.
1206
+
1207
+
1208
+
1209
+ obj.angles[i].start = angles[i].start * prop.roundRobinMultiplier;
1210
+ obj.angles[i].end = angles[i].end * prop.roundRobinMultiplier;
1211
+
1212
+ //var segment = (((value * prop.roundRobinMultiplier) / dataSum) * RG.SVG.TRIG.TWOPI);
1213
+ var segment = ((obj.angles[i].end - obj.angles[i].start) / 2);
1214
+ var explodedX = ma.cos(obj.angles[i].start + segment - RG.SVG.TRIG.HALFPI) * (prop.exploded[i] || 0);
1215
+ var explodedY = ma.sin(obj.angles[i].start + segment - RG.SVG.TRIG.HALFPI) * (prop.exploded[i] || 0);
1216
+
1217
+
1218
+
1219
+ var path = RG.SVG.TRIG.getArcPath({
1220
+ cx: obj.centerx + explodedX,
1221
+ cy: obj.centery + explodedY,
1222
+ r: obj.radius,// * prop.roundRobinMultiplier,
1223
+ start: obj.angles[i].start,
1224
+ end: obj.angles[i].end
1225
+ });
1226
+
1227
+ path = path + " L {1} {2} Z".format(
1228
+ obj.centerx + explodedX,
1229
+ obj.centery + explodedY
1230
+ );
1231
+
1232
+ if (obj.shadowNodes && obj.shadowNodes[i]) {
1233
+ obj.shadowNodes[i].setAttribute('d', path);
1234
+ }
1235
+ obj.nodes[i].setAttribute('d', path);
1236
+ }
1237
+
1238
+
1239
+ if (frame <= frames) {
1240
+ RG.SVG.FX.update(iterator);
1241
+ } else {
1242
+ prop.textColor = textColor;
1243
+
1244
+ RG.SVG.redraw(obj.svg);
1245
+
1246
+ callback(obj);
1247
+ }
1248
+ }
1249
+
1250
+ iterator();
1251
+
1252
+ return this;
1253
+ */
1254
+ };
1255
+
1256
+
1257
+
1258
+
1259
+
1260
+
1261
+
1262
+
1263
+ /**
1264
+ * Using a function to add events makes it easier to facilitate method
1265
+ * chaining
1266
+ *
1267
+ * @param string type The type of even to add
1268
+ * @param function func
1269
+ */
1270
+ this.on = function (type, func)
1271
+ {
1272
+ if (type.substr(0,2) !== 'on') {
1273
+ type = 'on' + type;
1274
+ }
1275
+
1276
+ RG.SVG.addCustomEventListener(this, type, func);
1277
+
1278
+ return this;
1279
+ };
1280
+
1281
+
1282
+
1283
+
1284
+
1285
+
1286
+
1287
+
1288
+ //
1289
+ // Used in chaining. Runs a function there and then - not waiting for
1290
+ // the events to fire (eg the onbeforedraw event)
1291
+ //
1292
+ // @param function func The function to execute
1293
+ //
1294
+ this.exec = function (func)
1295
+ {
1296
+ func(this);
1297
+
1298
+ return this;
1299
+ };
1300
+
1301
+
1302
+
1303
+
1304
+
1305
+
1306
+
1307
+
1308
+ //
1309
+ // Set the options that the user has provided
1310
+ //
1311
+ for (i in conf.options) {
1312
+ if (typeof i === 'string') {
1313
+ this.set(i, conf.options[i]);
1314
+ }
1315
+ }
1316
+ };
1317
+
1318
+
1319
+
1320
+ return this;
1321
+
1322
+
1323
+
1324
+
1325
+ // End module pattern
1326
+ })(window, document);