rgraph-rails 1.0.8 → 4.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/lib/rgraph-rails/version.rb +1 -1
  4. data/vendor/assets/javascripts/RGraph.bar.js +16 -8
  5. data/vendor/assets/javascripts/RGraph.bipolar.js +1 -1
  6. data/vendor/assets/javascripts/RGraph.common.annotate.js +1 -1
  7. data/vendor/assets/javascripts/RGraph.common.context.js +1 -1
  8. data/vendor/assets/javascripts/RGraph.common.core.js +84 -7
  9. data/vendor/assets/javascripts/RGraph.common.csv.js +1 -1
  10. data/vendor/assets/javascripts/RGraph.common.deprecated.js +1 -1
  11. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1 -1
  12. data/vendor/assets/javascripts/RGraph.common.effects.js +1 -1
  13. data/vendor/assets/javascripts/RGraph.common.key.js +3 -3
  14. data/vendor/assets/javascripts/RGraph.common.resizing.js +1 -1
  15. data/vendor/assets/javascripts/RGraph.common.sheets.js +1 -1
  16. data/vendor/assets/javascripts/RGraph.common.tooltips.js +1 -1
  17. data/vendor/assets/javascripts/RGraph.common.zoom.js +1 -1
  18. data/vendor/assets/javascripts/RGraph.drawing.background.js +1 -1
  19. data/vendor/assets/javascripts/RGraph.drawing.circle.js +1 -1
  20. data/vendor/assets/javascripts/RGraph.drawing.image.js +1 -1
  21. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +1 -1
  22. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +1 -1
  23. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +1 -1
  24. data/vendor/assets/javascripts/RGraph.drawing.poly.js +1 -1
  25. data/vendor/assets/javascripts/RGraph.drawing.rect.js +1 -1
  26. data/vendor/assets/javascripts/RGraph.drawing.text.js +1 -1
  27. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +1 -1
  28. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +1 -1
  29. data/vendor/assets/javascripts/RGraph.fuel.js +1 -1
  30. data/vendor/assets/javascripts/RGraph.funnel.js +1 -1
  31. data/vendor/assets/javascripts/RGraph.gantt.js +1 -1
  32. data/vendor/assets/javascripts/RGraph.gauge.js +1 -1
  33. data/vendor/assets/javascripts/RGraph.hbar.js +228 -2
  34. data/vendor/assets/javascripts/RGraph.hprogress.js +1 -1
  35. data/vendor/assets/javascripts/RGraph.line.js +27 -5
  36. data/vendor/assets/javascripts/RGraph.meter.js +1 -1
  37. data/vendor/assets/javascripts/RGraph.modaldialog.js +1 -1
  38. data/vendor/assets/javascripts/RGraph.odo.js +1 -1
  39. data/vendor/assets/javascripts/RGraph.pie.js +1 -1
  40. data/vendor/assets/javascripts/RGraph.radar.js +1 -1
  41. data/vendor/assets/javascripts/RGraph.rose.js +1 -1
  42. data/vendor/assets/javascripts/RGraph.rscatter.js +1 -1
  43. data/vendor/assets/javascripts/RGraph.scatter.js +161 -34
  44. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1 -1
  45. data/vendor/assets/javascripts/RGraph.svg.bar.js +772 -103
  46. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +1 -1
  47. data/vendor/assets/javascripts/RGraph.svg.common.core.js +806 -231
  48. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +1 -1
  49. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +24 -24
  50. data/vendor/assets/javascripts/RGraph.svg.common.key.js +206 -0
  51. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +1 -1
  52. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +63 -22
  53. data/vendor/assets/javascripts/RGraph.svg.hbar.js +351 -91
  54. data/vendor/assets/javascripts/RGraph.svg.line.js +159 -64
  55. data/vendor/assets/javascripts/RGraph.svg.pie.js +402 -51
  56. data/vendor/assets/javascripts/RGraph.svg.radar.js +320 -143
  57. data/vendor/assets/javascripts/RGraph.svg.rose.js +1818 -0
  58. data/vendor/assets/javascripts/RGraph.svg.scatter.js +1262 -0
  59. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +106 -57
  60. data/vendor/assets/javascripts/RGraph.svg.waterfall.js +1253 -0
  61. data/vendor/assets/javascripts/RGraph.thermometer.js +7 -6
  62. data/vendor/assets/javascripts/RGraph.vprogress.js +1 -1
  63. data/vendor/assets/javascripts/RGraph.waterfall.js +1 -1
  64. data/vendor/assets/javascripts/financial-data.js +1067 -0
  65. metadata +8 -5
  66. data/vendor/assets/javascripts/RGraph.cornergauge.js +0 -71
  67. data/vendor/assets/javascripts/RGraph.thermometer.old.js +0 -68
@@ -0,0 +1,1818 @@
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
+
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.Rose = 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 = 'rose';
89
+ this.angles = [];
90
+ this.angles2 = [];
91
+ this.colorsParsed = false;
92
+ this.originalColors = {};
93
+ this.gradientCounter = 1;
94
+ this.nodes = [];
95
+ this.shadowNodes = [];
96
+ this.max = 0;
97
+ this.redraw = false;
98
+ this.highlight_node = null;
99
+
100
+ // Add this object to the ObjectRegistry
101
+ RG.SVG.OR.add(this);
102
+
103
+ // Set the DIV container to be inline-block
104
+ this.container.style.display = 'inline-block';
105
+
106
+
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
+ backgroundGridRadialsAngleOffset: 0,
127
+ backgroundGridConcentricsCount: 5,
128
+ backgroundGridLinewidth: 1,
129
+
130
+ strokestyle: 'white',
131
+ colors: [
132
+ 'red', 'black', 'orange', 'green', '#6ff', '#ccc',
133
+ 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal'
134
+ ],
135
+ colorsOpacity: 1,
136
+
137
+ textColor: 'black',
138
+ textFont: 'sans-serif',
139
+ textSize: 12,
140
+ textBold: false,
141
+ textItalic: false,
142
+
143
+ labels: [],
144
+ labelsFont: null,
145
+ labelsSize: null,
146
+ labelsColor: null,
147
+ labelsBold: null,
148
+ labelsItalic: null,
149
+ labelsRadialMargin: 10,
150
+ labelsAngleOffset: 0,
151
+
152
+ scaleVisible: true,
153
+ scaleUnitsPre: '',
154
+ scaleUnitsPost: '',
155
+ scaleMax: null,
156
+ scaleMin: 0,
157
+ scalePoint: '.',
158
+ scaleThousand: ',',
159
+ scaleRound: false,
160
+ scaleDecimals: 0,
161
+ scaleFormatter: null,
162
+ scaleBold: null,
163
+ scaleItalic: null,
164
+ scaleColor: null,
165
+ scaleSize: null,
166
+ scaleFont: null,
167
+ scaleLabelsCount: 5,
168
+
169
+ linewidth: 1,
170
+
171
+ tooltips: null,
172
+ tooltipsOverride: null,
173
+ tooltipsEffect: 'fade',
174
+ tooltipsCssClass: 'RGraph_tooltip',
175
+ tooltipsEvent: 'click',
176
+
177
+ highlightStroke: 'rgba(0,0,0,0)',
178
+ highlightFill: 'rgba(255,255,255,0.7)',
179
+ highlightLinewidth: 1,
180
+
181
+ title: '',
182
+ titleSize: 16,
183
+ titleX: null,
184
+ titleY: null,
185
+ titleHalign: 'center',
186
+ titleValign: null,
187
+ titleColor: 'black',
188
+ titleFont: null,
189
+ titleBold: false,
190
+ titleItalic: false,
191
+
192
+ titleSubtitle: '',
193
+ titleSubtitleSize: 10,
194
+ titleSubtitleX: null,
195
+ titleSubtitleY: null,
196
+ titleSubtitleHalign: 'center',
197
+ titleSubtitleValign: null,
198
+ titleSubtitleColor: '#aaa',
199
+ titleSubtitleFont: null,
200
+ titleSubtitleBold: false,
201
+ titleSubtitleItalic: false,
202
+
203
+ shadow: false,
204
+ shadowOffsetx: 2,
205
+ shadowOffsety: 2,
206
+ shadowBlur: 2,
207
+ shadowOpacity: 0.25,
208
+
209
+ margin: 0,
210
+ exploded: 0,
211
+
212
+
213
+ key: null,
214
+ keyColors: null,
215
+ keyOffsetx: 0,
216
+ keyOffsety: 0,
217
+ keyTextOffsetx: 0,
218
+ keyTextOffsety: -1,
219
+ keyTextSize: null,
220
+ keyTextBold: null,
221
+ keyTextItalic: null,
222
+
223
+ attribution: true,
224
+ attributionX: null,
225
+ attributionY: null,
226
+ attributionHref: null,// Default is set in RGraph.svg.common.core.js
227
+ attributionHalign: 'right',
228
+ attributionValign: 'bottom',
229
+ attributionSize: 7,
230
+ attributionColor: 'gray',
231
+ attributionFont: 'sans-serif',
232
+ attributionItalic: false,
233
+ attributionBold: false,
234
+
235
+ segmentsAngleOffset: 0,
236
+ variant: 'normal'
237
+ };
238
+
239
+
240
+
241
+
242
+
243
+
244
+ /**
245
+ * "Decorate" the object with the generic effects if the effects library has been included
246
+ */
247
+ if (RG.SVG.FX && typeof RG.SVG.FX.decorate === 'function') {
248
+ RG.SVG.FX.decorate(this);
249
+ }
250
+
251
+
252
+
253
+
254
+ var prop = this.properties;
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+ //
264
+ // The draw method draws the Bar chart
265
+ //
266
+ this.draw = function ()
267
+ {
268
+ // Fire the beforedraw event
269
+ RG.SVG.fireCustomEvent(this, 'onbeforedraw');
270
+
271
+
272
+
273
+ // Reset the data back to the original values
274
+ this.data = RG.SVG.arrayClone(this.originalData);
275
+
276
+
277
+
278
+ // Reset the angles array to stop it growing
279
+ this.angles = [];
280
+
281
+
282
+ // Create the arrays in the angles2 array based on
283
+ // the data that we've been passed
284
+ for (var i=0; i<this.data.length; ++i) {
285
+ this.angles2[i] = [];
286
+ }
287
+
288
+
289
+
290
+
291
+
292
+ // Create the defs tag if necessary
293
+ RG.SVG.createDefs(this);
294
+
295
+
296
+
297
+
298
+ this.graphWidth = this.width - prop.gutterLeft - prop.gutterRight;
299
+ this.graphHeight = this.height - prop.gutterTop - prop.gutterBottom;
300
+
301
+
302
+
303
+ // Work out the center point
304
+ this.centerx = (this.graphWidth / 2) + prop.gutterLeft;
305
+ this.centery = (this.graphHeight / 2) + prop.gutterTop;
306
+ this.radius = ma.min(this.graphWidth, this.graphHeight) / 2;
307
+
308
+
309
+
310
+ // Allow the user to override the calculated centerx/y/radius
311
+ this.centerx = typeof prop.centerx === 'number' ? prop.centerx : this.centerx;
312
+ this.centery = typeof prop.centery === 'number' ? prop.centery : this.centery;
313
+ this.radius = typeof prop.radius === 'number' ? prop.radius : this.radius;
314
+
315
+ //
316
+ // Allow the centerx/centery/radius to be a plus/minus
317
+ //
318
+ if (typeof prop.radius === 'string' && prop.radius.match(/^\+|-\d+$/) ) this.radius += parseFloat(prop.radius);
319
+ if (typeof prop.centerx === 'string' && prop.centerx.match(/^\+|-\d+$/) ) this.centery += parseFloat(prop.centerx);
320
+ if (typeof prop.centery === 'string' && prop.centery.match(/^\+|-\d+$/) ) this.centerx += parseFloat(prop.centery);
321
+
322
+
323
+
324
+
325
+
326
+ //
327
+ // Convert the nargin from strings to a number
328
+ //
329
+ if (typeof prop.margin === 'string' && prop.margin.match(/([0-9.]+)deg/)) {
330
+ prop.margin = RegExp.$1 / (180 / ma.PI);
331
+ }
332
+
333
+
334
+
335
+
336
+ /**
337
+ * Add the data to the .originalData array and work out the max value
338
+ *
339
+ * 2/5/14 Now also use this loop to ensure that the data pieces
340
+ * are numbers
341
+ *
342
+ * **Is this necessary **
343
+ */
344
+ //if (RG.SVG.isArray(this.data) && (typeof this.data[0] === 'number' || typeof this.data[0] === 'string')) {
345
+ // this.data = [this.data];
346
+ //}
347
+
348
+ // Convert strings to numbers
349
+ for (var i=0; i<this.data.length; ++i) {
350
+ if (typeof this.data[i] === 'object') {
351
+ for (var j=0; j<this.data[i].length; ++j) {
352
+ if (typeof this.data[i][j] === 'string') {
353
+ this.data[i][j] = RG.SVG.stringsToNumbers(this.data[i][j]);
354
+ }
355
+ }
356
+ } else if (typeof this.data[i] === 'string') {
357
+ this.data[i] = RG.SVG.stringsToNumbers(this.data[i]);
358
+ }
359
+ }
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+ // Get the max value. This sets the maximum value on the
370
+ // this.max variable
371
+ this.getMaxValue();
372
+
373
+
374
+
375
+
376
+
377
+
378
+
379
+ // Parse the colors for gradients
380
+ RG.SVG.resetColorsToOriginalValues({object:this});
381
+ this.parseColors();
382
+
383
+ //
384
+ // Get the scale
385
+ //
386
+
387
+ this.scale = RG.SVG.getScale({
388
+ object: this,
389
+ numlabels: typeof prop.scaleLabelsCount === 'number' ? prop.scaleLabelsCount : prop.backgroundGridConcentricCount,
390
+ unitsPre: prop.scaleUnitsPre,
391
+ unitsPost: prop.scaleUnitsPost,
392
+ max: typeof prop.scaleMax === 'number' ? prop.scaleMax : this.max,
393
+ min: prop.scaleMin,
394
+ point: prop.scalePoint,
395
+ round: prop.scaleRound,
396
+ thousand: prop.scaleThousand,
397
+ decimals: prop.scaleDecimals,
398
+ strict: typeof prop.scaleMax === 'number',
399
+ formatter: prop.scaleFormatter
400
+ });
401
+
402
+ this.max = this.scale.max;
403
+
404
+
405
+
406
+ // Draw the background 'grid'
407
+ this.drawBackground();
408
+
409
+
410
+
411
+ // Draw the chart
412
+ this.drawRose();
413
+
414
+
415
+
416
+
417
+
418
+
419
+ // Draw the labels
420
+ this.drawLabels();
421
+
422
+
423
+
424
+ // Draw the title and subtitle
425
+ RG.SVG.drawTitle(this);
426
+
427
+
428
+
429
+
430
+
431
+
432
+ // Draw the key
433
+ if (typeof prop.key !== null && RG.SVG.drawKey) {
434
+ RG.SVG.drawKey(this);
435
+ } else if (!RGraph.SVG.isNull(prop.key)) {
436
+ alert('The drawKey() function does not exist - have you forgotten to include the key library?');
437
+ }
438
+
439
+
440
+
441
+
442
+
443
+ // Add the attribution link. If you're adding this elsewhere on your page/site
444
+ // and you don't want it displayed then there are options available to not
445
+ // show it.
446
+ RG.SVG.attribution(this);
447
+
448
+ // Create the shadow definition if needed
449
+ if (prop.shadow) {
450
+ RG.SVG.setShadow({
451
+ object: this,
452
+ offsetx: prop.shadowOffsetx,
453
+ offsety: prop.shadowOffsety,
454
+ blur: prop.shadowBlur,
455
+ opacity: prop.shadowOpacity,
456
+ id: 'dropShadow'
457
+ });
458
+ }
459
+
460
+
461
+
462
+ // Add the event listener that clears the highlight if
463
+ // there is any. Must be MOUSEDOWN (ie before the click event)
464
+ var obj = this;
465
+ doc.body.addEventListener('mousedown', function (e)
466
+ {
467
+ obj.hideHighlight(obj);
468
+ }, false);
469
+
470
+
471
+
472
+ // Fire the draw event
473
+ RG.SVG.fireCustomEvent(this, 'ondraw');
474
+
475
+
476
+
477
+ return this;
478
+ };
479
+
480
+
481
+
482
+
483
+
484
+
485
+
486
+
487
+ //
488
+ // Draw the background grid
489
+ //
490
+ this.drawBackground = function ()
491
+ {
492
+ if (prop.backgroundGrid) {
493
+
494
+ // Create the background grid group tag
495
+ var grid = RG.SVG.create({
496
+ svg: this.svg,
497
+ parent: this.svg.all,
498
+ type: 'g',
499
+ attr: {
500
+ className: 'rgraph_radar_grid',
501
+ fill: 'rgba(0,0,0,0)',
502
+ stroke: prop.backgroundGridColor
503
+ }
504
+ });
505
+
506
+ // Draw the concentric "rings" grid lines that are
507
+ // arranged around the centerx/centery along with
508
+ // the radials that eminate from the center outwards
509
+
510
+ var origin = 0 - (RG.SVG.TRIG.PI / 2),
511
+ radials = (typeof prop.backgroundGridRadialsCount === 'number' ? prop.backgroundGridRadialsCount : this.data.length),
512
+ concentrics = prop.backgroundGridConcentricsCount,
513
+ step = RG.SVG.TRIG.TWOPI / radials;
514
+
515
+
516
+
517
+
518
+
519
+ // First draw the radial lines that emanate from the
520
+ // center outwards
521
+ if (radials > 0) {
522
+ // This draws the radials for the non-equi-angular ONLY
523
+ if (prop.variant === 'non-equi-angular') {
524
+
525
+
526
+
527
+
528
+
529
+
530
+
531
+
532
+
533
+
534
+
535
+
536
+
537
+
538
+ // Number of radials always matches the number of data pieces
539
+ var radials = this.data.length;
540
+
541
+ // Work out the total of the second part of each data bit
542
+ for (var i=0,total=0; i<this.data.length; ++i) {
543
+ total += this.data[i][1];
544
+ }
545
+
546
+ for (var i=0,sum=0; i<this.data.length; ++i) {
547
+
548
+ var coords = RG.SVG.TRIG.toCartesian({
549
+ cx: this.centerx,
550
+ cy: this.centery,
551
+ r: this.radius,
552
+ angle: origin + ( (sum / total) * RG.SVG.TRIG.TWOPI) + prop.backgroundGridRadialsAngleOffset
553
+ });
554
+
555
+ var str = 'M {1} {2} L {3} {4}'.format(
556
+ this.centerx,
557
+ this.centery,
558
+ coords.x,
559
+ coords.y
560
+ );
561
+
562
+ RG.SVG.create({
563
+ svg: this.svg,
564
+ type: 'path',
565
+ parent: grid,
566
+ attr: {
567
+ d: str,
568
+ stroke: prop.backgroundGridColor,
569
+ 'stroke-width': prop.backgroundGridLinewidth
570
+ }
571
+ });
572
+
573
+ sum += this.data[i][1];
574
+ }
575
+
576
+
577
+
578
+
579
+
580
+
581
+
582
+
583
+
584
+
585
+
586
+
587
+ // This draws the radials for normal and STACKED Rose charts
588
+ } else {
589
+ for (var i=0,len=radials; i<len; ++i) {
590
+
591
+ var coords = RG.SVG.TRIG.toCartesian({
592
+ cx: this.centerx,
593
+ cy: this.centery,
594
+ r: this.radius,
595
+ angle: origin + (i * step) + prop.backgroundGridRadialsAngleOffset
596
+ });
597
+
598
+ var str = 'M {1} {2} L {3} {4}'.format(
599
+ this.centerx,
600
+ this.centery,
601
+ coords.x,
602
+ coords.y
603
+ );
604
+
605
+ RG.SVG.create({
606
+ svg: this.svg,
607
+ type: 'path',
608
+ parent: grid,
609
+ attr: {
610
+ d: str,
611
+ stroke: prop.backgroundGridColor,
612
+ 'stroke-width': prop.backgroundGridLinewidth
613
+ }
614
+ });
615
+ }
616
+ }
617
+ }
618
+
619
+
620
+
621
+
622
+
623
+ // Draw the concentrics
624
+ if (concentrics > 0) {
625
+
626
+ for (var j=1; j<=concentrics; j++) {
627
+
628
+ // Add circle to the scene
629
+ RG.SVG.create({
630
+ svg: this.svg,
631
+ type: 'circle',
632
+ parent: grid,
633
+ attr: {
634
+ cx: this.centerx,
635
+ cy: this.centery,
636
+ r: this.radius * (j/concentrics),
637
+ fill: 'transparent',
638
+ stroke: prop.backgroundGridColor,
639
+ 'stroke-width': prop.backgroundGridLinewidth
640
+ }
641
+ });
642
+ }
643
+ }
644
+ }
645
+ };
646
+
647
+
648
+
649
+
650
+
651
+
652
+
653
+
654
+ //
655
+ // Draws the radar
656
+ //
657
+ this.drawRose = function (opt)
658
+ {
659
+ // Jump to another function if we're drawing a non-equi-angular chart
660
+ if (prop.variant === 'non-equi-angular') {
661
+ return this.drawRoseNonEquiAngular(opt);
662
+ }
663
+
664
+
665
+
666
+
667
+
668
+
669
+ var radians = RG.SVG.TRIG.TWOPI / this.data.length;
670
+
671
+ var group = RG.SVG.create({
672
+ svg: this.svg,
673
+ type:'g',
674
+ parent: this.svg.all,
675
+ attr: {
676
+ id: 'rgraph_rose_segments_' + this.id
677
+ }
678
+ });
679
+
680
+
681
+ // Now loop thru the data
682
+ for (var i=0,seq=0; i<this.data.length; ++i,++seq) {
683
+
684
+ var radius = (this.data[i] / this.scale.max) * this.radius,
685
+ start = (i / this.data.length) * RG.SVG.TRIG.TWOPI,
686
+ end = ((i / this.data.length) * RG.SVG.TRIG.TWOPI) + radians;
687
+
688
+ // Get the exploded distance
689
+ var explosion = this.getExploded({
690
+ index: i,
691
+ start: start - RG.SVG.TRIG.HALFPI,
692
+ end: end - RG.SVG.TRIG.HALFPI
693
+ });
694
+
695
+
696
+
697
+
698
+
699
+
700
+
701
+
702
+
703
+
704
+
705
+
706
+
707
+
708
+
709
+
710
+
711
+
712
+
713
+ // Is the data piece an array or a number?
714
+ if (typeof this.data[i] === 'object' && !RG.SVG.isNull(this.data[i])) {
715
+
716
+ // Create a group for the parts of this segment
717
+ var segment_group = RG.SVG.create({
718
+ svg: this.svg,
719
+ type: 'g',
720
+ parent: group,
721
+ attr: {
722
+ id: 'rose_' + this.id + '_segment_group_' + i
723
+ }
724
+ });
725
+
726
+ for (var j=0,sum=0,accRadius=0; j<this.data[i].length; ++j,++seq) {
727
+
728
+ sum += this.data[i][j];
729
+
730
+ var radius = (sum / this.scale.max) * this.radius;
731
+
732
+ // This (I think is the OUTER curve in the segment
733
+ var arcPath = RG.SVG.TRIG.getArcPath2({
734
+ cx: this.centerx + explosion[0],
735
+ cy: this.centery + explosion[1],
736
+ r: radius,
737
+ start: start + prop.margin + prop.segmentsAngleOffset,
738
+ end: end - prop.margin + prop.segmentsAngleOffset,
739
+ anticlockwise: false
740
+ });
741
+
742
+ // The inner most segment
743
+ if (j === 0) {
744
+ arcPath = '{1} z'.format(
745
+ arcPath
746
+ );
747
+ } else {
748
+
749
+ var arcPath2 = RG.SVG.TRIG.getArcPath2({
750
+ cx: this.centerx + explosion[0],
751
+ cy: this.centery + explosion[1],
752
+ r: prevRadius,
753
+ start: end - prop.margin + prop.segmentsAngleOffset,
754
+ end: start + prop.margin + prop.segmentsAngleOffset,
755
+ anticlockwise: true
756
+ });
757
+ arcPath = '{1} L {2} {3} {4}'.format(
758
+ arcPath,
759
+ this.centerx + explosion[0],
760
+ this.centery + explosion[1],
761
+ arcPath2
762
+ );
763
+ }
764
+
765
+ var path = RG.SVG.create({
766
+ svg: this.svg,
767
+ type: 'path',
768
+ parent: segment_group,
769
+ attr: {
770
+ d: arcPath,
771
+ fill: prop.colorsSequential ? prop.colors[seq] : prop.colors[j],
772
+ 'fill-opacity': prop.colorsOpacity,
773
+ stroke: prop.strokestyle,
774
+ 'stroke-width': prop.linewidth,
775
+
776
+ 'data-tooltip': (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[seq] : '',
777
+ 'data-index': i,
778
+ 'data-centerx': this.centerx + explosion[0],
779
+ 'data-centery': this.centery + explosion[1],
780
+ 'data-group': i,
781
+ 'data-subindex': j,
782
+ 'data-value': this.data[i][j],
783
+ 'data-start-angle': start,
784
+ 'data-end-angle': end,
785
+ 'data-radius': radius,
786
+ 'data-radius-inner': typeof prevRadius === 'number' ? prevRadius : 0,
787
+ 'data-sequential-index': seq
788
+ }
789
+ });
790
+
791
+
792
+ // Install the tooltip listener
793
+ if (prop.tooltips && prop.tooltips[seq]) {
794
+
795
+ // Make the tooltipsEvent default to click
796
+ if (prop.tooltipsEvent !== 'mousemove') {
797
+ prop.tooltipsEvent = 'click';
798
+ }
799
+
800
+ (function (index, group, seq, obj)
801
+ {
802
+ path.addEventListener(prop.tooltipsEvent, function (e)
803
+ {
804
+ obj.removeHighlight();
805
+
806
+ // Show the tooltip
807
+ RG.SVG.tooltip({
808
+ object: obj,
809
+ group: group,
810
+ index: index,
811
+ sequentialIndex: seq,
812
+ text: prop.tooltips[seq],
813
+ event: e
814
+ });
815
+
816
+ // Highlight the rect that has been clicked on
817
+ obj.highlight(e.target);
818
+
819
+ var highlight = RG.SVG.REG.get('highlight');
820
+
821
+ if (prop.tooltipsEvent === 'mousemove') {
822
+ highlight.style.cursor = 'pointer';
823
+ }
824
+
825
+ }, false);
826
+
827
+ // Install the event listener that changes the
828
+ // cursor if necessary
829
+ if (prop.tooltipsEvent === 'click') {
830
+ path.addEventListener('mousemove', function (e)
831
+ {
832
+ e.target.style.cursor = 'pointer';
833
+ }, false);
834
+ }
835
+
836
+ }(j, i, seq, this));
837
+ }
838
+
839
+ // Add the segment to the angles and angles2 array
840
+ this.angles.push({
841
+ object: path,
842
+ index: seq,
843
+ cx: this.centerx + explosion[0],
844
+ cy: this.centery + explosion[1],
845
+ start: start,
846
+ end: end,
847
+ radius: radius,
848
+ 'radius-inner': prevRadius,
849
+ value: this.data[i][j]
850
+ });
851
+
852
+ this.angles2[i].push({
853
+ object: path,
854
+ index: seq,
855
+ cx: this.centerx + explosion[0],
856
+ cy: this.centery + explosion[1],
857
+ start: start,
858
+ end: end,
859
+ radius: radius,
860
+ 'radius-inner': prevRadius,
861
+ value: this.data[i][j]
862
+ });
863
+
864
+ var prevRadius = radius;
865
+ }
866
+
867
+
868
+
869
+
870
+
871
+
872
+
873
+
874
+
875
+
876
+ seq--;
877
+
878
+
879
+
880
+
881
+
882
+
883
+
884
+
885
+
886
+
887
+
888
+
889
+
890
+ // A regular number
891
+ } else {
892
+
893
+ var arcPath = RG.SVG.TRIG.getArcPath2({
894
+ cx: this.centerx + explosion[0],
895
+ cy: this.centery + explosion[1],
896
+ r: radius,
897
+ start: start + prop.margin + prop.segmentsAngleOffset,
898
+ end: end - prop.margin + prop.segmentsAngleOffset,
899
+ anticlockwise: false
900
+ });
901
+
902
+ var path = RG.SVG.create({
903
+ svg: this.svg,
904
+ type: 'path',
905
+ parent: group,
906
+ attr: {
907
+ d: '{1} z'.format(
908
+ arcPath
909
+ ),
910
+ fill: prop.colorsSequential ? prop.colors[i] : prop.colors[0],
911
+ 'fill-opacity': prop.colorsOpacity,
912
+ stroke: prop.strokestyle,
913
+ 'stroke-width': prop.linewidth,
914
+
915
+ 'data-tooltip': (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[i] : '',
916
+ 'data-index': i,
917
+ 'data-centerx': this.centerx + explosion[0],
918
+ 'data-centery': this.centery + explosion[1],
919
+ 'data-value': this.data[i],
920
+ 'data-start-angle': start,
921
+ 'data-end-angle': end,
922
+ 'data-radius': radius,
923
+ 'data-sequential': seq
924
+ }
925
+ });
926
+
927
+ // Add the segment to the angles array
928
+ this.angles.push({
929
+ object: path,
930
+ index: i,
931
+ cx: this.centerx + explosion[0],
932
+ cy: this.centery + explosion[1],
933
+ start: start,
934
+ end: end,
935
+ radius: radius,
936
+ value: this.data[i]
937
+ });
938
+
939
+ this.angles2[i].push({
940
+ object: path,
941
+ index: seq,
942
+ cx: this.centerx + explosion[0],
943
+ cy: this.centery + explosion[1],
944
+ start: start,
945
+ end: end,
946
+ radius: radius,
947
+ 'radius-inner': prevRadius,
948
+ value: this.data[i][j]
949
+ });
950
+
951
+
952
+
953
+
954
+ if (prop.tooltips && prop.tooltips[i]) {
955
+
956
+ // Make the tooltipsEvent default to click
957
+ if (prop.tooltipsEvent !== 'mousemove') {
958
+ prop.tooltipsEvent = 'click';
959
+ }
960
+
961
+ (function (index, obj)
962
+ {
963
+ path.addEventListener(prop.tooltipsEvent, function (e)
964
+ {
965
+ obj.removeHighlight();
966
+
967
+ // Show the tooltip
968
+ RG.SVG.tooltip({
969
+ object: obj,
970
+ index: index,
971
+ group: index,
972
+ sequentialIndex: index,
973
+ text: prop.tooltips[index],
974
+ event: e
975
+ });
976
+
977
+ // Highlight the rect that has been clicked on
978
+ obj.highlight(e.target);
979
+
980
+ var highlight = RG.SVG.REG.get('highlight');
981
+
982
+ if (prop.tooltipsEvent === 'mousemove') {
983
+ highlight.style.cursor = 'pointer';
984
+ }
985
+
986
+ }, false);
987
+
988
+ // Install the event listener that changes the
989
+ // cursor if necessary
990
+ if (prop.tooltipsEvent === 'click') {
991
+ path.addEventListener('mousemove', function (e)
992
+ {
993
+ e.target.style.cursor = 'pointer';
994
+ }, false);
995
+ }
996
+
997
+ }(i, this));
998
+ }
999
+ }
1000
+ }
1001
+ };
1002
+
1003
+
1004
+
1005
+
1006
+
1007
+
1008
+
1009
+
1010
+ //
1011
+ // Draws the radar, but only the non-equi-angular variant
1012
+ //
1013
+ this.drawRoseNonEquiAngular = function (opt)
1014
+ {
1015
+ var group = RG.SVG.create({
1016
+ svg: this.svg,
1017
+ type:'g',
1018
+ parent: this.svg.all,
1019
+ attr: {
1020
+ id: 'rgraph_rose_segments_' + this.id
1021
+ }
1022
+ });
1023
+
1024
+ //Loop through the data summing the second data-pieces
1025
+ for (var i=0,total=0; i<this.data.length; ++i) {
1026
+ total += parseFloat(this.data[i][1]);
1027
+ }
1028
+
1029
+
1030
+
1031
+
1032
+
1033
+
1034
+
1035
+
1036
+
1037
+
1038
+
1039
+ // The initial angles
1040
+ var start = 0;
1041
+
1042
+
1043
+
1044
+
1045
+ // Now loop thru the data
1046
+ for (var i=0,seq=0; i<this.data.length; ++i,++seq) {
1047
+
1048
+ var radians = (this.data[i][1] / total) * RG.SVG.TRIG.TWOPI,
1049
+ end = start + radians;
1050
+
1051
+ // Get the exploded distance
1052
+ var explosion = this.getExploded({
1053
+ index: i,
1054
+ start: start - RG.SVG.TRIG.HALFPI,
1055
+ end: end - RG.SVG.TRIG.HALFPI
1056
+ });
1057
+
1058
+
1059
+
1060
+
1061
+
1062
+
1063
+
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+ // A stacked non-equi-angular segment
1073
+ if (typeof this.data[i][0] === 'object' && !RG.SVG.isNull(this.data[i][0])) {
1074
+
1075
+
1076
+
1077
+ // Loop thru the set of values for this segment
1078
+ for (var j=0,sum=0; j<this.data[i][0].length; ++j,++seq) {
1079
+
1080
+ sum += this.data[i][0][j];
1081
+
1082
+ // First segment in the stack or not?
1083
+ if (j === 0) {
1084
+
1085
+ var prevRadius = 0,
1086
+ radius = (sum / this.scale.max) * this.radius;
1087
+
1088
+ var arcPath = RG.SVG.TRIG.getArcPath2({
1089
+ cx: this.centerx + explosion[0],
1090
+ cy: this.centery + explosion[1],
1091
+ r: radius,
1092
+ start: start + prop.margin + prop.segmentsAngleOffset,
1093
+ end: end - prop.margin + prop.segmentsAngleOffset,
1094
+ anticlockwise: false
1095
+ });
1096
+
1097
+ var arcPath2 = '';
1098
+
1099
+ } else {
1100
+
1101
+ var prevRadius = radius, // The previous iterations radius
1102
+ radius = (sum / this.scale.max) * this.radius;
1103
+
1104
+ var arcPath = RG.SVG.TRIG.getArcPath2({
1105
+ cx: this.centerx + explosion[0],
1106
+ cy: this.centery + explosion[1],
1107
+ r: radius,
1108
+ start: start + prop.margin + prop.segmentsAngleOffset,
1109
+ end: end - prop.margin + prop.segmentsAngleOffset,
1110
+ anticlockwise: false
1111
+ });
1112
+
1113
+ var arcPath2 = RG.SVG.TRIG.getArcPath2({
1114
+ cx: this.centerx + explosion[0],
1115
+ cy: this.centery + explosion[1],
1116
+ r: prevRadius,
1117
+ start: end - prop.margin + prop.segmentsAngleOffset,
1118
+ end: start + prop.margin + prop.segmentsAngleOffset,
1119
+ anticlockwise: true
1120
+ });
1121
+ }
1122
+
1123
+ var path = RG.SVG.create({
1124
+ svg: this.svg,
1125
+ type: 'path',
1126
+ parent: group,
1127
+ attr: {
1128
+ d: '{1} {2} z'.format(
1129
+ arcPath,
1130
+ arcPath2
1131
+ ),
1132
+ fill: prop.colorsSequential ? prop.colors[seq] : prop.colors[j],
1133
+ 'fill-opacity': prop.colorsOpacity,
1134
+ stroke: prop.strokestyle,
1135
+ 'stroke-width': prop.linewidth,
1136
+ 'data-tooltip': (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[i] : '',
1137
+ 'data-centerx': this.centerx + explosion[0],
1138
+ 'data-centery': this.centery + explosion[1],
1139
+ 'data-index': '[{1},{2}]'.format(i, j),
1140
+ 'data-value': this.data[i][0][j],
1141
+ 'data-start-angle': start,
1142
+ 'data-end-angle': end,
1143
+ 'data-radius': radius,
1144
+ 'data-radius-inner': prevRadius,
1145
+ 'data-sequential': seq
1146
+ }
1147
+ });
1148
+
1149
+
1150
+
1151
+ // Add the segment to the angles array
1152
+ this.angles.push({
1153
+ object: path,
1154
+ index: i,
1155
+ cx: this.centerx + explosion[0],
1156
+ cy: this.centery + explosion[1],
1157
+ start: start,
1158
+ end: end,
1159
+ radius: radius,
1160
+ 'radius-inner': prevRadius,
1161
+ value: this.data[i][0]
1162
+ });
1163
+
1164
+ this.angles2[i].push({
1165
+ object: path,
1166
+ index: seq,
1167
+ cx: this.centerx + explosion[0],
1168
+ cy: this.centery + explosion[1],
1169
+ start: start,
1170
+ end: end,
1171
+ radius: radius,
1172
+ 'radius-inner': prevRadius,
1173
+ value: this.data[i][j]
1174
+ });
1175
+
1176
+
1177
+
1178
+
1179
+ // Install tooltips listeners
1180
+ if (prop.tooltips && prop.tooltips[seq]) {
1181
+
1182
+ // Make the tooltipsEvent default to click
1183
+ if (prop.tooltipsEvent !== 'mousemove') {
1184
+ prop.tooltipsEvent = 'click';
1185
+ }
1186
+
1187
+ (function (index,group,seq,obj)
1188
+ {
1189
+ path.addEventListener(prop.tooltipsEvent, function (e)
1190
+ {
1191
+ obj.removeHighlight();
1192
+
1193
+ // Show the tooltip
1194
+ RG.SVG.tooltip({
1195
+ object: obj,
1196
+ index: index,
1197
+ group: group,
1198
+ sequentialIndex: seq,
1199
+ text: prop.tooltips[seq],
1200
+ event: e
1201
+ });
1202
+
1203
+ // Highlight the rect that has been clicked on
1204
+ obj.highlight(e.target);
1205
+
1206
+ var highlight = RG.SVG.REG.get('highlight');
1207
+
1208
+ if (prop.tooltipsEvent === 'mousemove') {
1209
+ highlight.style.cursor = 'pointer';
1210
+ }
1211
+
1212
+ }, false);
1213
+
1214
+ // Install the event listener that changes the
1215
+ // cursor if necessary
1216
+ if (prop.tooltipsEvent === 'click') {
1217
+ path.addEventListener('mousemove', function (e)
1218
+ {
1219
+ e.target.style.cursor = 'pointer';
1220
+ }, false);
1221
+ }
1222
+
1223
+ }(j, i, seq, this));
1224
+ }
1225
+ var prevRadius = radius;
1226
+ }
1227
+ seq--
1228
+
1229
+
1230
+
1231
+
1232
+
1233
+
1234
+
1235
+
1236
+
1237
+
1238
+
1239
+
1240
+
1241
+
1242
+
1243
+
1244
+
1245
+
1246
+
1247
+
1248
+ // A regular non-equi-angular segment
1249
+ } else {
1250
+ var radius = (this.data[i][0] / this.scale.max) * this.radius;
1251
+
1252
+ var arcPath = RG.SVG.TRIG.getArcPath2({
1253
+ cx: this.centerx + explosion[0],
1254
+ cy: this.centery + explosion[1],
1255
+ r: radius,
1256
+ start: start + prop.margin + prop.segmentsAngleOffset,
1257
+ end: end - prop.margin + prop.segmentsAngleOffset,
1258
+ anticlockwise: false
1259
+ });
1260
+
1261
+ var path = RG.SVG.create({
1262
+ svg: this.svg,
1263
+ type: 'path',
1264
+ parent: group,
1265
+ attr: {
1266
+ d: '{1} z'.format(
1267
+ arcPath
1268
+ ),
1269
+ fill: prop.colorsSequential ? prop.colors[i] : prop.colors[0],
1270
+ 'fill-opacity': prop.colorsOpacity,
1271
+ stroke: prop.strokestyle,
1272
+ 'stroke-width': prop.linewidth,
1273
+
1274
+ 'data-tooltip': (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[i] : '',
1275
+ 'data-centerx': this.centerx + explosion[0],
1276
+ 'data-centery': this.centery + explosion[1],
1277
+ 'data-index': i,
1278
+ 'data-value': this.data[i],
1279
+ 'data-start-angle': start,
1280
+ 'data-end-angle': end,
1281
+ 'data-radius': radius,
1282
+ 'data-sequential': seq
1283
+ }
1284
+ });
1285
+
1286
+ // Add the segment to the angles array
1287
+ this.angles.push({
1288
+ object: path,
1289
+ index: i,
1290
+ cx: this.centerx + explosion[0],
1291
+ cy: this.centery + explosion[1],
1292
+ start: start,
1293
+ end: end,
1294
+ radius: radius,
1295
+ value: this.data[i][0]
1296
+ });
1297
+
1298
+ this.angles2[i].push({
1299
+ object: path,
1300
+ index: seq,
1301
+ cx: this.centerx + explosion[0],
1302
+ cy: this.centery + explosion[1],
1303
+ start: start,
1304
+ end: end,
1305
+ radius: radius,
1306
+ 'radius-inner': 0,
1307
+ value: this.data[i][j]
1308
+ });
1309
+
1310
+
1311
+
1312
+
1313
+ if (prop.tooltips && prop.tooltips[i]) {
1314
+
1315
+ // Make the tooltipsEvent default to click
1316
+ if (prop.tooltipsEvent !== 'mousemove') {
1317
+ prop.tooltipsEvent = 'click';
1318
+ }
1319
+
1320
+ (function (index, group, seq, obj)
1321
+ {
1322
+ path.addEventListener(prop.tooltipsEvent, function (e)
1323
+ {
1324
+ obj.removeHighlight();
1325
+
1326
+ // Show the tooltip
1327
+ RG.SVG.tooltip({
1328
+ object: obj,
1329
+ index: index,
1330
+ group: index,
1331
+ sequentialIndex: seq,
1332
+ text: prop.tooltips[index],
1333
+ event: e
1334
+ });
1335
+
1336
+ // Highlight the rect that has been clicked on
1337
+ obj.highlight(e.target);
1338
+
1339
+ var highlight = RG.SVG.REG.get('highlight');
1340
+
1341
+ if (prop.tooltipsEvent === 'mousemove') {
1342
+ highlight.style.cursor = 'pointer';
1343
+ }
1344
+
1345
+ }, false);
1346
+
1347
+ // Install the event listener that changes the
1348
+ // cursor if necessary
1349
+ if (prop.tooltipsEvent === 'click') {
1350
+ path.addEventListener('mousemove', function (e)
1351
+ {
1352
+ e.target.style.cursor = 'pointer';
1353
+ }, false);
1354
+ }
1355
+
1356
+ }(i, i, seq, this));
1357
+ }
1358
+ }
1359
+
1360
+
1361
+ // Increment the start angle for the next iteration of the loop
1362
+ start += radians;
1363
+ }
1364
+ };
1365
+
1366
+
1367
+
1368
+
1369
+
1370
+
1371
+
1372
+
1373
+ //
1374
+ // Redraws the chart if required
1375
+ //
1376
+ this.redrawRose = function ()
1377
+ {
1378
+ };
1379
+
1380
+
1381
+
1382
+
1383
+
1384
+
1385
+
1386
+
1387
+ //
1388
+ // Draw the labels
1389
+ //
1390
+ this.drawLabels = function ()
1391
+ {
1392
+ // Draw the scale if required
1393
+ if (prop.scaleVisible) {
1394
+ for (var i=0; i<this.scale.labels.length; ++i) {
1395
+
1396
+ var x = this.centerx;
1397
+ var y = this.centery - (this.radius / this.scale.labels.length * (i+1) );
1398
+
1399
+
1400
+ RG.SVG.text({
1401
+ object: this,
1402
+ svg: this.svg,
1403
+ parent: this.svg.all,
1404
+ text: this.scale.labels[i],
1405
+ size: prop.scaleSize || prop.textSize - 2,
1406
+ x: x,
1407
+ y: y,
1408
+ halign: 'center',
1409
+ valign: 'center',
1410
+ background: 'rgba(255,255,255,0.7)',
1411
+ padding:2,
1412
+ color: prop.scaleColor || prop.textColor,
1413
+ bold: typeof prop.scaleBold === 'boolean' ? prop.scaleBold : prop.textBold,
1414
+ italic: typeof prop.scaleItalic === 'boolean' ? prop.scaleItalic : prop.textItalic,
1415
+ font: prop.scaleFont || prop.textFont
1416
+ });
1417
+ }
1418
+
1419
+ // Draw the zero label
1420
+ var str = RG.SVG.numberFormat({
1421
+ object: this,
1422
+ num: this.scale.min.toFixed(prop.scaleDecimals),
1423
+ prepend: prop.scaleUnitsPre,
1424
+ append: prop.scaleUnitsPost,
1425
+ point: prop.scalePoint,
1426
+ thousand: prop.scaleThousand,
1427
+ formatter: prop.scaleFormatter
1428
+ });
1429
+
1430
+
1431
+ RG.SVG.text({
1432
+ object: this,
1433
+ svg: this.svg,
1434
+ parent: this.svg.all,
1435
+ text: str,
1436
+ size: prop.scaleSize || prop.textSize - 2,
1437
+ x: this.centerx,
1438
+ y: this.centery,
1439
+ halign: 'center',
1440
+ valign: 'center',
1441
+ background: 'rgba(255,255,255,0.7)',
1442
+ padding:2,
1443
+ color: prop.scaleColor || prop.textColor,
1444
+ bold: typeof prop.scaleBold === 'boolean' ? prop.scaleBold : prop.textBold,
1445
+ italic: typeof prop.scaleItalic === 'boolean' ? prop.scaleItalic : prop.textItalic,
1446
+ font: prop.scaleFont || prop.textFont
1447
+ });
1448
+ }
1449
+
1450
+
1451
+
1452
+
1453
+
1454
+
1455
+
1456
+ // Used further down
1457
+ var halign;
1458
+
1459
+ // Set a default size for the labels
1460
+ if (typeof prop.labelsSize !== 'number') {
1461
+ prop.labelsSize = prop.textSize + 4;
1462
+ }
1463
+
1464
+
1465
+
1466
+ // Draw the circular labels if necessary
1467
+ for (var i=0; i<prop.labels.length; ++i) {
1468
+
1469
+ if (prop.variant === 'non-equi-angular') {
1470
+ var angle = ((this.angles2[i][0].end - this.angles2[i][0].start) / 2) + this.angles2[i][0].start - RG.SVG.TRIG.HALFPI;
1471
+ } else {
1472
+ var angle = (((RG.SVG.TRIG.TWOPI / prop.labels.length)) * i) - RG.SVG.TRIG.HALFPI + prop.labelsAngleOffset + ((this.angles2[i][0].end - this.angles2[i][0].start) / 2);
1473
+ }
1474
+
1475
+ var endpoint = RG.SVG.TRIG.getRadiusEndPoint({
1476
+ r: this.radius + prop.labelsRadialMargin,
1477
+ angle: angle
1478
+ });
1479
+
1480
+ // Accommodate the explosion for the label
1481
+ var explosion = this.getExploded({
1482
+ index: i,
1483
+ start: this.angles2[i][0].start - RG.SVG.TRIG.HALFPI,
1484
+ end: this.angles2[i][0].end - RG.SVG.TRIG.HALFPI
1485
+ });
1486
+
1487
+ endpoint[0] += this.centerx + explosion[0];
1488
+ endpoint[1] += this.centery + explosion[1];
1489
+
1490
+
1491
+ // Do the alignment based on which quadrant the label is in
1492
+ if (ma.round(endpoint[0]) > this.centerx) {
1493
+ halign = 'left';
1494
+ } else if (ma.round(endpoint[0]) === this.centerx) {
1495
+ halign = 'center';
1496
+ } else {
1497
+ halign = 'right';
1498
+ }
1499
+
1500
+
1501
+
1502
+
1503
+
1504
+ RG.SVG.text({
1505
+ object: this,
1506
+ svg: this.svg,
1507
+ parent: this.svg.all,
1508
+ text: typeof prop.labels[i] === 'string' ? prop.labels[i] : '',
1509
+ size: prop.labelsSize,
1510
+ x: endpoint[0],
1511
+ y: endpoint[1],
1512
+ halign: halign,
1513
+ valign: 'center',
1514
+ background: 'rgba(255,255,255,0.7)',
1515
+ padding:2,
1516
+ color: prop.labelsColor || prop.textColor,
1517
+ bold: typeof prop.labelsBold === 'boolean' ? prop.labelsBold : prop.textBold,
1518
+ italic: typeof prop.labelsItalic === 'boolean' ? prop.labelsItalic : prop.textItalic,
1519
+ font: prop.labelsFont || prop.textFont
1520
+ });
1521
+ }
1522
+ };
1523
+
1524
+
1525
+
1526
+
1527
+
1528
+
1529
+
1530
+
1531
+ /**
1532
+ * This function can be used to highlight a segment on the chart
1533
+ *
1534
+ * @param object circle The circle to highlight
1535
+ */
1536
+ this.highlight = function (path)
1537
+ {
1538
+ var path = path.getAttribute('d');
1539
+
1540
+ var highlight = RG.SVG.create({
1541
+ svg: this.svg,
1542
+ parent: this.svg.all,
1543
+ type: 'path',
1544
+ attr: {
1545
+ d: path,
1546
+ fill: prop.highlightFill,
1547
+ stroke: prop.highlightStroke,
1548
+ 'stroke-width': prop.highlightLinewidth
1549
+ }
1550
+ });
1551
+
1552
+
1553
+ if (prop.tooltipsEvent === 'mousemove') {
1554
+ highlight.addEventListener('mouseout', function (e)
1555
+ {
1556
+ highlight.parentNode.removeChild(highlight);
1557
+ RG.SVG.hideTooltip();
1558
+
1559
+ RG.SVG.REG.set('highlight', null);
1560
+ }, false);
1561
+ }
1562
+
1563
+
1564
+ // Store the highlight rect in the registry so
1565
+ // it can be cleared later
1566
+ RG.SVG.REG.set('highlight', highlight);
1567
+ };
1568
+
1569
+
1570
+
1571
+
1572
+
1573
+
1574
+
1575
+
1576
+ /**
1577
+ * This allows for easy specification of gradients
1578
+ */
1579
+ this.parseColors = function ()
1580
+ {
1581
+ // Save the original colors so that they can be restored when the canvas is reset
1582
+ if (!Object.keys(this.originalColors).length) {
1583
+ this.originalColors = {
1584
+ colors: RG.SVG.arrayClone(prop.colors),
1585
+ highlightFill: RG.SVG.arrayClone(prop.highlightFill)
1586
+ }
1587
+ }
1588
+
1589
+
1590
+ // colors
1591
+ var colors = prop.colors;
1592
+
1593
+ if (colors) {
1594
+ for (var i=0; i<colors.length; ++i) {
1595
+ colors[i] = RG.SVG.parseColorRadial({
1596
+ object: this,
1597
+ color: colors[i]
1598
+ });
1599
+ }
1600
+ }
1601
+
1602
+ // Highlight fill
1603
+ prop.highlightFill = RG.SVG.parseColorRadial({
1604
+ object: this,
1605
+ color: prop.highlightFill
1606
+ });
1607
+ };
1608
+
1609
+
1610
+
1611
+
1612
+
1613
+
1614
+
1615
+
1616
+ //
1617
+ // Get the maximum value
1618
+ //
1619
+ this.getMaxValue = function ()
1620
+ {
1621
+ var max = 0;
1622
+
1623
+ if (prop.variant === 'non-equi-angular') {
1624
+ for (var i=0; i<this.data.length; ++i) {
1625
+ if (!RG.SVG.isNull(this.data[i])) {
1626
+ if (typeof this.data[i][0] === 'number') {
1627
+ max = ma.max(max, this.data[i][0]);
1628
+ } else if (typeof this.data[i][0] === 'object'){
1629
+ max = ma.max(max, RG.SVG.arraySum(this.data[i][0]));
1630
+ }
1631
+ }
1632
+ }
1633
+ } else {
1634
+ for (var i=0; i<this.data.length; ++i) {
1635
+ if (!RG.SVG.isNull(this.data[i])) {
1636
+ if (typeof this.data[i] === 'number') {
1637
+ max = ma.max(max, this.data[i]);
1638
+ } else if (typeof this.data[i] === 'object') {
1639
+ max = ma.max(max, RG.SVG.arraySum(this.data[i]));
1640
+ }
1641
+ }
1642
+ }
1643
+ }
1644
+
1645
+ this.max = max;
1646
+ };
1647
+
1648
+
1649
+
1650
+
1651
+
1652
+
1653
+
1654
+
1655
+ //
1656
+ // Gets the radius of a value
1657
+ //
1658
+ //@param number The value to get the radius for
1659
+ //
1660
+ this.getRadius = function (value)
1661
+ {
1662
+ return ( (value - prop.scaleMin) / (this.scale.max - prop.scaleMin) ) * this.radius;
1663
+ };
1664
+
1665
+
1666
+
1667
+
1668
+
1669
+
1670
+
1671
+
1672
+ //
1673
+ // A roundRobin effect for the Pie chart
1674
+ //
1675
+ // @param object Options for the effect
1676
+ // @param function An optional callback function to call when
1677
+ // the effect is complete
1678
+ //
1679
+ this.roundRobin = function ()
1680
+ {
1681
+ };
1682
+
1683
+
1684
+
1685
+
1686
+
1687
+
1688
+
1689
+
1690
+ /**
1691
+ * Using a function to add events makes it easier to facilitate method
1692
+ * chaining
1693
+ *
1694
+ * @param string type The type of even to add
1695
+ * @param function func
1696
+ */
1697
+ this.on = function (type, func)
1698
+ {
1699
+ if (type.substr(0,2) !== 'on') {
1700
+ type = 'on' + type;
1701
+ }
1702
+
1703
+ RG.SVG.addCustomEventListener(this, type, func);
1704
+
1705
+ return this;
1706
+ };
1707
+
1708
+
1709
+
1710
+
1711
+
1712
+
1713
+
1714
+
1715
+ //
1716
+ // Used in chaining. Runs a function there and then - not waiting for
1717
+ // the events to fire (eg the onbeforedraw event)
1718
+ //
1719
+ // @param function func The function to execute
1720
+ //
1721
+ this.exec = function (func)
1722
+ {
1723
+ func(this);
1724
+
1725
+ return this;
1726
+ };
1727
+
1728
+
1729
+
1730
+
1731
+
1732
+
1733
+
1734
+
1735
+ //
1736
+ // Removes the tooltip highlight from the chart
1737
+ //
1738
+ this.removeHighlight =
1739
+ this.hideHighlight = function ()
1740
+ {
1741
+ var highlight = RG.SVG.REG.get('highlight');
1742
+
1743
+ if (highlight && this.highlight_node) {
1744
+ this.highlight_node.setAttribute('fill','transparent');
1745
+ this.highlight_node.setAttribute('stroke','transparent');
1746
+
1747
+ RG.SVG.REG.set('highlight', null);
1748
+ }
1749
+ };
1750
+
1751
+
1752
+
1753
+
1754
+
1755
+
1756
+
1757
+
1758
+ //
1759
+ // Returns the exploded X/Y for a given explosion
1760
+ //
1761
+ //TODO Needs updating to current coding style, including converting
1762
+ // arguments to an object
1763
+ //
1764
+ this.getExploded = function (opt)
1765
+ {
1766
+ var index = opt.index,
1767
+ start = opt.start,
1768
+ end = opt.end,
1769
+ exploded = prop.exploded,
1770
+ explodedX,
1771
+ explodedY;
1772
+
1773
+ /**
1774
+ * Retrieve any exploded - the exploded can be an array of numbers or a single number
1775
+ * (which is applied to all segments)
1776
+ */
1777
+ if (typeof exploded === 'object' && typeof exploded[index] === 'number') {
1778
+ explodedX = ma.cos(((end - start) / 2) + start) * exploded[index];
1779
+ explodedY = (ma.sin(((end - start) / 2) + start) * exploded[index]);
1780
+
1781
+ } else if (typeof exploded === 'number') {
1782
+ explodedX = ma.cos(((end - start) / 2) + start) * exploded;
1783
+ explodedY = ma.sin(((end - start) / 2) + start) * exploded;
1784
+
1785
+ } else {
1786
+ explodedX = 0;
1787
+ explodedY = 0;
1788
+ }
1789
+
1790
+ return [explodedX, explodedY];
1791
+ };
1792
+
1793
+
1794
+
1795
+
1796
+
1797
+
1798
+
1799
+
1800
+ //
1801
+ // Set the options that the user has provided
1802
+ //
1803
+ for (i in conf.options) {
1804
+ if (typeof i === 'string') {
1805
+ this.set(i, conf.options[i]);
1806
+ }
1807
+ }
1808
+ };
1809
+
1810
+
1811
+
1812
+ return this;
1813
+
1814
+
1815
+
1816
+
1817
+ // End module pattern
1818
+ })(window, document);