rgraph-rails 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/lib/rgraph-rails/version.rb +1 -1
  4. data/license.txt +4 -16
  5. data/vendor/assets/javascripts/RGraph.bar.js +3734 -241
  6. data/vendor/assets/javascripts/RGraph.bipolar.js +2005 -115
  7. data/vendor/assets/javascripts/RGraph.common.annotate.js +395 -35
  8. data/vendor/assets/javascripts/RGraph.common.context.js +595 -30
  9. data/vendor/assets/javascripts/RGraph.common.core.js +5282 -405
  10. data/vendor/assets/javascripts/RGraph.common.csv.js +276 -19
  11. data/vendor/assets/javascripts/RGraph.common.deprecated.js +450 -35
  12. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1395 -86
  13. data/vendor/assets/javascripts/RGraph.common.effects.js +1545 -90
  14. data/vendor/assets/javascripts/RGraph.common.key.js +753 -54
  15. data/vendor/assets/javascripts/RGraph.common.resizing.js +563 -37
  16. data/vendor/assets/javascripts/RGraph.common.sheets.js +352 -29
  17. data/vendor/assets/javascripts/RGraph.common.tooltips.js +450 -32
  18. data/vendor/assets/javascripts/RGraph.common.zoom.js +219 -14
  19. data/vendor/assets/javascripts/RGraph.drawing.background.js +570 -35
  20. data/vendor/assets/javascripts/RGraph.drawing.circle.js +544 -35
  21. data/vendor/assets/javascripts/RGraph.drawing.image.js +755 -52
  22. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +645 -41
  23. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +633 -37
  24. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +514 -36
  25. data/vendor/assets/javascripts/RGraph.drawing.poly.js +559 -39
  26. data/vendor/assets/javascripts/RGraph.drawing.rect.js +548 -35
  27. data/vendor/assets/javascripts/RGraph.drawing.text.js +664 -36
  28. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +812 -50
  29. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +856 -51
  30. data/vendor/assets/javascripts/RGraph.fuel.js +964 -58
  31. data/vendor/assets/javascripts/RGraph.funnel.js +984 -55
  32. data/vendor/assets/javascripts/RGraph.gantt.js +1354 -77
  33. data/vendor/assets/javascripts/RGraph.gauge.js +1421 -87
  34. data/vendor/assets/javascripts/RGraph.hbar.js +2562 -146
  35. data/vendor/assets/javascripts/RGraph.hprogress.js +1401 -80
  36. data/vendor/assets/javascripts/RGraph.line.js +4226 -244
  37. data/vendor/assets/javascripts/RGraph.meter.js +1280 -74
  38. data/vendor/assets/javascripts/RGraph.modaldialog.js +301 -19
  39. data/vendor/assets/javascripts/RGraph.odo.js +1264 -71
  40. data/vendor/assets/javascripts/RGraph.pie.js +2288 -137
  41. data/vendor/assets/javascripts/RGraph.radar.js +1847 -110
  42. data/vendor/assets/javascripts/RGraph.rose.js +1977 -108
  43. data/vendor/assets/javascripts/RGraph.rscatter.js +1432 -80
  44. data/vendor/assets/javascripts/RGraph.scatter.js +3036 -168
  45. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1120 -60
  46. data/vendor/assets/javascripts/RGraph.svg.bar.js +1067 -0
  47. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +247 -0
  48. data/vendor/assets/javascripts/RGraph.svg.common.core.js +3363 -0
  49. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +277 -0
  50. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +1304 -0
  51. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +353 -0
  52. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +233 -0
  53. data/vendor/assets/javascripts/RGraph.svg.hbar.js +1141 -0
  54. data/vendor/assets/javascripts/RGraph.svg.line.js +1486 -0
  55. data/vendor/assets/javascripts/RGraph.svg.pie.js +781 -0
  56. data/vendor/assets/javascripts/RGraph.svg.radar.js +1326 -0
  57. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +817 -0
  58. data/vendor/assets/javascripts/RGraph.thermometer.js +1135 -62
  59. data/vendor/assets/javascripts/RGraph.vprogress.js +1470 -83
  60. data/vendor/assets/javascripts/RGraph.waterfall.js +1347 -80
  61. metadata +15 -3
@@ -0,0 +1,1141 @@
1
+ // version: 2017-01-02
2
+ /**
3
+ * o--------------------------------------------------------------------------------o
4
+ * | This file is part of the RGraph package - you can learn more at: |
5
+ * | |
6
+ * | http://www.rgraph.net |
7
+ * | |
8
+ * | RGraph is licensed under the Open Source MIT license. That means that it's |
9
+ * | totally free to use! |
10
+ * o--------------------------------------------------------------------------------o
11
+ */
12
+
13
+ RGraph = window.RGraph || {isRGraph: true};
14
+ RGraph.SVG = RGraph.SVG || {};
15
+
16
+ // Module pattern
17
+ (function (win, doc, undefined)
18
+ {
19
+ var RG = RGraph,
20
+ ua = navigator.userAgent,
21
+ ma = Math,
22
+ win = window,
23
+ doc = document;
24
+
25
+
26
+
27
+ RG.SVG.HBar = function (conf)
28
+ {
29
+ this.id = conf.id;
30
+ this.uid = RG.SVG.createUID();
31
+ this.container = document.getElementById(this.id);
32
+ this.svg = RG.SVG.createSVG({container: this.container});
33
+ this.isRGraph = true;
34
+ this.width = Number(this.svg.getAttribute('width'));
35
+ this.height = Number(this.svg.getAttribute('height'));
36
+ this.data = conf.data;
37
+ this.type = 'hbar';
38
+ this.coords = [];
39
+ this.stackedBackfaces = [];
40
+ this.colorsParsed = false;
41
+ this.originalColors = {};
42
+ this.gradientCounter = 1;
43
+
44
+ // Add this object to the ObjectRegistry
45
+ RG.SVG.OR.add(this);
46
+
47
+ this.container.style.display = 'inline-block';
48
+
49
+ this.properties =
50
+ {
51
+ gutterLeft: 100,
52
+ gutterRight: 35,
53
+ gutterTop: 35,
54
+ gutterBottom: 35,
55
+ gutterLeftAutosize: true,
56
+
57
+ backgroundGrid: true,
58
+ backgroundGridColor: '#ddd',
59
+ backgroundGridLinewidth: 1,
60
+ backgroundGridHlines: true,
61
+ backgroundGridHlinesCount: null,
62
+ backgroundGridVlines: true,
63
+ backgroundGridVlinesCount: null,
64
+ backgroundGridBorder: true,
65
+
66
+ // 20 colors. If you need more you need to set the colors property
67
+ colors: [
68
+ 'red', '#0f0', '#00f', '#ff0', '#0ff', '#0f0','pink','orange','gray','black',
69
+ 'red', '#0f0', '#00f', '#ff0', '#0ff', '#0f0','pink','orange','gray','black'
70
+ ],
71
+ colorsSequential: false,
72
+ strokestyle: 'rgba(0,0,0,0)',
73
+
74
+ vmargin: 3,
75
+ vmarginGrouped: 2,
76
+
77
+ xaxis: true,
78
+ xaxisTickmarks: true,
79
+ xaxisTickmarksLength: 4,
80
+ xaxisColor: 'black',
81
+ xaxisLabels: [],
82
+ xaxisLabelsOffsetx: 0,
83
+ xaxisLabelsOffsety: 0,
84
+ xaxisLabelsCount: 5,
85
+ xaxisScale: true,
86
+ xaxisUnitsPre: '',
87
+ xaxisUnitsPost: '',
88
+ xaxisStrict: false,
89
+ xaxisDecimals: 0,
90
+ xaxisPoint: '.',
91
+ xaxisThousand: ',',
92
+ xaxisRound: false,
93
+ xaxisMax: null,
94
+ xaxisMin: 0,
95
+ xaxisFormatter: null,
96
+ xaxisLabelsPositionEdgeTickmarksCount: null,
97
+ xaxisTextColor: null,
98
+ xaxisTextBold: null,
99
+ xaxisTextItalic: null,
100
+ xaxisTextFont: null,
101
+ xaxisTextSize: null,
102
+
103
+ yaxis: true,
104
+ yaxisTickmarks: true,
105
+ yaxisTickmarksLength: 3,
106
+ yaxisLabels: [],
107
+ yaxisLabelsPosition: 'section',
108
+ yaxisLabelsOffsetx: 0,
109
+ yaxisLabelsOffsety: 0,
110
+ yaxisScale: false,
111
+ yaxisLabelsPositionEdgeTickmarksCount: null,
112
+ yaxisColor: 'black',
113
+ yaxisTextFont: null,
114
+ yaxisTextSize: null,
115
+ yaxisTextColor: null,
116
+ yaxisTextBold: null,
117
+ yaxisTextItalic: null,
118
+
119
+ textColor: 'black',
120
+ textFont: 'sans-serif',
121
+ textSize: 12,
122
+ textBold: false,
123
+ textItalic: false,
124
+
125
+ labelsAbove: false,
126
+ labelsAboveFont: null,
127
+ labelsAboveSize: null,
128
+ labelsAboveBold: null,
129
+ labelsAboveItalic: null,
130
+ labelsAboveColor: null,
131
+ labelsAboveBackground: null,
132
+ labelsAboveBackgroundPadding: 0,
133
+ labelsAboveUnitsPre: null,
134
+ labelsAboveUnitsPost: null,
135
+ labelsAbovePoint: null,
136
+ labelsAboveThousand: null,
137
+ labelsAboveFormatter: null,
138
+ labelsAboveDecimals: null,
139
+ labelsAboveOffsetx: 0,
140
+ labelsAboveOffsety: 0,
141
+ labelsAboveHalign: 'left',
142
+ labelsAboveValign: 'center',
143
+
144
+ linewidth: 1,
145
+ grouping: 'grouped',
146
+
147
+ tooltips: null,
148
+ tooltipsOverride: null,
149
+ tooltipsEffect: 'fade',
150
+ tooltipsCssClass: 'RGraph_tooltip',
151
+ tooltipsEvent: 'click',
152
+
153
+ highlightStroke: 'rgba(0,0,0,0)',
154
+ highlightFill: 'rgba(255,255,255,0.7)',
155
+ highlightLinewidth: 1,
156
+
157
+ title: '',
158
+ titleSize: 16,
159
+ titleX: null,
160
+ titleY: null,
161
+ titleHalign: 'center',
162
+ titleValign: 'bottom',
163
+ titleColor: 'black',
164
+ titleFont: null,
165
+ titleBold: false,
166
+ titleItalic: false,
167
+
168
+ titleSubtitle: '',
169
+ titleSubtitleX: null,
170
+ titleSubtitleY: null,
171
+ titleSubtitleHalign: 'center',
172
+ titleSubtitleValign: 'top',
173
+ titleSubtitleColor: '#aaa',
174
+ titleSubtitleSize: 10,
175
+ titleSubtitleFont: null,
176
+ titleSubtitleBold: false,
177
+ titleSubtitleItalic: false,
178
+
179
+ shadow: false,
180
+ shadowOffsetx: 2,
181
+ shadowOffsety: 2,
182
+ shadowBlur: 2,
183
+ shadowOpacity: 0.25,
184
+
185
+ attribution: true,
186
+ attributionX: null,
187
+ attributionY: null,
188
+ attributionHref: 'http://www.rgraph.net/svg/index.html',
189
+ attributionHalign: 'right',
190
+ attributionValign: 'bottom',
191
+ attributionSize: 8,
192
+ attributionColor: 'gray',
193
+ attributionFont: 'sans-serif',
194
+ attributionItalic: false,
195
+ attributionBold: false
196
+ };
197
+
198
+
199
+
200
+
201
+
202
+ /**
203
+ * "Decorate" the object with the generic effects if the effects library has been included
204
+ */
205
+ if (RG.SVG.FX && typeof RG.SVG.FX.decorate === 'function') {
206
+ RG.SVG.FX.decorate(this);
207
+ }
208
+
209
+
210
+
211
+
212
+ var prop = this.properties;
213
+
214
+
215
+
216
+
217
+
218
+ //
219
+ // A setter that the constructor uses (at the end)
220
+ // to set all of the properties
221
+ //
222
+ // @param string name The name of the property to set
223
+ // @param string value The value to set the property to
224
+ //
225
+ this.set = function (name, value)
226
+ {
227
+ if (arguments.length === 1 && typeof name === 'object') {
228
+ for (i in arguments[0]) {
229
+ if (typeof i === 'string') {
230
+ this.set(i, arguments[0][i]);
231
+ }
232
+ }
233
+ } else {
234
+ this.properties[name] = value;
235
+ }
236
+
237
+ return this;
238
+ };
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+ //
248
+ // The draw method draws the Bar chart
249
+ //
250
+ this.draw = function ()
251
+ {
252
+ // Fire the beforedraw event
253
+ RG.SVG.fireCustomEvent(this, 'onbeforedraw');
254
+
255
+
256
+
257
+
258
+ // Create the defs tag if necessary
259
+ RG.SVG.createDefs(this);
260
+
261
+
262
+
263
+ //
264
+ // Handle the gutterLeft autosizing
265
+ //
266
+ if (prop.gutterLeftAutosize) {
267
+ for (var i=0,len=prop.yaxisLabels.length,maxLength=0; i<len; ++i) {
268
+ var sizes = RG.SVG.measureText({
269
+ text: prop.yaxisLabels[i],
270
+ bold: prop.yaxisTextBold || prop.textBold,
271
+ size: prop.yaxisTextSize || prop.textSize,
272
+ font: prop.yaxisTextFont || prop.textFont
273
+ });
274
+
275
+ maxLength = ma.max(maxLength, sizes[0]);
276
+ }
277
+
278
+ prop.gutterLeft = maxLength + 15;
279
+ }
280
+
281
+
282
+
283
+
284
+ this.graphWidth = this.width - prop.gutterLeft - prop.gutterRight;
285
+ this.graphHeight = this.height - prop.gutterTop - prop.gutterBottom;
286
+
287
+
288
+
289
+ //
290
+ // Parse the colors. This allows for simple gradient syntax
291
+ //
292
+ if (!this.colorsParsed) {
293
+ this.parseColors();
294
+
295
+ // Don't want to do this again
296
+ this.colorsParsed = true;
297
+ }
298
+
299
+
300
+
301
+ // Go through the data and work out the maximum value
302
+ var values = [];
303
+
304
+ for (var i=0,max=0; i<this.data.length; ++i) {
305
+ if (typeof this.data[i] === 'number') {
306
+ values.push(this.data[i]);
307
+
308
+ } else if (RG.SVG.isArray(this.data[i]) && prop.grouping === 'grouped') {
309
+ values.push(RG.SVG.arrayMax(this.data[i]));
310
+
311
+ } else if (RG.SVG.isArray(this.data[i]) && prop.grouping === 'stacked') {
312
+ values.push(RG.SVG.arraySum(this.data[i]));
313
+ }
314
+ }
315
+ var max = RG.SVG.arrayMax(values);
316
+
317
+ // A custom, user-specified maximum value
318
+ if (typeof prop.xaxisMax === 'number') {
319
+ max = prop.xaxisMax;
320
+ }
321
+
322
+ // Set the ymin to zero if it's set to mirror
323
+ if (prop.xaxisMin === 'mirror' || prop.xaxisMin === 'middle' || prop.xaxisMin === 'center') {
324
+ var mirrorScale = true;
325
+ prop.xaxisMin = prop.xaxisMax * -1;
326
+ }
327
+
328
+
329
+ //
330
+ // Generate an appropiate scale
331
+ //
332
+ this.scale = RG.SVG.getScale({
333
+ object: this,
334
+ numlabels: prop.xaxisLabelsCount,
335
+ unitsPre: prop.xaxisUnitsPre,
336
+ unitsPost: prop.xaxisUnitsPost,
337
+ max: max,
338
+ min: prop.xaxisMin,
339
+ point: prop.xaxisPoint,
340
+ round: prop.xaxisRound,
341
+ thousand: prop.xaxisThousand,
342
+ decimals: prop.xaxisDecimals,
343
+ strict: typeof prop.xaxisMax === 'number',
344
+ formatter: prop.xaxisFormatter
345
+ });
346
+
347
+
348
+
349
+ //
350
+ // Get the scale a second time if the xmin should be mirored
351
+ //
352
+ // Set the xmin to zero if it's set mirror
353
+ if (mirrorScale) {
354
+ this.scale = RG.SVG.getScale({
355
+ object: this,
356
+ numlabels: prop.xaxisLabelsCount,
357
+ unitsPre: prop.xaxisUnitsPre,
358
+ unitsPost: prop.xaxisUnitsPost,
359
+ max: this.scale.max,
360
+ min: this.scale.max * -1,
361
+ point: prop.xaxisPoint,
362
+ round: false,
363
+ thousand: prop.xaxisThousand,
364
+ decimals: prop.xaxisDecimals,
365
+ strict: typeof prop.xaxisMax === 'number',
366
+ formatter: prop.xaxisFormatter
367
+ });
368
+ }
369
+
370
+ // Now the scale has been generated adopt its max value
371
+ this.max = this.scale.max;
372
+ prop.xaxisMax = this.scale.max;
373
+
374
+ this.min = this.scale.min;
375
+ prop.xaxisMin = this.scale.min;
376
+
377
+
378
+
379
+
380
+ // Draw the background first
381
+ RG.SVG.drawBackground(this);
382
+
383
+ // Draw the bars
384
+ this.drawBars();
385
+
386
+
387
+ // Draw the axes over the bars
388
+ RG.SVG.drawXAxis(this);
389
+ RG.SVG.drawYAxis(this);
390
+
391
+
392
+ // Draw the labelsAbove
393
+ this.drawLabelsAbove();
394
+
395
+
396
+
397
+ // Add the attribution link. If you're adding this elsewhere on your page/site
398
+ // and you don't want it displayed then there are options available to not
399
+ // show it.
400
+ RG.SVG.attribution(this);
401
+
402
+
403
+
404
+ // Add the event listener that clears the highlight rect if
405
+ // there is any. Must be MOUSEDOWN (ie before the click event)
406
+ var obj = this;
407
+ document.body.addEventListener('mousedown', function (e)
408
+ {
409
+ RG.SVG.removeHighlight(obj);
410
+
411
+ }, false);
412
+
413
+
414
+
415
+ // Fire the draw event
416
+ RG.SVG.fireCustomEvent(this, 'ondraw');
417
+
418
+
419
+
420
+
421
+ return this;
422
+ };
423
+
424
+
425
+
426
+
427
+
428
+
429
+
430
+
431
+ //
432
+ // Draws the bars
433
+ //
434
+ this.drawBars = function ()
435
+ {
436
+ if (prop.shadow) {
437
+ RG.SVG.setShadow({
438
+ object: this,
439
+ offsetx: prop.shadowOffsetx,
440
+ offsety: prop.shadowOffsety,
441
+ blur: prop.shadowBlur,
442
+ opacity: prop.shadowOpacity,
443
+ id: 'dropShadow'
444
+ });
445
+ }
446
+
447
+ // Go through the bars
448
+ for (var i=0,sequentialIndex=0; i<this.data.length; ++i,++sequentialIndex) {
449
+
450
+ //
451
+ // NORMAL bars
452
+ //
453
+ if (typeof this.data[i] === 'number') {
454
+
455
+ var outerSegment = this.graphHeight / this.data.length,
456
+ width = ma.abs((this.data[i] / (this.max - this.min)) * this.graphWidth),
457
+ height = (this.graphHeight / this.data.length) - prop.vmargin - prop.vmargin,
458
+ x = this.getXCoord(0) - (this.data[i] < 0 ? width : 0),
459
+ y = prop.gutterTop + prop.vmargin + (outerSegment * i);
460
+
461
+ var rect = RG.SVG.create({
462
+ svg: this.svg,
463
+ type: 'rect',
464
+ attr: {
465
+ stroke: prop.strokestyle,
466
+ fill: prop.colorsSequential ? (prop.colors[sequentialIndex] ? prop.colors[sequentialIndex] : prop.colors[prop.colors.length - 1]) : prop.colors[0],
467
+ x: x,
468
+ y: y,
469
+ width: width,
470
+ height: height,
471
+ 'stroke-width': prop.linewidth,
472
+ 'data-tooltip': (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[i] : '',
473
+ 'data-index': i,
474
+ 'data-sequential-index': sequentialIndex,
475
+ 'data-value': this.data[i],
476
+ filter: prop.shadow ? 'url(#dropShadow)' : ''
477
+ }
478
+ });
479
+
480
+ this.coords.push({
481
+ object: rect,
482
+ x: x,
483
+ y: y - (this.data[i] > 0 ? height : 0),
484
+ width: width,
485
+ height: height
486
+ });
487
+
488
+
489
+
490
+
491
+
492
+ // Add toooltips if necessary
493
+ if (!RG.SVG.isNull(prop.tooltips) && prop.tooltips[sequentialIndex]) {
494
+
495
+ var obj = this;
496
+
497
+ //
498
+ // Add tooltip event listeners
499
+ //
500
+ (function (idx, seq)
501
+ {
502
+ rect['on' + prop.tooltipsEvent] = function (e)
503
+ {
504
+ // Hide any tooltip that is currently visible
505
+ RG.SVG.hideTooltip();
506
+
507
+ // Show the tooltip
508
+ RG.SVG.tooltip({
509
+ object: obj,
510
+ index: idx,
511
+ group: null,
512
+ sequentialIndex: seq,
513
+ text: prop.tooltips[seq],
514
+ event: e
515
+ });
516
+
517
+ // Highlight the rect that has been clicked on
518
+ obj.highlight(e.target);
519
+
520
+ };
521
+
522
+ rect.onmousemove = function (e)
523
+ {
524
+ e.target.style.cursor = 'pointer'
525
+ };
526
+ })(i, sequentialIndex);
527
+ }
528
+
529
+
530
+
531
+
532
+ //
533
+ // GROUPED charts
534
+ //
535
+ } else if (RG.SVG.isArray(this.data[i]) && prop.grouping === 'grouped') {
536
+
537
+ var outerSegment = (this.graphHeight / this.data.length),
538
+ innerSegment = outerSegment - (2 * prop.vmargin);
539
+
540
+ // Loop through the group
541
+ for (var j=0; j<this.data[i].length; ++j,++sequentialIndex) {
542
+
543
+ var width = ma.abs((this.data[i][j] / (this.max - this.min)) * this.graphWidth),
544
+ height = ( (innerSegment - ((this.data[i].length - 1) * prop.vmarginGrouped)) / this.data[i].length),
545
+ y = prop.gutterTop + prop.vmargin + (outerSegment * i) + (j * height) + (j * prop.vmarginGrouped),
546
+ x = this.getXCoord(0) - (this.data[i][j] < 0 ? width : 0);
547
+
548
+
549
+ var rect = RG.SVG.create({
550
+ svg: this.svg,
551
+ type: 'rect',
552
+ attr: {
553
+ stroke: prop['strokestyle'],
554
+ fill: (prop.colorsSequential && prop.colors[sequentialIndex]) ? prop.colors[sequentialIndex] : (prop.colors[j] ? prop.colors[j] : prop.colors[prop.colors.length - 1]),
555
+ x: x,
556
+ y: y,
557
+ width: width,
558
+ height: height,
559
+ 'stroke-width': prop.linewidth,
560
+ 'data-index': i,
561
+ 'data-sequential-index': sequentialIndex,
562
+ 'data-tooltip': (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[sequentialIndex] : '',
563
+ 'data-value': this.data[i][j],
564
+ filter: prop.shadow ? 'url(#dropShadow)' : ''
565
+ }
566
+ });
567
+
568
+ this.coords.push({
569
+ object: rect,
570
+ x: x,
571
+ y: y - (this.data[i][j] > 0 ? height : 0),
572
+ width: width,
573
+ height: height
574
+ });
575
+
576
+
577
+ // Add the tooltip data- attribute
578
+ if (!RG.SVG.isNull(prop.tooltips) && prop.tooltips[sequentialIndex]) {
579
+
580
+ var obj = this;
581
+
582
+
583
+ //
584
+ // Add tooltip event listeners
585
+ //
586
+ (function (idx, seq)
587
+ {
588
+ var indexes = RG.SVG.sequentialIndexToGrouped(seq, obj.data);
589
+
590
+ rect['on' + prop.tooltipsEvent] = function (e)
591
+ {
592
+ // Hide any tooltip that is currently visible
593
+ RG.SVG.hideTooltip();
594
+
595
+ // Show the tooltip
596
+ RG.SVG.tooltip({
597
+ object: obj,
598
+ group: idx,
599
+ index: indexes[1],
600
+ sequentialIndex: seq,
601
+ text: prop.tooltips[seq],
602
+ event: e
603
+ });
604
+
605
+ // Highlight the rect that has been clicked on
606
+ obj.highlight(e.target);
607
+
608
+ };
609
+
610
+ rect.onmousemove = function (e)
611
+ {
612
+ e.target.style.cursor = 'pointer'
613
+ };
614
+ })(i, sequentialIndex);
615
+ }
616
+ }
617
+
618
+ --sequentialIndex;
619
+
620
+
621
+
622
+ //
623
+ // Stacked charts
624
+ //
625
+ } else if (RG.SVG.isArray(this.data[i]) && prop.grouping === 'stacked') {
626
+
627
+ // This is each bars "segment" of the chart
628
+ var section = (this.graphHeight / this.data.length);
629
+
630
+
631
+ // Intialise the X and Y coordinates
632
+ var x = this.getXCoord(0);
633
+
634
+
635
+
636
+ // Loop through the stack
637
+ for (var j=0; j<this.data[i].length; ++j,++sequentialIndex) {
638
+
639
+ var outerHeight = this.graphHeight / this.data.length,
640
+ width = ma.abs((this.data[i][j] / (this.max - this.min)) * this.graphWidth),
641
+ height = outerHeight - (2 * prop.vmargin),
642
+ y = prop.gutterTop + prop.vmargin + (outerHeight * i);
643
+
644
+ // If this is the first iteration of the loop and a shadow
645
+ // is requested draw a rect here to create it.
646
+ if (j === 0 && prop.shadow) {
647
+
648
+ var fullWidth = ma.abs((RG.SVG.arraySum(this.data[i]) / (this.max - this.min)) * this.graphWidth);
649
+
650
+ var rect = RG.SVG.create({
651
+ svg: this.svg,
652
+ type: 'rect',
653
+ attr: {
654
+ x: x,
655
+ y: y,
656
+ width: fullWidth,
657
+ height: height,
658
+ fill: 'white',
659
+ 'stroke-width': 0,
660
+ 'data-index': i,
661
+ filter: 'url(#dropShadow)'
662
+ }
663
+ });
664
+
665
+ this.stackedBackfaces[i] = rect;
666
+ }
667
+
668
+
669
+
670
+ // Create the visible bar
671
+ var rect = RG.SVG.create({
672
+ svg: this.svg,
673
+ type: 'rect',
674
+ attr: {
675
+ stroke: prop['strokestyle'],
676
+ fill: prop.colorsSequential ? (prop.colors[sequentialIndex] ? prop.colors[sequentialIndex] : prop.colors[prop.colors.length - 1]) : (prop.colors[j] ? prop.colors[j] : prop.colors[prop.colors.length - 1]),
677
+ x: x,
678
+ y: y,
679
+ width: width,
680
+ height: height,
681
+ 'stroke-width': prop.linewidth,
682
+ 'data-index': i,
683
+ 'data-sequential-index': sequentialIndex,
684
+ 'data-tooltip': (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[sequentialIndex] : '',
685
+ 'data-value': this.data[i][j]
686
+ }
687
+ });
688
+
689
+
690
+ this.coords.push({
691
+ object: rect,
692
+ x: x,
693
+ y: y,
694
+ width: width,
695
+ height: height
696
+ });
697
+
698
+
699
+
700
+ // Add the tooltip data- attribute
701
+ if (!RG.SVG.isNull(prop.tooltips) && prop.tooltips[sequentialIndex]) {
702
+
703
+ var obj = this;
704
+
705
+
706
+ //
707
+ // Add tooltip event listeners
708
+ //
709
+ (function (idx, seq)
710
+ {
711
+ rect['on' + prop.tooltipsEvent] = function (e)
712
+ {
713
+ // Hide any tooltip that is currently visible
714
+ RG.SVG.hideTooltip();
715
+
716
+ var indexes = RG.SVG.sequentialIndexToGrouped(seq, obj.data);
717
+
718
+ // Show the tooltip
719
+ RG.SVG.tooltip({
720
+ object: obj,
721
+ index: indexes[1],
722
+ group: idx,
723
+ sequentialIndex: seq,
724
+ text: prop.tooltips[seq],
725
+ event: e
726
+ });
727
+
728
+ // Highlight the rect that has been clicked on
729
+ obj.highlight(e.target);
730
+ };
731
+
732
+ rect.onmousemove = function (e)
733
+ {
734
+ e.target.style.cursor = 'pointer'
735
+ };
736
+ })(i, sequentialIndex);
737
+ }
738
+
739
+ x += width;
740
+ }
741
+
742
+ --sequentialIndex;
743
+ }
744
+ }
745
+
746
+ };
747
+
748
+
749
+
750
+
751
+
752
+
753
+
754
+
755
+
756
+ /**
757
+ * This function can be used to retrieve the relevant X coordinate for a
758
+ * particular value.
759
+ *
760
+ * @param int value The value to get the X coordinate for
761
+ */
762
+ this.getXCoord = function (value)
763
+ {
764
+ var prop = this.properties;
765
+
766
+ if (value > this.scale.max) {
767
+ return null;
768
+ }
769
+
770
+ var x;
771
+
772
+ if (value < this.scale.min) {
773
+ return null;
774
+ }
775
+
776
+ x = ((value - this.scale.min) / (this.scale.max - this.scale.min));
777
+ x *= this.graphWidth;
778
+ x += prop.gutterLeft;
779
+
780
+ return x;
781
+ };
782
+
783
+
784
+
785
+
786
+
787
+
788
+
789
+
790
+ /**
791
+ * This function can be used to highlight a bar on the chart
792
+ *
793
+ * @param object rect The rectangle to highlight
794
+ */
795
+ this.highlight = function (rect)
796
+ {
797
+ var x = rect.getAttribute('x'),
798
+ y = rect.getAttribute('y'),
799
+ width = rect.getAttribute('width'),
800
+ height = rect.getAttribute('height');
801
+
802
+ var highlight = RG.SVG.create({
803
+ svg: this.svg,
804
+ type: 'rect',
805
+ attr: {
806
+ stroke: prop.highlightStroke,
807
+ fill: prop.highlightFill,
808
+ x: x,
809
+ y: y,
810
+ width: width,
811
+ height: height,
812
+ 'stroke-width': prop.highlightLinewidth
813
+ }
814
+ });
815
+
816
+
817
+ if (prop.tooltipsEvent === 'mousemove') {
818
+ highlight.addEventListener('mouseout', function (e)
819
+ {
820
+ highlight.parentNode.removeChild(highlight);
821
+ RG.SVG.hideTooltip();
822
+
823
+ RG.SVG.REG.set('highlight', null);
824
+ }, false);
825
+ }
826
+
827
+
828
+ // Store the highlight rect in the rebistry so
829
+ // it can be cleared later
830
+ RG.SVG.REG.set('highlight', highlight);
831
+ };
832
+
833
+
834
+
835
+
836
+
837
+
838
+
839
+
840
+ /**
841
+ * This allows for easy specification of gradients
842
+ */
843
+ this.parseColors = function ()
844
+ {
845
+ // Save the original colors so that they can be restored when
846
+ // the canvas is cleared
847
+ if (!Object.keys(this.originalColors).length) {
848
+ this.originalColors = {
849
+ colors: RG.SVG.arrayClone(prop.colors),
850
+ backgroundGridColor: RG.SVG.arrayClone(prop.backgroundGridColor),
851
+ highlightFill: RG.SVG.arrayClone(prop.highlightFill)
852
+ }
853
+ }
854
+
855
+
856
+ // colors
857
+ var colors = prop.colors;
858
+
859
+ if (colors) {
860
+ for (var i=0; i<colors.length; ++i) {
861
+ colors[i] = RG.SVG.parseColorLinear({
862
+ object: this,
863
+ color: colors[i],
864
+ direction: 'horizontal',
865
+ start: prop.gutterLeft,
866
+ end: this.width - prop.gutterRight
867
+ });
868
+ }
869
+ }
870
+
871
+ prop.backgroundGridColor = RG.SVG.parseColorLinear({object: this, color: prop.backgroundGridColor, direction: 'horizontal',start: prop.gutterLeft,end: this.width - prop.gutterRight});
872
+ prop.highlightFill = RG.SVG.parseColorLinear({object: this, color: prop.highlightFill, direction: 'horizontal',start: prop.gutterLeft,end: this.width - prop.gutterRight});
873
+ };
874
+
875
+
876
+
877
+
878
+
879
+
880
+
881
+
882
+ //
883
+ // Draws the labelsAbove
884
+ //
885
+ this.drawLabelsAbove = function ()
886
+ {
887
+ // Go through the above labels
888
+ if (prop.labelsAbove) {
889
+
890
+ var data = RG.SVG.arrayLinearize(this.data);
891
+
892
+ for (var i=0; i<this.coords.length; ++i) {
893
+
894
+ var value = data[i].toFixed(typeof prop.labelsAboveDecimals === 'number' ? prop.labelsAboveDecimals : prop.xaxisDecimals);
895
+
896
+ var indexes = RG.SVG.sequentialIndexToGrouped(i, this.data);
897
+ if (RG.SVG.isArray(this.data[indexes[0]]) && prop.grouping === 'stacked') {
898
+ if ((indexes[1] +1) === this.data[indexes[0]].length) {
899
+ value = RG.SVG.arraySum(this.data[indexes[0]]);
900
+ value = value.toFixed(typeof prop.labelsAboveDecimals === 'number' ? prop.labelsAboveDecimals : prop.xaxisDecimals);
901
+ } else {
902
+ continue;
903
+ }
904
+ }
905
+
906
+
907
+ var str = RG.SVG.numberFormat({
908
+ object: this,
909
+ num: value,
910
+ prepend: typeof prop.labelsAboveUnitsPre === 'string' ? prop.labelsAboveUnitsPre : null,
911
+ append: typeof prop.labelsAboveUnitsPost === 'string' ? prop.labelsAboveUnitsPost : null,
912
+ point: typeof prop.labelsAbovePoint === 'string' ? prop.labelsAbovePoint : null,
913
+ thousand: typeof prop.labelsAboveThousand === 'string' ? prop.labelsAboveThousand : null,
914
+ formatter: typeof prop.labelsAboveFormatter === 'function' ? prop.labelsAboveFormatter : null
915
+ });
916
+
917
+ var bold = typeof prop.labelsAboveBold === 'boolean' ? prop.labelsAboveBold : prop.textBold,
918
+ italic = typeof prop.labelsAboveItalic === 'boolean' ? prop.labelsAboveItalic : prop.textItalic,
919
+ size = prop.labelsAboveSize || prop.textSize,
920
+ font = prop.labelsAboveFont || prop.textFont,
921
+ halign = prop.labelsAboveHalign,
922
+ valign = prop.labelsAboveValign;
923
+
924
+ var dimensions = RG.SVG.measureText({
925
+ text: str,
926
+ bold: bold,
927
+ font: font,
928
+ size: size
929
+ });
930
+
931
+ var x = parseFloat(this.coords[i].object.getAttribute('x')) + parseFloat(this.coords[i].object.getAttribute('width')) + 7 + prop.labelsAboveOffsetx,
932
+ y = parseFloat(this.coords[i].object.getAttribute('y')) + parseFloat(this.coords[i].object.getAttribute('height') / 2) + prop.labelsAboveOffsety,
933
+ width = dimensions[0],
934
+ height = dimensions[1];
935
+
936
+ if (x + width > this.width) {
937
+ halign = 'right';
938
+ x = this.width - 5;
939
+ prop.labelsAboveBackground = prop.labelsAboveBackground || 'rgba(255,255,255,0.95)';
940
+ }
941
+
942
+
943
+ var text = RG.SVG.text({
944
+ object: this,
945
+ text: str,
946
+ x: x,
947
+ y: y,
948
+ halign: halign,
949
+ valign: valign,
950
+ font: font,
951
+ size: size,
952
+ bold: bold,
953
+ italic: italic,
954
+ color: prop.labelsAboveColor || prop.textColor,
955
+ background: prop.labelsAboveBackground || null,
956
+ padding: prop.labelsAboveBackgroundPadding || 0
957
+ });
958
+ }
959
+ }
960
+ };
961
+
962
+
963
+
964
+
965
+
966
+
967
+
968
+
969
+ /**
970
+ * Using a function to add events makes it easier to facilitate method
971
+ * chaining
972
+ *
973
+ * @param string type The type of even to add
974
+ * @param function func
975
+ */
976
+ this.on = function (type, func)
977
+ {
978
+ if (type.substr(0,2) !== 'on') {
979
+ type = 'on' + type;
980
+ }
981
+
982
+ RG.SVG.addCustomEventListener(this, type, func);
983
+
984
+ return this;
985
+ };
986
+
987
+
988
+
989
+
990
+
991
+
992
+
993
+
994
+ //
995
+ // Used in chaining. Runs a function there and then - not waiting for
996
+ // the events to fire (eg the onbeforedraw event)
997
+ //
998
+ // @param function func The function to execute
999
+ //
1000
+ this.exec = function (func)
1001
+ {
1002
+ func(this);
1003
+
1004
+ return this;
1005
+ };
1006
+
1007
+
1008
+
1009
+
1010
+
1011
+
1012
+
1013
+
1014
+ //
1015
+ // The Bar chart grow effect
1016
+ //
1017
+ this.grow = function ()
1018
+ {
1019
+ var opt = arguments[0] || {},
1020
+ frames = opt.frames || 30,
1021
+ frame = 0,
1022
+ obj = this,
1023
+ data = [],
1024
+ height = null,
1025
+ seq = 0;
1026
+
1027
+ //
1028
+ // Copy the data
1029
+ //
1030
+ data = RG.SVG.arrayClone(this.data);
1031
+
1032
+ this.draw();
1033
+
1034
+ var iterate = function ()
1035
+ {
1036
+ for (var i=0,seq=0,len=obj.coords.length; i<len; ++i, ++seq) {
1037
+
1038
+ var multiplier = (frame / frames)
1039
+ * RG.SVG.FX.getEasingMultiplier(frames, frame)
1040
+ * RG.SVG.FX.getEasingMultiplier(frames, frame);
1041
+
1042
+
1043
+
1044
+
1045
+ // TODO Go through the data and update the value according to
1046
+ // the frame number
1047
+ if (typeof data[i] === 'number') {
1048
+
1049
+ width = ma.abs(obj.getXCoord(data[i]) - obj.getXCoord(0));
1050
+ obj.data[i] = data[i] * multiplier;
1051
+ width = multiplier * width;
1052
+
1053
+ // Set the new width on the rect
1054
+ obj.coords[seq].object.setAttribute(
1055
+ 'width',
1056
+ width
1057
+ );
1058
+
1059
+ // Set the correct Y coord on the object
1060
+ obj.coords[seq].object.setAttribute(
1061
+ 'x',
1062
+ data[i] > 0 ? obj.getXCoord(0) : obj.getXCoord(0) - width
1063
+ );
1064
+
1065
+ } else if (typeof data[i] === 'object') {
1066
+
1067
+ var accumulativeWidth = 0;
1068
+
1069
+ for (var j=0,len2=data[i].length; j<len2; ++j, ++seq) {
1070
+
1071
+ width = ma.abs(obj.getXCoord(data[i][j]) - obj.getXCoord(0));
1072
+ width = multiplier * width;
1073
+ obj.data[i][j] = data[i][j] * multiplier;
1074
+
1075
+ obj.coords[seq].object.setAttribute(
1076
+ 'width',
1077
+ width
1078
+ );
1079
+
1080
+ obj.coords[seq].object.setAttribute(
1081
+ 'x',
1082
+ data[i][j] > 0 ? (obj.getXCoord(0) + accumulativeWidth) : (obj.getXCoord(0) - width - accumulativeWidth)
1083
+ );
1084
+
1085
+ accumulativeWidth += (prop.grouping === 'stacked' ? width : 0);
1086
+ }
1087
+
1088
+ //
1089
+ // Set the height and Y cooord of the backfaces if necessary
1090
+ //
1091
+ if (obj.stackedBackfaces[i]) {
1092
+ obj.stackedBackfaces[i].setAttribute(
1093
+ 'width',
1094
+ accumulativeWidth
1095
+ );
1096
+
1097
+ obj.stackedBackfaces[i].setAttribute(
1098
+ 'x',
1099
+ prop.gutterLeft
1100
+ );
1101
+ }
1102
+
1103
+ // Decrease seq by one so that it's not incremented twice
1104
+ --seq;
1105
+ }
1106
+ }
1107
+
1108
+ if (frame++ < frames) {
1109
+ //setTimeout(iterate, frame > 1 ? opt.delay : 200);
1110
+ RG.SVG.FX.update(iterate);
1111
+ } else if (opt.callback) {
1112
+ (opt.callback)(obj);
1113
+ }
1114
+ };
1115
+
1116
+ iterate();
1117
+
1118
+ return this;
1119
+ };
1120
+
1121
+
1122
+
1123
+
1124
+
1125
+
1126
+
1127
+
1128
+ //
1129
+ // Set the options that the user has provided
1130
+ //
1131
+ for (i in conf.options) {
1132
+ if (typeof i === 'string') {
1133
+ this.set(i, conf.options[i]);
1134
+ }
1135
+ }
1136
+ };
1137
+
1138
+ return this;
1139
+
1140
+ // End module pattern
1141
+ })(window, document);