rgraph-rails 4.62 → 4.64

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