rgraph-rails 1.0.1

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 (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
+ };