rgraph-rails 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +4 -0
  7. data/README.md +73 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/lib/rgraph-rails/version.rb +3 -0
  12. data/lib/rgraph-rails.rb +8 -0
  13. data/license.txt +19 -0
  14. data/rgraph-rails.gemspec +26 -0
  15. data/vendor/assets/images/bg.png +0 -0
  16. data/vendor/assets/images/bullet.png +0 -0
  17. data/vendor/assets/images/facebook-large.png +0 -0
  18. data/vendor/assets/images/google-plus-large.png +0 -0
  19. data/vendor/assets/images/logo.png +0 -0
  20. data/vendor/assets/images/meter-image-sd-needle.png +0 -0
  21. data/vendor/assets/images/meter-image-sd.png +0 -0
  22. data/vendor/assets/images/meter-sketch-needle.png +0 -0
  23. data/vendor/assets/images/meter-sketch.png +0 -0
  24. data/vendor/assets/images/odometer-background.png +0 -0
  25. data/vendor/assets/images/rgraph.jpg +0 -0
  26. data/vendor/assets/images/title.png +0 -0
  27. data/vendor/assets/images/twitter-large.png +0 -0
  28. data/vendor/assets/javascripts/RGraph.bar.js +3246 -0
  29. data/vendor/assets/javascripts/RGraph.bipolar.js +2003 -0
  30. data/vendor/assets/javascripts/RGraph.common.annotate.js +399 -0
  31. data/vendor/assets/javascripts/RGraph.common.context.js +600 -0
  32. data/vendor/assets/javascripts/RGraph.common.core.js +4751 -0
  33. data/vendor/assets/javascripts/RGraph.common.csv.js +275 -0
  34. data/vendor/assets/javascripts/RGraph.common.deprecated.js +454 -0
  35. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1194 -0
  36. data/vendor/assets/javascripts/RGraph.common.effects.js +1524 -0
  37. data/vendor/assets/javascripts/RGraph.common.key.js +735 -0
  38. data/vendor/assets/javascripts/RGraph.common.resizing.js +550 -0
  39. data/vendor/assets/javascripts/RGraph.common.tooltips.js +605 -0
  40. data/vendor/assets/javascripts/RGraph.common.zoom.js +223 -0
  41. data/vendor/assets/javascripts/RGraph.drawing.background.js +636 -0
  42. data/vendor/assets/javascripts/RGraph.drawing.circle.js +579 -0
  43. data/vendor/assets/javascripts/RGraph.drawing.image.js +810 -0
  44. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +710 -0
  45. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +672 -0
  46. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +568 -0
  47. data/vendor/assets/javascripts/RGraph.drawing.poly.js +623 -0
  48. data/vendor/assets/javascripts/RGraph.drawing.rect.js +603 -0
  49. data/vendor/assets/javascripts/RGraph.drawing.text.js +648 -0
  50. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +815 -0
  51. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +860 -0
  52. data/vendor/assets/javascripts/RGraph.fuel.js +965 -0
  53. data/vendor/assets/javascripts/RGraph.funnel.js +988 -0
  54. data/vendor/assets/javascripts/RGraph.gantt.js +1242 -0
  55. data/vendor/assets/javascripts/RGraph.gauge.js +1391 -0
  56. data/vendor/assets/javascripts/RGraph.hbar.js +1794 -0
  57. data/vendor/assets/javascripts/RGraph.hprogress.js +1307 -0
  58. data/vendor/assets/javascripts/RGraph.line.js +3940 -0
  59. data/vendor/assets/javascripts/RGraph.meter.js +1242 -0
  60. data/vendor/assets/javascripts/RGraph.modaldialog.js +292 -0
  61. data/vendor/assets/javascripts/RGraph.odo.js +1265 -0
  62. data/vendor/assets/javascripts/RGraph.pie.js +1979 -0
  63. data/vendor/assets/javascripts/RGraph.radar.js +1840 -0
  64. data/vendor/assets/javascripts/RGraph.rose.js +1860 -0
  65. data/vendor/assets/javascripts/RGraph.rscatter.js +1332 -0
  66. data/vendor/assets/javascripts/RGraph.scatter.js +3029 -0
  67. data/vendor/assets/javascripts/RGraph.thermometer.js +1131 -0
  68. data/vendor/assets/javascripts/RGraph.vprogress.js +1326 -0
  69. data/vendor/assets/javascripts/RGraph.waterfall.js +1252 -0
  70. data/vendor/assets/javascripts/financial-data.js +1067 -0
  71. data/vendor/assets/stylesheets/ModalDialog.css +90 -0
  72. data/vendor/assets/stylesheets/animations.css +3347 -0
  73. data/vendor/assets/stylesheets/website.css +402 -0
  74. metadata +175 -0
@@ -0,0 +1,1252 @@
1
+ // version: 2015-11-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 dual licensed under the Open Source GPL (General Public License) |
9
+ * | v2.0 license and a commercial license which means that you're not bound by |
10
+ * | the terms of the GPL. The commercial license is just �99 (GBP) and you can |
11
+ * | read about it here: |
12
+ * | http://www.rgraph.net/license |
13
+ * o--------------------------------------------------------------------------------o
14
+ */
15
+
16
+ RGraph = window.RGraph || {isRGraph: true};
17
+
18
+
19
+
20
+
21
+ /**
22
+ * The bar chart constructor
23
+ *
24
+ * @param object canvas The canvas object
25
+ * @param array data The chart data
26
+ */
27
+ RGraph.Waterfall = function (conf)
28
+ {
29
+ /**
30
+ * Allow for object config style
31
+ */
32
+ if ( typeof conf === 'object'
33
+ && typeof conf.data === 'object'
34
+ && typeof conf.id === 'string') {
35
+
36
+ var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
37
+
38
+ } else {
39
+
40
+ var conf = {
41
+ id: conf,
42
+ data: arguments[1]
43
+ };
44
+ }
45
+
46
+
47
+
48
+
49
+ this.id = conf.id;
50
+ this.canvas = document.getElementById(this.id);
51
+ this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null;
52
+ this.canvas.__object__ = this;
53
+ this.type = 'waterfall';
54
+ this.max = 0;
55
+ this.data = conf.data;
56
+ this.isRGraph = true;
57
+ this.coords = [];
58
+ this.uid = RGraph.CreateUID();
59
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
60
+ this.colorsParsed = false;
61
+ this.coordsText = [];
62
+ this.original_colors = [];
63
+ this.firstDraw = true; // After the first draw this will be false
64
+
65
+
66
+ // Various config
67
+ this.properties =
68
+ {
69
+ 'chart.background.barcolor1': 'rgba(0,0,0,0)',
70
+ 'chart.background.barcolor2': 'rgba(0,0,0,0)',
71
+ 'chart.background.grid': true,
72
+ 'chart.background.grid.color': '#ddd',
73
+ 'chart.background.grid.width': 1,
74
+ 'chart.background.grid.hsize': 20,
75
+ 'chart.background.grid.vsize': 20,
76
+ 'chart.background.grid.vlines': true,
77
+ 'chart.background.grid.hlines': true,
78
+ 'chart.background.grid.border': true,
79
+ 'chart.background.grid.autofit':true,
80
+ 'chart.background.grid.autofit.align': true,
81
+ 'chart.background.grid.autofit.numhlines': 5,
82
+ 'chart.background.grid.autofit.numvlines': 20,
83
+ 'chart.background.image': null,
84
+ 'chart.background.hbars': null,
85
+ 'chart.linewidth': 1,
86
+ 'chart.axis.linewidth': 1,
87
+ 'chart.xaxispos': 'bottom',
88
+ 'chart.numxticks': null,
89
+ 'chart.numyticks': 10,
90
+ 'chart.hmargin': 5,
91
+ 'chart.strokestyle': '#666',
92
+ 'chart.axis.color': 'black',
93
+ 'chart.gutter.left': 25,
94
+ 'chart.gutter.right': 25,
95
+ 'chart.gutter.top': 25,
96
+ 'chart.gutter.bottom': 25,
97
+ 'chart.labels': [],
98
+ 'chart.labels.bold': false,
99
+ 'chart.ylabels': true,
100
+ 'chart.text.color': 'black',
101
+ 'chart.text.size': 12,
102
+ 'chart.text.angle': 0,
103
+ 'chart.text.font': 'Arial',
104
+ 'chart.ymax': null,
105
+ 'chart.title': '',
106
+ 'chart.title.color': 'black',
107
+ 'chart.title.background': null,
108
+ 'chart.title.hpos': null,
109
+ 'chart.title.vpos': null,
110
+ 'chart.title.bold': true,
111
+ 'chart.title.font': null,
112
+ 'chart.title.xaxis': '',
113
+ 'chart.title.yaxis': '',
114
+ 'chart.title.yaxis.bold': true,
115
+ 'chart.title.yaxis.size': null,
116
+ 'chart.title.yaxis.font': null,
117
+ 'chart.title.yaxis.color': null,
118
+ 'chart.title.xaxis.pos': null,
119
+ 'chart.title.yaxis.pos': null,
120
+ 'chart.title.yaxis.align': 'left',
121
+ 'chart.title.xaxis.bold': true,
122
+ 'chart.title.xaxis.size': null,
123
+ 'chart.title.xaxis.font': null,
124
+ 'chart.title.yaxis.x': null,
125
+ 'chart.title.yaxis.y': null,
126
+ 'chart.title.xaxis.x': null,
127
+ 'chart.title.xaxis.y': null,
128
+ 'chart.title.x': null,
129
+ 'chart.title.y': null,
130
+ 'chart.title.halign': null,
131
+ 'chart.title.valign': null,
132
+ 'chart.colors': ['Gradient(white:green)', 'Gradient(white:red)', 'Gradient(white:blue)'],
133
+ 'chart.shadow': false,
134
+ 'chart.shadow.color': '#666',
135
+ 'chart.shadow.offsetx': 3,
136
+ 'chart.shadow.offsety': 3,
137
+ 'chart.shadow.blur': 3,
138
+ 'chart.tooltips': null,
139
+ 'chart.tooltips.effect': 'fade',
140
+ 'chart.tooltips.css.class': 'RGraph_tooltip',
141
+ 'chart.tooltips.event': 'onclick',
142
+ 'chart.tooltips.highlight': true,
143
+ 'chart.tooltips.override': null,
144
+ 'chart.highlight.stroke': 'rgba(0,0,0,0)',
145
+ 'chart.highlight.fill': 'rgba(255,255,255,0.7)',
146
+ 'chart.contextmenu': null,
147
+ 'chart.units.pre': '',
148
+ 'chart.units.post': '',
149
+ 'chart.scale.decimals': 0,
150
+ 'chart.scale.point': '.',
151
+ 'chart.scale.thousand': ',',
152
+ //'chart.scale.formatter': null,
153
+ 'chart.crosshairs': false,
154
+ 'chart.crosshairs.color': '#333',
155
+ 'chart.crosshairs.hline': true,
156
+ 'chart.crosshairs.vline': true,
157
+ 'chart.annotatable': false,
158
+ 'chart.annotate.color': 'black',
159
+ 'chart.zoom.factor': 1.5,
160
+ 'chart.zoom.fade.in': true,
161
+ 'chart.zoom.fade.out': true,
162
+ 'chart.zoom.hdir': 'right',
163
+ 'chart.zoom.vdir': 'down',
164
+ 'chart.zoom.frames': 25,
165
+ 'chart.zoom.delay': 16.666,
166
+ 'chart.zoom.shadow': true,
167
+ 'chart.zoom.background': true,
168
+ 'chart.resizable': false,
169
+ 'chart.resize.handle.background': null,
170
+ 'chart.noaxes': false,
171
+ 'chart.noxaxis': false,
172
+ 'chart.noyaxis': false,
173
+ 'chart.axis.color': 'black',
174
+ 'chart.total': true,
175
+ 'chart.multiplier.x': 1,
176
+ 'chart.multiplier.w': 1,
177
+ 'chart.events.click': null,
178
+ 'chart.events.mousemove': null,
179
+ 'chart.ylabels.count': 5
180
+ }
181
+
182
+ // Check for support
183
+ if (!this.canvas) {
184
+ alert('[WATERFALL] No canvas support');
185
+ return;
186
+ }
187
+
188
+ /**
189
+ * Create the $ objects
190
+ */
191
+ for (var i=0; i<=this.data.length; ++i) {
192
+ this['$' + i] = {}
193
+ }
194
+
195
+
196
+ /**
197
+ * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
198
+ * done already
199
+ */
200
+ if (!this.canvas.__rgraph_aa_translated__) {
201
+ this.context.translate(0.5,0.5);
202
+
203
+ this.canvas.__rgraph_aa_translated__ = true;
204
+ }
205
+
206
+
207
+
208
+
209
+ // Short variable names
210
+ var RG = RGraph,
211
+ ca = this.canvas,
212
+ co = ca.getContext('2d'),
213
+ prop = this.properties,
214
+ pa = RG.Path,
215
+ pa2 = RG.path2,
216
+ win = window,
217
+ doc = document,
218
+ ma = Math
219
+
220
+
221
+
222
+ /**
223
+ * "Decorate" the object with the generic effects if the effects library has been included
224
+ */
225
+ if (RG.Effects && typeof RG.Effects.decorate === 'function') {
226
+ RG.Effects.decorate(this);
227
+ }
228
+
229
+
230
+
231
+
232
+ /**
233
+ * A setter
234
+ *
235
+ * @param name string The name of the property to set
236
+ * @param value mixed The value of the property
237
+ */
238
+ this.set =
239
+ this.Set = function (name, value)
240
+ {
241
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
242
+
243
+ /**
244
+ * the number of arguments is only one and it's an
245
+ * object - parse it for configuration data and return.
246
+ */
247
+ if (arguments.length === 1 && typeof name === 'object') {
248
+ RG.parseObjectStyleConfig(this, name);
249
+ return this;
250
+ }
251
+
252
+
253
+
254
+
255
+ /**
256
+ * This should be done first - prepend the propertyy name with "chart." if necessary
257
+ */
258
+ if (name.substr(0,6) != 'chart.') {
259
+ name = 'chart.' + name;
260
+ }
261
+
262
+
263
+
264
+ // Convert uppercase letters to dot+lower case letter
265
+ name = name.replace(/([A-Z])/g, function (str)
266
+ {
267
+ return '.' + String(RegExp.$1).toLowerCase()
268
+ });
269
+
270
+
271
+
272
+
273
+ if (name == 'chart.total' && prop['chart.numxticks'] == null) {
274
+ prop['chart.numxticks'] = this.data.length;
275
+ }
276
+
277
+
278
+
279
+ prop[name.toLowerCase()] = value;
280
+
281
+ return this;
282
+ };
283
+
284
+
285
+
286
+
287
+ /**
288
+ * A getter
289
+ *
290
+ * @param name string The name of the property to get
291
+ */
292
+ this.get =
293
+ this.Get = function (name)
294
+ {
295
+ /**
296
+ * This should be done first - prepend the property name with "chart." if necessary
297
+ */
298
+ if (name.substr(0,6) != 'chart.') {
299
+ name = 'chart.' + name;
300
+ }
301
+
302
+ // Convert uppercase letters to dot+lower case letter
303
+ name = name.replace(/([A-Z])/g, function (str)
304
+ {
305
+ return '.' + String(RegExp.$1).toLowerCase()
306
+ });
307
+
308
+ return prop[name.toLowerCase()];
309
+ };
310
+
311
+
312
+
313
+
314
+ /**
315
+ * The function you call to draw the bar chart
316
+ */
317
+ this.draw =
318
+ this.Draw = function ()
319
+ {
320
+ /**
321
+ * Fire the onbeforedraw event
322
+ */
323
+ RGraph.FireCustomEvent(this, 'onbeforedraw');
324
+
325
+
326
+ /**
327
+ * Parse the colors. This allows for simple gradient syntax
328
+ */
329
+ if (!this.colorsParsed) {
330
+ this.parseColors();
331
+
332
+ // Don't want to do this again
333
+ this.colorsParsed = true;
334
+ }
335
+
336
+
337
+ /**
338
+ * Draw the background image
339
+ */
340
+ RGraph.DrawBackgroundImage(this);
341
+
342
+ /**
343
+ * This is new in May 2011 and facilitates indiviual gutter settings,
344
+ * eg chart.gutter.left
345
+ */
346
+ this.gutterLeft = prop['chart.gutter.left'];
347
+ this.gutterRight = prop['chart.gutter.right'];
348
+ this.gutterTop = prop['chart.gutter.top'];
349
+ this.gutterBottom = prop['chart.gutter.bottom'];
350
+
351
+ /**
352
+ * Stop the coords array from growing uncontrollably
353
+ */
354
+ this.coords = [];
355
+
356
+
357
+
358
+ /**
359
+ * Stop this growing uncontrollably
360
+ */
361
+ this.coordsText = [];
362
+
363
+
364
+
365
+
366
+ /**
367
+ * This gets used a lot
368
+ */
369
+ this.centery = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop;
370
+
371
+ /**
372
+ * Work out a few things. They need to be here because they depend on things you can change after you instantiate the object
373
+ */
374
+ this.max = 0;
375
+ this.grapharea = ca.height - this.gutterTop - this.gutterBottom;
376
+ this.graphwidth = ca.width - this.gutterLeft - this.gutterRight;
377
+ this.halfTextHeight = prop['chart.text.size'] / 2;
378
+
379
+
380
+ /**
381
+ * Work out the maximum value
382
+ */
383
+ this.max = this.getMax(this.data);
384
+
385
+ var decimals = prop['chart.scale.decimals'];
386
+ this.scale2 = RGraph.getScale2(this, {'max':typeof(prop['chart.ymax']) == 'number' ? prop['chart.ymax'] : this.max,
387
+ 'min':prop['chart.xmin'],
388
+ 'strict': typeof(prop['chart.ymax']) == 'number' ? true : false,
389
+ 'scale.decimals':Number(decimals),
390
+ 'scale.point':prop['chart.scale.point'],
391
+ 'scale.thousand':prop['chart.scale.thousand'],
392
+ 'scale.round':prop['chart.scale.round'],
393
+ 'units.pre':prop['chart.units.pre'],
394
+ 'units.post':prop['chart.units.post'],
395
+ 'ylabels.count':prop['chart.ylabels.count']
396
+ });
397
+
398
+ this.max = this.scale2.max;
399
+
400
+
401
+ // Draw the background hbars
402
+ RGraph.DrawBars(this)
403
+
404
+ // Progressively Draw the chart
405
+ RG.background.Draw(this);
406
+
407
+ this.DrawAxes();
408
+ this.Drawbars();
409
+ this.DrawLabels();
410
+
411
+ /**
412
+ * If the X axis is at the bottom - draw the it again so that it appears "on top" of the bars
413
+ */
414
+ if (prop['chart.xaxispos'] == 'bottom' && prop['chart.noaxes'] == false && prop['chart.noxaxis'] == false) {
415
+ co.strokeStyle = prop['chart.axis.color'];
416
+ co.strokeRect(prop['chart.gutter.left'], ca.height - prop['chart.gutter.bottom'], ca.width - this.gutterLeft - this.gutterRight, 0);
417
+ }
418
+
419
+ /**
420
+ * Setup the context menu if required
421
+ */
422
+ if (prop['chart.contextmenu']) {
423
+ RG.ShowContext(this);
424
+ }
425
+
426
+
427
+ /**
428
+ * This function enables resizing
429
+ */
430
+ if (prop['chart.resizable']) {
431
+ RG.AllowResizing(this);
432
+ }
433
+
434
+
435
+ /**
436
+ * This installs the event listeners
437
+ */
438
+ RG.InstallEventListeners(this);
439
+
440
+
441
+
442
+ /**
443
+ * Fire the onfirstdraw event
444
+ */
445
+ if (this.firstDraw) {
446
+ RG.fireCustomEvent(this, 'onfirstdraw');
447
+ this.firstDraw = false;
448
+ this.firstDrawFunc();
449
+ }
450
+
451
+
452
+
453
+
454
+ /**
455
+ * Fire the RGraph ondraw event
456
+ */
457
+ RG.FireCustomEvent(this, 'ondraw');
458
+
459
+ return this;
460
+ };
461
+
462
+
463
+
464
+
465
+ /**
466
+ * Draws the charts axes
467
+ */
468
+ this.drawAxes =
469
+ this.DrawAxes = function ()
470
+ {
471
+ if (prop['chart.noaxes']) {
472
+ return;
473
+ }
474
+
475
+ co.beginPath();
476
+ co.strokeStyle = prop['chart.axis.color'];
477
+ co.lineWidth = prop['chart.axis.linewidth'] + 0.001;
478
+
479
+ // Draw the Y axis
480
+ if (prop['chart.noyaxis'] == false) {
481
+ co.moveTo(Math.round(this.gutterLeft), this.gutterTop);
482
+ co.lineTo(Math.round(this.gutterLeft), ca.height - this.gutterBottom);
483
+ }
484
+
485
+ // Draw the X axis
486
+ if (prop['chart.noxaxis'] == false) {
487
+ // Center X axis
488
+ if (prop['chart.xaxispos'] == 'center') {
489
+ co.moveTo(this.gutterLeft, Math.round( ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop));
490
+ co.lineTo(ca.width - this.gutterRight, Math.round( ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop));
491
+ } else {
492
+ co.moveTo(this.gutterLeft, Math.round(ca.height - this.gutterBottom));
493
+ co.lineTo(ca.width - this.gutterRight, Math.round(ca.height - this.gutterBottom));
494
+ }
495
+ }
496
+
497
+ var numYTicks = prop['chart.numyticks'];
498
+
499
+ // Draw the Y tickmarks
500
+ if (prop['chart.noyaxis'] == false && prop['chart.numyticks'] > 0) {
501
+
502
+ var yTickGap = (ca.height - this.gutterTop - this.gutterBottom) / numYTicks;
503
+
504
+ for (y=this.gutterTop; y < (ca.height - this.gutterBottom); y += yTickGap) {
505
+ if (prop['chart.xaxispos'] == 'bottom' || (y != ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop)) {
506
+ co.moveTo(this.gutterLeft, Math.round( y));
507
+ co.lineTo(this.gutterLeft - 3, Math.round( y));
508
+ }
509
+ }
510
+
511
+ /**
512
+ * If the X axis is not being shown, draw an extra tick
513
+ */
514
+ if (prop['chart.noxaxis'] || prop['chart.xaxispos'] == 'center') {
515
+ co.moveTo(this.gutterLeft - 3, Math.round(ca.height - this.gutterBottom));
516
+ co.lineTo(this.gutterLeft, Math.round(ca.height - this.gutterBottom));
517
+ }
518
+ }
519
+
520
+
521
+ // Draw the X tickmarks
522
+ if (prop['chart.numxticks'] == null) {
523
+ prop['chart.numxticks'] = this.data.length + (prop['chart.total'] ? 1 : 0)
524
+ }
525
+
526
+ if (prop['chart.noxaxis'] == false && prop['chart.numxticks'] > 0) {
527
+
528
+ xTickGap = (ca.width - this.gutterLeft - this.gutterRight ) / prop['chart.numxticks'];
529
+
530
+ if (prop['chart.xaxispos'] == 'center') {
531
+ yStart = ((ca.height - this.gutterBottom - this.gutterTop) / 2) + this.gutterTop - 3;
532
+ yEnd = ((ca.height - this.gutterBottom - this.gutterTop) / 2) + this.gutterTop + 3;
533
+ } else {
534
+ yStart = ca.height - this.gutterBottom;
535
+ yEnd = (ca.height - this.gutterBottom) + 3;
536
+ }
537
+
538
+ for (x=this.gutterLeft + xTickGap; x<=ca.width - this.gutterRight + 1; x+=xTickGap) {
539
+ co.moveTo(Math.round( x), yStart);
540
+ co.lineTo(Math.round( x), yEnd);
541
+ }
542
+
543
+ if (prop['chart.noyaxis']) {
544
+ co.moveTo(Math.round( this.gutterLeft), yStart);
545
+ co.lineTo(Math.round( this.gutterLeft), yEnd);
546
+ }
547
+ }
548
+
549
+ /**
550
+ * If the Y axis is not being shown, draw an extra tick
551
+ */
552
+ if (prop['chart.noyaxis'] && prop['chart.noxaxis'] == false) {
553
+ co.moveTo(Math.round( this.gutterLeft), ca.height - this.gutterBottom);
554
+ co.lineTo(Math.round( this.gutterLeft), ca.height - this.gutterBottom + 3);
555
+ }
556
+
557
+ co.stroke();
558
+ };
559
+
560
+
561
+
562
+
563
+ /**
564
+ * Draws the labels for the graph
565
+ */
566
+ this.drawLabels =
567
+ this.DrawLabels = function ()
568
+ {
569
+ var context = co;
570
+ var numYLabels = 5; // Make this configurable
571
+ var interval = this.grapharea / numYLabels;
572
+ var font = prop['chart.text.font'];
573
+ var size = prop['chart.text.size'];
574
+ var color = prop['chart.text.color'];
575
+ var units_pre = prop['chart.units.pre'];
576
+ var units_post = prop['chart.units.post'];
577
+
578
+ co.beginPath();
579
+ co.fillStyle = color;
580
+
581
+ /**
582
+ * First, draw the Y labels
583
+ */
584
+ if (prop['chart.ylabels']) {
585
+ if (prop['chart.xaxispos'] == 'center') {
586
+
587
+ var halfInterval = interval / 2;
588
+ var halfWay = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop;
589
+
590
+ for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
591
+ RG.text2(this, {
592
+ 'font':font,
593
+ 'size':size,
594
+ 'x':this.gutterLeft - 5,
595
+ 'y': this.gutterTop + (((this.grapharea/2) / len) * i),
596
+ 'text':this.scale2.labels[len - i - 1],
597
+ 'valign':'center',
598
+ 'halign':'right',
599
+ 'tag': 'scale'
600
+ });
601
+
602
+ RG.Text2(this, {
603
+ 'font':font,
604
+ 'size':size,
605
+ 'x':this.gutterLeft - 5,
606
+ 'y': halfWay + (((this.grapharea/2) / len) * (i + 1)),
607
+ 'text':this.scale2.labels[i],
608
+ 'valign':'center',
609
+ 'halign':'right',
610
+ 'tag': 'scale'
611
+ });
612
+ }
613
+
614
+ } else {
615
+
616
+ for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
617
+ RG.text2(this, {
618
+ 'font':font,
619
+ 'size':size,
620
+ 'x':this.gutterLeft - 5,
621
+ 'y': ca.height - this.gutterBottom - ((this.grapharea / len) * (i + 1)),
622
+ 'text':this.scale2.labels[i],
623
+ 'valign':'center',
624
+ 'halign':'right',
625
+ 'tag': 'scale'
626
+ });
627
+ }
628
+ }
629
+ }
630
+
631
+
632
+
633
+ /**
634
+ * Now, draw the X labels
635
+ */
636
+ if (prop['chart.labels'].length > 0) {
637
+
638
+ // Recalculate the interval for the X labels
639
+ interval = (ca.width - this.gutterLeft - this.gutterRight) / prop['chart.labels'].length;
640
+
641
+ var halign = 'center';
642
+ var angle = prop['chart.text.angle'];
643
+
644
+ if (angle) {
645
+ halign = 'right';
646
+ angle *= -1;
647
+ }
648
+
649
+ var labels = prop['chart.labels'],
650
+ labelsColor = prop['chart.labels.color'],
651
+ bold = prop['chart.labels.bold']
652
+
653
+ for (var i=0,len=labels.length; i<len; i+=1) {
654
+ RG.text2(this, {
655
+ 'color': labelsColor,
656
+ 'font':font,
657
+ 'size':size,
658
+ 'bold': bold,
659
+ 'x':this.gutterLeft + (i * interval) + (interval / 2),
660
+ 'y':ca.height - this.gutterBottom + 5 + this.halfTextHeight,
661
+ 'text':labels[i],
662
+ 'valign':'center',
663
+ 'halign':halign,
664
+ 'angle':angle,
665
+ 'tag': 'labels'
666
+ });
667
+ }
668
+ }
669
+
670
+ co.stroke();
671
+ co.fill();
672
+ };
673
+
674
+
675
+
676
+
677
+ /**
678
+ * Draws the bars on to the chart
679
+ */
680
+ this.drawbars =
681
+ this.Drawbars = function ()
682
+ {
683
+ var context = co;
684
+ var canvas = ca;
685
+ var hmargin = prop['chart.hmargin'];
686
+ var runningTotal = 0;
687
+
688
+ co.lineWidth = prop['chart.linewidth'] + 0.001;
689
+
690
+ for (var i=0,len=this.data.length; i<len; ++i) {
691
+ co.beginPath();
692
+ co.strokeStyle = prop['chart.strokestyle'];
693
+
694
+ var x = Math.round( this.gutterLeft + hmargin + (((this.graphwidth / (this.data.length + (prop['chart.total'] ? 1 : 0))) * i) * prop['chart.multiplier.x']));
695
+ var y = Math.round( this.gutterTop + this.grapharea - (i == 0 ? ((this.data[0] / this.max) * this.grapharea) : (this.data[i] > 0 ? ((runningTotal + this.data[i]) / this.max) * this.grapharea : (runningTotal / this.max) * this.grapharea)));
696
+ var w = ((ca.width - this.gutterLeft - this.gutterRight) / (this.data.length + (prop['chart.total'] ? 1 : 0 )) ) - (2 * prop['chart.hmargin']);
697
+ w = w * prop['chart.multiplier.w'];
698
+ var h = (Math.abs(this.data[i]) / this.max) * this.grapharea;
699
+
700
+ if (prop['chart.xaxispos'] == 'center') {
701
+ h /= 2;
702
+ y = (i == 0 ? ((this.data[0] / this.max) * this.grapharea) : (this.data[i] > 0 ? ((runningTotal + this.data[i]) / this.max) * this.grapharea : (runningTotal / this.max) * this.grapharea));
703
+ y = this.gutterTop + (this.grapharea/2) - (y / 2);
704
+ }
705
+
706
+ // Color
707
+ co.fillStyle = this.data[i] >= 0 ? prop['chart.colors'][0] : prop['chart.colors'][1];
708
+
709
+
710
+ if (prop['chart.shadow']) {
711
+ RG.SetShadow(this, prop['chart.shadow.color'], prop['chart.shadow.offsetx'], prop['chart.shadow.offsety'], prop['chart.shadow.blur']);
712
+ } else {
713
+ RG.NoShadow(this);
714
+ }
715
+
716
+ co.rect(x, y, w, h);
717
+
718
+ this.coords.push([x, y, w, h]);
719
+
720
+ runningTotal += this.data[i];
721
+
722
+ co.stroke();
723
+ co.fill();
724
+ }
725
+
726
+ // Store the total
727
+ this.total = runningTotal;
728
+
729
+ if (prop['chart.total']) {
730
+
731
+ // This is the height of the final bar
732
+ h = (runningTotal / this.max) * (this.grapharea / (prop['chart.xaxispos'] == 'center' ? 2 : 1));
733
+
734
+ /**
735
+ * Set the Y (ie the start point) value
736
+ */
737
+ if (prop['chart.xaxispos'] == 'center') {
738
+ y = runningTotal > 0 ? this.centery - h : this.centery - h;
739
+ } else {
740
+ y = ca.height - this.gutterBottom - h;
741
+ }
742
+
743
+ // This is the X position of the final bar
744
+ x = x + (prop['chart.hmargin'] * 2) + w;
745
+
746
+
747
+ // Final color
748
+ co.fillStyle = prop['chart.colors'][2];
749
+
750
+ co.beginPath();
751
+ co.strokeRect(x, y, w, h);
752
+ co.fillRect(x, y, w, h);
753
+ co.stroke();
754
+ co.fill();
755
+
756
+ this.coords.push([x, y - (runningTotal > 0 ? 0 : Math.abs(h)), w, Math.abs(h)]);
757
+ }
758
+
759
+ RG.NoShadow(this);
760
+
761
+ /**
762
+ * This draws the connecting lines
763
+ */
764
+ co.lineWidth = 1;
765
+
766
+ for (var i=1,len=this.coords.length; i<len; i+=1) {
767
+ co.strokeStyle = 'gray';
768
+ co.beginPath();
769
+ if (this.data[i - 1] > 0) {
770
+ co.moveTo(this.coords[i - 1][0] + this.coords[i - 1][2], Math.round( this.coords[i - 1][1]));
771
+ co.lineTo(this.coords[i - 1][0] + this.coords[i - 1][2] + (2 * hmargin), Math.round( this.coords[i - 1][1]));
772
+ } else {
773
+ co.moveTo(this.coords[i - 1][0] + this.coords[i - 1][2], Math.round( this.coords[i - 1][1] + this.coords[i - 1][3]));
774
+ co.lineTo(this.coords[i - 1][0] + this.coords[i - 1][2] + (2 * hmargin), Math.round( this.coords[i - 1][1] + this.coords[i - 1][3]));
775
+ }
776
+ co.stroke();
777
+ }
778
+ };
779
+
780
+
781
+
782
+
783
+ /**
784
+ * Not used by the class during creating the graph, but is used by event handlers
785
+ * to get the coordinates (if any) of the selected bar
786
+ *
787
+ * @param object e The event object
788
+ */
789
+ this.getShape =
790
+ this.getBar = function (e)
791
+ {
792
+ /**
793
+ * Loop through the bars determining if the mouse is over a bar
794
+ */
795
+ for (var i=0,len=this.coords.length; i<len; i++) {
796
+
797
+ var mouseCoords = RG.getMouseXY(e);
798
+ var mouseX = mouseCoords[0];
799
+ var mouseY = mouseCoords[1];
800
+
801
+ var left = this.coords[i][0];
802
+ var top = this.coords[i][1];
803
+ var width = this.coords[i][2];
804
+ var height = this.coords[i][3];
805
+
806
+ if ( mouseX >= left
807
+ && mouseX <= (left + width)
808
+ && mouseY >= top
809
+ && mouseY <= top + height) {
810
+
811
+ var tooltip = RG.parseTooltipText(prop['chart.tooltips'], i);
812
+
813
+ return {0: this, 'object': this,
814
+ 1: left, 'x': left,
815
+ 2: top, 'y': top,
816
+ 3: width, 'width': width,
817
+ 4: height, 'height': height,
818
+ 5: i, 'index': i,
819
+ 'tooltip': tooltip};
820
+ }
821
+ }
822
+
823
+ return null;
824
+ };
825
+
826
+
827
+
828
+
829
+ /**
830
+ * The Waterfall is slightly different to Bar/Line charts so has this function to get the max value
831
+ */
832
+ this.getMax = function (data)
833
+ {
834
+ var runningTotal = 0;
835
+ var max = 0;
836
+
837
+ for (var i=0,len=data.length; i<len; i+=1) {
838
+ runningTotal += data[i];
839
+ max = ma.max(max, ma.abs(runningTotal));
840
+ }
841
+
842
+ return max;
843
+ };
844
+
845
+
846
+
847
+
848
+ /**
849
+ * This function facilitates the installation of tooltip event listeners if
850
+ * tooltips are defined.
851
+ */
852
+ this.allowTooltips =
853
+ this.AllowTooltips = function ()
854
+ {
855
+ // Preload any tooltip images that are used in the tooltips
856
+ RG.PreLoadTooltipImages(this);
857
+
858
+
859
+ /**
860
+ * This installs the window mousedown event listener that lears any
861
+ * highlight that may be visible.
862
+ */
863
+ RG.InstallWindowMousedownTooltipListener(this);
864
+
865
+
866
+ /**
867
+ * This installs the canvas mousemove event listener. This function
868
+ * controls the pointer shape.
869
+ */
870
+ RG.InstallCanvasMousemoveTooltipListener(this);
871
+
872
+
873
+ /**
874
+ * This installs the canvas mouseup event listener. This is the
875
+ * function that actually shows the appropriate tooltip (if any).
876
+ */
877
+ RG.InstallCanvasMouseupTooltipListener(this);
878
+ };
879
+
880
+
881
+
882
+
883
+ /**
884
+ * Each object type has its own Highlight() function which highlights the appropriate shape
885
+ *
886
+ * @param object shape The shape to highlight
887
+ */
888
+ this.highlight =
889
+ this.Highlight = function (shape)
890
+ {
891
+ // Add the new highlight
892
+ RG.Highlight.Rect(this, shape);
893
+ };
894
+
895
+
896
+
897
+
898
+ /**
899
+ * The getObjectByXY() worker method. Don't call this call:
900
+ *
901
+ * RGraph.ObjectRegistry.getObjectByXY(e)
902
+ *
903
+ * @param object e The event object
904
+ */
905
+ this.getObjectByXY = function (e)
906
+ {
907
+ var mouseXY = RG.getMouseXY(e);
908
+
909
+ if (
910
+ mouseXY[0] > this.gutterLeft
911
+ && mouseXY[0] < (ca.width - this.gutterRight)
912
+ && mouseXY[1] > this.gutterTop
913
+ && mouseXY[1] < (ca.height - this.gutterBottom)
914
+ ) {
915
+
916
+ return this;
917
+ }
918
+ };
919
+
920
+
921
+
922
+
923
+ /**
924
+ * This function positions a tooltip when it is displayed
925
+ *
926
+ * @param obj object The chart object
927
+ * @param int x The X coordinate specified for the tooltip
928
+ * @param int y The Y coordinate specified for the tooltip
929
+ * @param objec tooltip The tooltips DIV element
930
+ */
931
+ this.positionTooltip = function (obj, x, y, tooltip, idx)
932
+ {
933
+ var coordX = obj.coords[tooltip.__index__][0];
934
+ var coordY = obj.coords[tooltip.__index__][1];
935
+ var coordW = obj.coords[tooltip.__index__][2];
936
+ var coordH = obj.coords[tooltip.__index__][3];
937
+ var canvasXY = RG.getCanvasXY(obj.canvas);
938
+ var gutterLeft = obj.gutterLeft;
939
+ var gutterTop = obj.gutterTop;
940
+ var width = tooltip.offsetWidth;
941
+ var height = tooltip.offsetHeight;
942
+ var value = obj.data[idx];
943
+
944
+ /**
945
+ * Change the value to be the total if necessary
946
+ */
947
+ if (tooltip.__index__ == obj.data.length) {
948
+ value = obj.total;
949
+ }
950
+
951
+ // Set the top position
952
+ tooltip.style.left = 0;
953
+ tooltip.style.top = canvasXY[1] + coordY - height - 7 + 'px';
954
+
955
+
956
+ /**
957
+ * If the tooltip is for a negative value - position it underneath the bar
958
+ */
959
+ if (value < 0) {
960
+ tooltip.style.top = canvasXY[1] + coordY + coordH + 7 + 'px';
961
+ }
962
+
963
+
964
+ // By default any overflow is hidden
965
+ tooltip.style.overflow = '';
966
+
967
+ // The arrow
968
+ var img = new Image();
969
+ img.id = '__rgraph_tooltip_pointer__';
970
+ img.style.position = 'absolute';
971
+ if (value >= 0) {
972
+ img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC';
973
+ img.style.top = (tooltip.offsetHeight - 2) + 'px';
974
+ } else {
975
+ img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAFCAMAAACkeOZkAAAAK3RFWHRDcmVhdGlvbiBUaW1lAFNhdCA2IE9jdCAyMDEyIDEyOjQ5OjMyIC0wMDAw2S1RlgAAAAd0SU1FB9wKBgszM4Ed2k4AAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAEZ0FNQQAAsY8L/GEFAAAACVBMVEX/AAC9vb3//+92Pom0AAAAAXRSTlMAQObYZgAAAB1JREFUeNpjYAABRgY4YGRiRDCZYBwQE8qBMEEcAANCACqByy1sAAAAAElFTkSuQmCC';
976
+ img.style.top = '-5px';
977
+ }
978
+ tooltip.appendChild(img);
979
+
980
+ // Reposition the tooltip if at the edges:
981
+
982
+ // LEFT edge
983
+ if ((canvasXY[0] + coordX - (width / 2)) < 10) {
984
+ tooltip.style.left = (canvasXY[0] + coordX - (width * 0.1)) + (coordW / 2) + 'px';
985
+ img.style.left = ((width * 0.1) - 8.5) + 'px';
986
+
987
+ // RIGHT edge
988
+ } else if ((canvasXY[0] + coordX + (width / 2)) > doc.body.offsetWidth) {
989
+ tooltip.style.left = canvasXY[0] + coordX - (width * 0.9) + (coordW / 2) + 'px';
990
+ img.style.left = ((width * 0.9) - 8.5) + 'px';
991
+
992
+ // Default positioning - CENTERED
993
+ } else {
994
+ tooltip.style.left = (canvasXY[0] + coordX + (coordW / 2) - (width * 0.5)) + 'px';
995
+ img.style.left = ((width * 0.5) - 8.5) + 'px';
996
+ }
997
+ };
998
+
999
+
1000
+
1001
+
1002
+ /**
1003
+ * This method returns the appropriate Y coord for the given value
1004
+ *
1005
+ * @param number value The value
1006
+ */
1007
+ this.getYCoord = function (value)
1008
+ {
1009
+ if (value > this.max) {
1010
+ return null;
1011
+ }
1012
+
1013
+ if (prop['chart.xaxispos'] == 'center') {
1014
+
1015
+ if (value < (-1 * this.max)) {
1016
+ return null;
1017
+ }
1018
+
1019
+ var coord = (value / this.max) * (this.grapharea / 2);
1020
+ return this.gutterTop + (this.grapharea / 2) - coord;
1021
+
1022
+ } else {
1023
+
1024
+ if (value < 0) {
1025
+ return null;
1026
+ }
1027
+
1028
+ var coord = (value / this.max) * this.grapharea;
1029
+ coord = coord + this.gutterTop;
1030
+ return ca.height - coord;
1031
+ }
1032
+ };
1033
+
1034
+
1035
+
1036
+
1037
+ /**
1038
+ * This allows for easy specification of gradients
1039
+ */
1040
+ this.parseColors = function ()
1041
+ {
1042
+ // Save the original colors so that they can be restored when the canvas is reset
1043
+ if (this.original_colors.length === 0) {
1044
+ this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
1045
+ this.original_colors['chart.key.colors'] = RG.array_clone(prop['chart.key.colors']);
1046
+ this.original_colors['chart.crosshairs.color'] = RG.array_clone(prop['chart.crosshairs.color']);
1047
+ this.original_colors['chart.highlight.stroke'] = RG.array_clone(prop['chart.highlight.stroke']);
1048
+ this.original_colors['chart.highlight.fill'] = RG.array_clone(prop['chart.highlight.fill']);
1049
+ this.original_colors['chart.background.barcolor1'] = RG.array_clone(prop['chart.background.barcolor1']);
1050
+ this.original_colors['chart.background.barcolor2'] = RG.array_clone(prop['chart.background.barcolor2']);
1051
+ this.original_colors['chart.background.grid.color'] = RG.array_clone(prop['chart.background.grid.color']);
1052
+ this.original_colors['chart.strokestyle'] = RG.array_clone(prop['chart.strokestyle']);
1053
+ this.original_colors['chart.axis.color'] = RG.array_clone(prop['chart.axis.color']);
1054
+ }
1055
+
1056
+
1057
+
1058
+
1059
+
1060
+
1061
+
1062
+
1063
+ // chart.colors
1064
+ var colors = prop['chart.colors'];
1065
+
1066
+ if (colors) {
1067
+ for (var i=0,len=colors.length; i<len; ++i) {
1068
+ colors[i] = this.parseSingleColorForGradient(colors[i]);
1069
+ }
1070
+ }
1071
+
1072
+ // chart.key.colors
1073
+ var colors = prop['chart.key.colors'];
1074
+
1075
+ if (colors) {
1076
+ for (var i=0,len=colors.length; i<len; ++i) {
1077
+ colors[i] = this.parseSingleColorForGradient(colors[i]);
1078
+ }
1079
+ }
1080
+
1081
+ prop['chart.crosshairs.color'] = this.parseSingleColorForGradient(prop['chart.crosshairs.color']);
1082
+ prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
1083
+ prop['chart.highlight.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.fill']);
1084
+ prop['chart.background.barcolor1'] = this.parseSingleColorForGradient(prop['chart.background.barcolor1']);
1085
+ prop['chart.background.barcolor2'] = this.parseSingleColorForGradient(prop['chart.background.barcolor2']);
1086
+ prop['chart.background.grid.color'] = this.parseSingleColorForGradient(prop['chart.background.grid.color']);
1087
+ prop['chart.strokestyle'] = this.parseSingleColorForGradient(prop['chart.strokestyle']);
1088
+ prop['chart.axis.color'] = this.parseSingleColorForGradient(prop['chart.axis.color']);
1089
+ };
1090
+
1091
+
1092
+
1093
+
1094
+ /**
1095
+ * Use this function to reset the object to the post-constructor state. Eg reset colors if
1096
+ * need be etc
1097
+ */
1098
+ this.reset = function ()
1099
+ {
1100
+ };
1101
+
1102
+
1103
+
1104
+
1105
+ /**
1106
+ * This parses a single color value
1107
+ *
1108
+ * @param string color The color to parse for gradients
1109
+ */
1110
+ this.parseSingleColorForGradient = function (color)
1111
+ {
1112
+ if (!color || typeof color != 'string') {
1113
+ return color;
1114
+ }
1115
+
1116
+ if (typeof color === 'string' && color.match(/^gradient\((.*)\)$/i)) {
1117
+
1118
+ var parts = RegExp.$1.split(':');
1119
+
1120
+ // Create the gradient
1121
+
1122
+ var grad = co.createLinearGradient(0,ca.height - prop['chart.gutter.bottom'], 0, prop['chart.gutter.top']);
1123
+
1124
+ var diff = 1 / (parts.length - 1);
1125
+
1126
+ grad.addColorStop(0, RG.trim(parts[0]));
1127
+
1128
+ for (var j=1,len=parts.length; j<len; ++j) {
1129
+ grad.addColorStop(j * diff, RG.trim(parts[j]));
1130
+ }
1131
+ }
1132
+
1133
+ return grad ? grad : color;
1134
+ };
1135
+
1136
+
1137
+
1138
+
1139
+ /**
1140
+ * Using a function to add events makes it easier to facilitate method chaining
1141
+ *
1142
+ * @param string type The type of even to add
1143
+ * @param function func
1144
+ */
1145
+ this.on = function (type, func)
1146
+ {
1147
+ if (type.substr(0,2) !== 'on') {
1148
+ type = 'on' + type;
1149
+ }
1150
+
1151
+ this[type] = func;
1152
+
1153
+ return this;
1154
+ };
1155
+
1156
+
1157
+
1158
+
1159
+ /**
1160
+ * This function runs once only
1161
+ * (put at the end of the file (before any effects))
1162
+ */
1163
+ this.firstDrawFunc = function ()
1164
+ {
1165
+ };
1166
+
1167
+
1168
+
1169
+
1170
+ /**
1171
+ * Waterfall Grow
1172
+ *
1173
+ * @param object Options. You can pass frames here - which should be a number
1174
+ * @param function An optional function which is called when the animation is finished
1175
+ */
1176
+ this.grow = function ()
1177
+ {
1178
+ var opt = arguments[0] || {};
1179
+ var callback = arguments[1] || function () {};
1180
+ var frames = opt.frames || 30;
1181
+ var numFrame = 0;
1182
+ var obj = this;
1183
+ var data = RG.array_clone(obj.data);
1184
+
1185
+ //Reset The data to zeros
1186
+ for (var i=0,len=obj.data.length; i<len; ++i) {
1187
+ obj.data[i] /= frames;
1188
+ }
1189
+
1190
+ /**
1191
+ * Fix the scale
1192
+ */
1193
+ if (obj.Get('chart.ymax') == null) {
1194
+ var max = obj.getMax(data);
1195
+ var scale2 = RG.getScale2(obj, {'max':max});
1196
+ obj.Set('chart.ymax', scale2.max);
1197
+ }
1198
+
1199
+ //obj.Set('chart.multiplier.x', 0);
1200
+ //obj.Set('chart.multiplier.w', 0);
1201
+
1202
+ function iterator ()
1203
+ {
1204
+ for (var i=0; i<obj.data.length; ++i) {
1205
+
1206
+ // This produces a very slight easing effect
1207
+ obj.data[i] = data[i] * RG.Effects.getEasingMultiplier(frames, numFrame);
1208
+ }
1209
+
1210
+ RGraph.clear(obj.canvas);
1211
+ RGraph.redrawCanvas(obj.canvas);
1212
+
1213
+ if (++numFrame < frames) {
1214
+ RGraph.Effects.updateCanvas(iterator);
1215
+ } else {
1216
+ callback(obj);
1217
+ }
1218
+ }
1219
+
1220
+ iterator();
1221
+
1222
+ return this;
1223
+ };
1224
+
1225
+
1226
+
1227
+
1228
+
1229
+ RG.att(ca);
1230
+
1231
+
1232
+ /**
1233
+ * Now, because canvases can support multiple charts, canvases must always be registered
1234
+ */
1235
+ RG.Register(this);
1236
+
1237
+
1238
+
1239
+
1240
+ /**
1241
+ * This is the 'end' of the constructor so if the first argument
1242
+ * contains configuration data - handle that.
1243
+ */
1244
+ if (parseConfObjectForOptions) {
1245
+ RG.parseObjectStyleConfig(this, conf.options);
1246
+ }
1247
+
1248
+
1249
+
1250
+
1251
+ return this;
1252
+ };