rgraph-rails 1.0.8 → 4.62

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