rgraph-rails 4.62 → 4.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +3 -4
  3. data/lib/rgraph-rails/version.rb +1 -1
  4. data/vendor/assets/javascripts/RGraph.bar.js +240 -3742
  5. data/vendor/assets/javascripts/RGraph.bipolar.js +165 -2005
  6. data/vendor/assets/javascripts/RGraph.common.annotate.js +35 -395
  7. data/vendor/assets/javascripts/RGraph.common.context.js +30 -595
  8. data/vendor/assets/javascripts/RGraph.common.core.js +418 -5359
  9. data/vendor/assets/javascripts/RGraph.common.csv.js +20 -276
  10. data/vendor/assets/javascripts/RGraph.common.deprecated.js +35 -450
  11. data/vendor/assets/javascripts/RGraph.common.dynamic.js +88 -1395
  12. data/vendor/assets/javascripts/RGraph.common.effects.js +90 -1545
  13. data/vendor/assets/javascripts/RGraph.common.key.js +52 -753
  14. data/vendor/assets/javascripts/RGraph.common.resizing.js +37 -563
  15. data/vendor/assets/javascripts/RGraph.common.sheets.js +29 -352
  16. data/vendor/assets/javascripts/RGraph.common.tooltips.js +32 -450
  17. data/vendor/assets/javascripts/RGraph.common.zoom.js +14 -219
  18. data/vendor/assets/javascripts/RGraph.cornergauge.js +71 -0
  19. data/vendor/assets/javascripts/RGraph.drawing.background.js +34 -570
  20. data/vendor/assets/javascripts/RGraph.drawing.circle.js +33 -544
  21. data/vendor/assets/javascripts/RGraph.drawing.image.js +51 -755
  22. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +37 -645
  23. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +36 -633
  24. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +35 -514
  25. data/vendor/assets/javascripts/RGraph.drawing.poly.js +37 -559
  26. data/vendor/assets/javascripts/RGraph.drawing.rect.js +33 -548
  27. data/vendor/assets/javascripts/RGraph.drawing.text.js +36 -664
  28. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +50 -812
  29. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +51 -856
  30. data/vendor/assets/javascripts/RGraph.fuel.js +58 -964
  31. data/vendor/assets/javascripts/RGraph.funnel.js +55 -984
  32. data/vendor/assets/javascripts/RGraph.gantt.js +77 -1354
  33. data/vendor/assets/javascripts/RGraph.gauge.js +85 -1421
  34. data/vendor/assets/javascripts/RGraph.hbar.js +162 -2788
  35. data/vendor/assets/javascripts/RGraph.hprogress.js +80 -1401
  36. data/vendor/assets/javascripts/RGraph.line.js +249 -4248
  37. data/vendor/assets/javascripts/RGraph.meter.js +74 -1280
  38. data/vendor/assets/javascripts/RGraph.modaldialog.js +19 -301
  39. data/vendor/assets/javascripts/RGraph.odo.js +71 -1264
  40. data/vendor/assets/javascripts/RGraph.pie.js +137 -2288
  41. data/vendor/assets/javascripts/RGraph.radar.js +110 -1847
  42. data/vendor/assets/javascripts/RGraph.rose.js +108 -1977
  43. data/vendor/assets/javascripts/RGraph.rscatter.js +80 -1432
  44. data/vendor/assets/javascripts/RGraph.scatter.js +172 -3163
  45. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +60 -1120
  46. data/vendor/assets/javascripts/RGraph.svg.bar.js +66 -1735
  47. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +21 -246
  48. data/vendor/assets/javascripts/RGraph.svg.common.core.js +255 -3937
  49. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +20 -276
  50. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +68 -1303
  51. data/vendor/assets/javascripts/RGraph.svg.common.key.js +19 -205
  52. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +29 -352
  53. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +22 -273
  54. data/vendor/assets/javascripts/RGraph.svg.funnel.js +32 -0
  55. data/vendor/assets/javascripts/RGraph.svg.hbar.js +59 -1400
  56. data/vendor/assets/javascripts/RGraph.svg.line.js +70 -1580
  57. data/vendor/assets/javascripts/RGraph.svg.pie.js +55 -1131
  58. data/vendor/assets/javascripts/RGraph.svg.radar.js +57 -1502
  59. data/vendor/assets/javascripts/RGraph.svg.rose.js +66 -1817
  60. data/vendor/assets/javascripts/RGraph.svg.scatter.js +58 -1261
  61. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +28 -865
  62. data/vendor/assets/javascripts/RGraph.svg.waterfall.js +45 -1252
  63. data/vendor/assets/javascripts/RGraph.thermometer.js +63 -1136
  64. data/vendor/assets/javascripts/RGraph.vprogress.js +83 -1470
  65. data/vendor/assets/javascripts/RGraph.waterfall.js +83 -1347
  66. metadata +5 -4
  67. data/vendor/assets/javascripts/financial-data.js +0 -1067
@@ -1,2789 +1,163 @@
1
- // version: 2017-05-08
2
- /**
3
- * o--------------------------------------------------------------------------------o
4
- * | This file is part of the RGraph package - you can learn more at: |
5
- * | |
6
- * | http://www.rgraph.net |
7
- * | |
8
- * | RGraph is licensed under the Open Source MIT license. That means that it's |
9
- * | totally free to use! |
10
- * o--------------------------------------------------------------------------------o
11
- */
12
1
 
13
- RGraph = window.RGraph || {isRGraph: true};
14
-
15
- /**
16
- * The horizontal bar chart constructor. The horizontal bar is a minor variant
17
- * on the bar chart. If you have big labels, this may be useful as there is usually
18
- * more space available for them.
19
- *
20
- * @param object canvas The canvas object
21
- * @param array data The chart data
22
- */
23
- RGraph.HBar = function (conf)
24
- {
25
- /**
26
- * Allow for object config style
27
- */
28
- if ( typeof conf === 'object'
29
- && typeof conf.data === 'object'
30
- && typeof conf.id === 'string') {
31
-
32
- var id = conf.id
33
- var canvas = document.getElementById(id);
34
- var data = conf.data;
35
- var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
36
-
37
- } else {
38
-
39
- var id = conf;
40
- var canvas = document.getElementById(id);
41
- var data = arguments[1];
42
- }
43
-
44
-
45
- this.id = id;
46
- this.canvas = canvas;
47
- this.context = this.canvas.getContext ? this.canvas.getContext("2d", {alpha: (typeof id === 'object' && id.alpha === false) ? false : true}) : null;
48
- this.canvas.__object__ = this;
49
- this.data = data;
50
- this.type = 'hbar';
51
- this.isRGraph = true;
52
- this.uid = RGraph.CreateUID();
53
- this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
54
- this.colorsParsed = false;
55
- this.coords = [];
56
- this.coords2 = [];
57
- this.coordsText = [];
58
- this.original_colors = [];
59
- this.firstDraw = true; // After the first draw this will be false
60
-
61
-
62
-
63
-
64
- this.max = 0;
65
- this.stackedOrGrouped = false;
66
-
67
- // Default properties
68
- this.properties =
69
- {
70
- 'chart.gutter.left': 75,
71
- 'chart.gutter.left.autosize': false,
72
- 'chart.gutter.right': 25,
73
- 'chart.gutter.top': 25,
74
- 'chart.gutter.bottom': 25,
75
- 'chart.background.grid': true,
76
- 'chart.background.grid.color': '#ddd',
77
- 'chart.background.grid.width': 1,
78
- 'chart.background.grid.hsize': 25,
79
- 'chart.background.grid.vsize': 25,
80
- 'chart.background.barcolor1': 'rgba(0,0,0,0)',
81
- 'chart.background.barcolor2': 'rgba(0,0,0,0)',
82
- 'chart.background.grid.hlines': true,
83
- 'chart.background.grid.vlines': true,
84
- 'chart.background.grid.border': true,
85
- 'chart.background.grid.autofit':true,
86
- 'chart.background.grid.autofit.align':true,
87
- 'chart.background.grid.autofit.numhlines': null,
88
- 'chart.background.grid.autofit.numvlines': 5,
89
- 'chart.background.grid.dashed': false,
90
- 'chart.background.grid.dotted': false,
91
- 'chart.background.color': null,
92
- 'chart.linewidth': 1,
93
- 'chart.title': '',
94
- 'chart.title.background': null,
95
- 'chart.title.xaxis': '',
96
- 'chart.title.xaxis.bold': true,
97
- 'chart.title.xaxis.size': null,
98
- 'chart.title.xaxis.font': null,
99
- 'chart.title.yaxis': '',
100
- 'chart.title.yaxis.bold': true,
101
- 'chart.title.yaxis.size': null,
102
- 'chart.title.yaxis.font': null,
103
- 'chart.title.yaxis.color': null,
104
- 'chart.title.xaxis.pos': null,
105
- 'chart.title.yaxis.pos': 0.8,
106
- 'chart.title.yaxis.x': null,
107
- 'chart.title.yaxis.y': null,
108
- 'chart.title.xaxis.x': null,
109
- 'chart.title.xaxis.y': null,
110
- 'chart.title.xaxis.color': null,
111
- 'chart.title.hpos': null,
112
- 'chart.title.vpos': null,
113
- 'chart.title.bold': true,
114
- 'chart.title.font': null,
115
- 'chart.title.x': null,
116
- 'chart.title.y': null,
117
- 'chart.title.halign': null,
118
- 'chart.title.valign': null,
119
- 'chart.text.size': 12,
120
- 'chart.text.color': 'black',
121
- 'chart.text.font': 'Segoe UI, Arial, Verdana, sans-serif',
122
- 'chart.text.accessible': true,
123
- 'chart.text.accessible.overflow': 'visible',
124
- 'chart.text.accessible.pointerevents': true,
125
- 'chart.colors': ['red', 'blue', 'green', 'pink', 'yellow', 'cyan', 'navy', 'gray', 'black'],
126
- 'chart.colors.sequential': false,
127
- 'chart.xlabels.specific': null,
128
- 'chart.labels': [],
129
- 'chart.labels.bold': false,
130
- 'chart.labels.color': null,
131
-
132
- 'chart.labels.above': false,
133
- 'chart.labels.above.decimals': 0,
134
- 'chart.labels.above.specific': null,
135
- 'chart.labels.above.color': null,
136
- 'chart.labels.above.units.pre': '',
137
- 'chart.labels.above.units.post': '',
138
- 'chart.labels.above.font': null,
139
- 'chart.labels.above.size': null,
140
- 'chart.labels.above.bold': false,
141
- 'chart.labels.above.italic': false,
142
-
143
- 'chart.labels.offsetx': 0,
144
- 'chart.labels.offsety': 0,
145
- 'chart.xlabels.offsetx': 0,
146
- 'chart.xlabels.offsety': 0,
147
- 'chart.xlabels': true,
148
- 'chart.xlabels.count': 5,
149
- 'chart.contextmenu': null,
150
- 'chart.key': null,
151
- 'chart.key.background': 'white',
152
- 'chart.key.position': 'graph',
153
- 'chart.key.halign': 'right',
154
- 'chart.key.shadow': false,
155
- 'chart.key.shadow.color': '#666',
156
- 'chart.key.shadow.blur': 3,
157
- 'chart.key.shadow.offsetx': 2,
158
- 'chart.key.shadow.offsety': 2,
159
- 'chart.key.position.gutter.boxed': false,
160
- 'chart.key.position.x': null,
161
- 'chart.key.position.y': null,
162
- 'chart.key.color.shape': 'square',
163
- 'chart.key.rounded': true,
164
- 'chart.key.linewidth': 1,
165
- 'chart.key.colors': null,
166
- 'chart.key.interactive': false,
167
- 'chart.key.interactive.highlight.chart.stroke': 'black',
168
- 'chart.key.interactive.highlight.chart.fill':'rgba(255,255,255,0.7)',
169
- 'chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)',
170
- 'chart.key.text.color': 'black',
171
- 'chart.units.pre': '',
172
- 'chart.units.post': '',
173
- 'chart.units.ingraph': false,
174
- 'chart.strokestyle': 'rgba(0,0,0,0)',
175
- 'chart.xmin': 0,
176
- 'chart.xmax': 0,
177
- 'chart.axis.color': 'black',
178
- 'chart.shadow': false,
179
- 'chart.shadow.color': '#666',
180
- 'chart.shadow.blur': 3,
181
- 'chart.shadow.offsetx': 3,
182
- 'chart.shadow.offsety': 3,
183
- 'chart.vmargin': 2,
184
- 'chart.vmargin.grouped': 2,
185
- 'chart.grouping': 'grouped',
186
- 'chart.tooltips': null,
187
- 'chart.tooltips.event': 'onclick',
188
- 'chart.tooltips.effect': 'fade',
189
- 'chart.tooltips.css.class': 'RGraph_tooltip',
190
- 'chart.tooltips.highlight': true,
191
- 'chart.highlight.fill': 'rgba(255,255,255,0.7)',
192
- 'chart.highlight.stroke': 'rgba(0,0,0,0)',
193
- 'chart.highlight.style': null,
194
- 'chart.annotatable': false,
195
- 'chart.annotate.color': 'black',
196
- 'chart.zoom.factor': 1.5,
197
- 'chart.zoom.fade.in': true,
198
- 'chart.zoom.fade.out': true,
199
- 'chart.zoom.hdir': 'right',
200
- 'chart.zoom.vdir': 'down',
201
- 'chart.zoom.frames': 25,
202
- 'chart.zoom.delay': 16.666,
203
- 'chart.zoom.shadow': true,
204
- 'chart.zoom.background': true,
205
- 'chart.zoom.action': 'zoom',
206
- 'chart.resizable': false,
207
- 'chart.resize.handle.adjust': [0,0],
208
- 'chart.resize.handle.background': null,
209
- 'chart.scale.point': '.',
210
- 'chart.scale.thousand': ',',
211
- 'chart.scale.decimals': null,
212
- 'chart.scale.zerostart': true,
213
- 'chart.noredraw': false,
214
- 'chart.events.click': null,
215
- 'chart.events.mousemove': null,
216
- 'chart.noxaxis': false,
217
- 'chart.noyaxis': false,
218
- 'chart.noaxes': false,
219
- 'chart.noxtickmarks': false,
220
- 'chart.noytickmarks': false,
221
- 'chart.numyticks': data.length,
222
- 'chart.numxticks': 10,
223
- 'chart.variant': 'hbar',
224
- 'chart.variant.threed.angle': 0.1,
225
- 'chart.variant.threed.offsetx': 10,
226
- 'chart.variant.threed.offsety': 5,
227
- 'chart.variant.threed.xaxis': true,
228
- 'chart.variant.threed.yaxis': true,
229
- 'chart.yaxispos': 'left',
230
- 'chart.variant': 'hbar',
231
- 'chart.clearto': 'rgba(0,0,0,0)',
232
- 'chart.adjustable': false,
233
- 'chart.adjustable.only': null
234
- }
235
-
236
- // Check for support
237
- if (!this.canvas) {
238
- alert('[HBAR] No canvas support');
239
- return;
240
- }
241
-
242
- // This loop is used to check for stacked or grouped charts and now
243
- // also to convert strings to numbers. And now also undefined values
244
- // (29/07/2016
245
- for (i=0,len=this.data.length; i<len; ++i) {
246
- if (typeof this.data[i] == 'object' && !RGraph.isNull(this.data[i])) {
247
-
248
- this.stackedOrGrouped = true;
249
-
250
- for (var j=0,len2=this.data[i].length; j<len2; ++j) {
251
- if (typeof this.data[i][j] === 'string') {
252
- this.data[i][j] = parseFloat(this.data[i][j]);
253
- }
254
- }
255
-
256
- } else if (typeof this.data[i] == 'string') {
257
- this.data[i] = parseFloat(this.data[i]) || 0;
258
-
259
- } else if (typeof this.data[i] === 'undefined') {
260
- this.data[i] = null;
261
- }
262
- }
263
-
264
-
265
- /**
266
- * Create the dollar objects so that functions can be added to them
267
- */
268
- var linear_data = RGraph.arrayLinearize(data);
269
- for (var i=0,len=linear_data.length; i<len; ++i) {
270
- this['$' + i] = {};
271
- }
272
-
273
-
274
-
275
- /**
276
- * Create the linear data array
277
- */
278
- this.data_arr = RGraph.arrayLinearize(this.data);
279
-
280
-
281
- /**
282
- * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
283
- * done already
284
- */
285
- if (!this.canvas.__rgraph_aa_translated__) {
286
- this.context.translate(0.5,0.5);
287
-
288
- this.canvas.__rgraph_aa_translated__ = true;
289
- }
290
-
291
-
292
-
293
-
294
- // Short variable names
295
- var RG = RGraph,
296
- ca = this.canvas,
297
- co = ca.getContext('2d'),
298
- prop = this.properties,
299
- pa2 = RG.path2,
300
- win = window,
301
- doc = document,
302
- ma = Math
303
-
304
-
305
-
306
- /**
307
- * "Decorate" the object with the generic effects if the effects library has been included
308
- */
309
- if (RG.Effects && typeof RG.Effects.decorate === 'function') {
310
- RG.Effects.decorate(this);
311
- }
312
-
313
-
314
-
315
-
316
- /**
317
- * A setter
318
- *
319
- * @param name string The name of the property to set
320
- * @param value mixed The value of the property
321
- */
322
- this.set =
323
- this.Set = function (name)
324
- {
325
- var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
326
-
327
- /**
328
- * the number of arguments is only one and it's an
329
- * object - parse it for configuration data and return.
330
- */
331
- if (arguments.length === 1 && typeof name === 'object') {
332
- RG.parseObjectStyleConfig(this, name);
333
- return this;
334
- }
335
-
336
-
337
-
338
-
339
- /**
340
- * This should be done first - prepend the propertyy name with "chart." if necessary
341
- */
342
- if (name.substr(0,6) != 'chart.') {
343
- name = 'chart.' + name;
344
- }
345
-
346
-
347
-
348
- // Convert uppercase letters to dot+lower case letter
349
- while(name.match(/([A-Z])/)) {
350
- name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
351
- }
352
-
353
- if (name == 'chart.labels.abovebar') {
354
- name = 'chart.labels.above';
355
- }
356
-
357
- prop[name] = value;
358
-
359
- return this;
360
- };
361
-
362
-
363
-
364
-
365
- /**
366
- * A getter
367
- *
368
- * @param name string The name of the property to get
369
- */
370
- this.get =
371
- this.Get = function (name)
372
- {
373
- /**
374
- * This should be done first - prepend the property name with "chart." if necessary
375
- */
376
- if (name.substr(0,6) != 'chart.') {
377
- name = 'chart.' + name;
378
- }
379
-
380
- // Convert uppercase letters to dot+lower case letter
381
- while(name.match(/([A-Z])/)) {
382
- name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
383
- }
384
-
385
-
386
- if (name == 'chart.labels.abovebar') {
387
- name = 'chart.labels.above';
388
- }
389
-
390
- return prop[name];
391
- };
392
-
393
-
394
-
395
-
396
- /**
397
- * The function you call to draw the bar chart
398
- */
399
- this.draw =
400
- this.Draw = function ()
401
- {
402
- /**
403
- * Fire the onbeforedraw event
404
- */
405
- RG.fireCustomEvent(this, 'onbeforedraw');
406
-
407
-
408
- //
409
- // Check that the bHBar isn't stacked with adjusting enabled
410
- //
411
- if (prop['chart.adjustable'] && prop['chart.grouping'] === 'stacked') {
412
- alert('[RGRAPH] The HBar does not support stacked charts with adjusting');
413
- }
414
-
415
- //
416
- // If the chart is 3d then angle it it
417
- //
418
-
419
- if (prop['chart.variant'] === '3d') {
420
-
421
- if (prop['chart.text.accessible']) {
422
- // Nada
423
- } else {
424
- co.setTransform(1,prop['chart.variant.threed.angle'],0,1,0.5,0.5);
425
- }
426
-
427
- // Enlarge the gutter if its 25
428
- if (prop['chart.gutter.bottom'] === 25) {
429
- this.set('gutterBottom', 80);
430
- }
431
- }
432
-
433
-
434
-
435
-
436
- /**
437
- * Parse the colors. This allows for simple gradient syntax
438
- */
439
- if (!this.colorsParsed) {
440
- this.parseColors();
441
-
442
- // Don't want to do this again
443
- this.colorsParsed = true;
444
- }
445
-
446
-
447
-
448
-
449
-
450
-
451
- /**
452
- * Accomodate autosizing the left gutter
453
- */
454
- if (prop['chart.gutter.left.autosize']) {
455
- var len = 0;
456
- var labels = prop['chart.labels'];
457
- var font = prop['chart.text.font'];
458
- var size = prop['chart.text.size'];
459
-
460
- for (var i=0; i<labels.length; i+=1) {
461
- var length = RG.measureText(labels[i], false, font, size)[0] || 0
462
- len = ma.max(len, length);
463
- }
464
-
465
- prop['chart.gutter.left'] = len + 10;
466
- }
467
-
468
-
469
-
470
-
471
-
472
-
473
-
474
-
475
-
476
-
477
-
478
-
479
-
480
- /**
481
- * This is new in May 2011 and facilitates indiviual gutter settings,
482
- * eg chart.gutter.left
483
- */
484
- this.gutterLeft = prop['chart.gutter.left'];
485
- this.gutterRight = prop['chart.gutter.right'];
486
- this.gutterTop = prop['chart.gutter.top'];
487
- this.gutterBottom = prop['chart.gutter.bottom'];
488
-
489
-
490
-
491
-
492
- /**
493
- * Stop the coords array from growing uncontrollably
494
- */
495
- this.coords = [];
496
- this.coords2 = [];
497
- this.coordsText = [];
498
- this.max = 0;
499
-
500
- /**
501
- * Check for chart.xmin in stacked charts
502
- */
503
- if (prop['chart.xmin'] > 0 && prop['chart.grouping'] == 'stacked') {
504
- alert('[HBAR] Using chart.xmin is not supported with stacked charts, resetting chart.xmin to zero');
505
- this.Set('chart.xmin', 0);
506
- }
507
-
508
- /**
509
- * Work out a few things. They need to be here because they depend on things you can change before you
510
- * call Draw() but after you instantiate the object
511
- */
512
- this.graphwidth = ca.width - this.gutterLeft - this.gutterRight;
513
- this.graphheight = ca.height - this.gutterTop - this.gutterBottom;
514
- this.halfgrapharea = this.grapharea / 2;
515
- this.halfTextHeight = prop['chart.text.size'] / 2;
516
- this.halfway = ma.round((this.graphwidth / 2) + this.gutterLeft)
517
-
518
-
519
-
520
-
521
-
522
-
523
-
524
-
525
-
526
-
527
- // Progressively Draw the chart
528
- RG.Background.draw(this);
529
-
530
- this.drawbars();
531
- this.drawAxes();
532
- this.drawLabels();
533
-
534
-
535
- // Draw the key if necessary
536
- if (prop['chart.key'] && prop['chart.key'].length) {
537
- RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
538
- }
539
-
540
-
541
-
542
- /**
543
- * Setup the context menu if required
544
- */
545
- if (prop['chart.contextmenu']) {
546
- RG.ShowContext(this);
547
- }
548
-
549
-
550
-
551
- /**
552
- * Draw "in graph" labels
553
- */
554
- RG.DrawInGraphLabels(this);
555
-
556
-
557
- /**
558
- * This function enables resizing
559
- */
560
- if (prop['chart.resizable']) {
561
- RG.AllowResizing(this);
562
- }
563
-
564
-
565
- /**
566
- * This installs the event listeners
567
- */
568
- RG.InstallEventListeners(this);
569
-
570
-
571
- /**
572
- * Fire the onfirstdraw event
573
- */
574
- if (this.firstDraw) {
575
- RG.fireCustomEvent(this, 'onfirstdraw');
576
- this.firstDraw = false;
577
- this.firstDrawFunc();
578
- }
579
-
580
-
581
-
582
- /**
583
- * Fire the RGraph ondraw event
584
- */
585
- RG.FireCustomEvent(this, 'ondraw');
586
-
587
- return this;
588
- };
589
-
590
-
591
-
592
- /**
593
- * Used in chaining. Runs a function there and then - not waiting for
594
- * the events to fire (eg the onbeforedraw event)
595
- *
596
- * @param function func The function to execute
597
- */
598
- this.exec = function (func)
599
- {
600
- func(this);
601
-
602
- return this;
603
- };
604
-
605
-
606
-
607
-
608
- /**
609
- * This draws the axes
610
- */
611
- this.drawAxes =
612
- this.DrawAxes = function ()
613
- {
614
- var halfway = this.halfway
615
-
616
-
617
-
618
-
619
-
620
-
621
- co.beginPath();
622
-
623
- co.lineWidth = prop['chart.axis.linewidth'] ? prop['chart.axis.linewidth'] + 0.001 : 1.001;
624
- co.strokeStyle = prop['chart.axis.color'];
625
-
626
-
627
-
628
-
629
- // Draw the Y axis
630
- if (prop['chart.noyaxis'] == false && prop['chart.noaxes'] == false) {
631
- if (prop['chart.yaxispos'] == 'center') {
632
- co.moveTo(halfway, this.gutterTop);
633
- co.lineTo(halfway, ca.height - this.gutterBottom);
634
-
635
- } else if (prop['chart.yaxispos'] == 'right') {
636
- co.moveTo(ca.width - this.gutterRight, this.gutterTop);
637
- co.lineTo(ca.width - this.gutterRight, ca.height - this.gutterBottom);
638
-
639
- } else {
640
- co.moveTo(this.gutterLeft, this.gutterTop);
641
- co.lineTo(this.gutterLeft, ca.height - this.gutterBottom);
642
- }
643
- }
644
-
645
- // Draw the X axis
646
- if (prop['chart.noxaxis'] == false && prop['chart.noaxes'] == false) {
647
- co.moveTo(this.gutterLeft +0.001, ca.height - this.gutterBottom + 0.001);
648
- co.lineTo(ca.width - this.gutterRight + 0.001, ca.height - this.gutterBottom + 0.001);
649
- }
650
-
651
- // Draw the Y tickmarks
652
- if ( prop['chart.noytickmarks'] == false
653
- && prop['chart.noyaxis'] == false
654
- && prop['chart.numyticks'] > 0
655
- && prop['chart.noaxes'] == false
656
- ) {
657
-
658
- var yTickGap = (ca.height - this.gutterTop - this.gutterBottom) / (prop['chart.numyticks'] > 0 ? prop['chart.numyticks'] : this.data.length);
659
-
660
- for (y=this.gutterTop; y<(ca.height - this.gutterBottom - 1); y+=yTickGap) {
661
- if (prop['chart.yaxispos'] == 'center') {
662
- co.moveTo(halfway + 3, ma.round(y));
663
- co.lineTo(halfway - 3, ma.round(y));
664
-
665
- } else if (prop['chart.yaxispos'] == 'right') {
666
- co.moveTo(ca.width - this.gutterRight, ma.round(y));
667
- co.lineTo(ca.width - this.gutterRight + 3, ma.round(y));
668
-
669
- } else {
670
- co.moveTo(this.gutterLeft, ma.round(y));
671
- co.lineTo( this.gutterLeft - 3, ma.round(y));
672
- }
673
- }
674
-
675
- // If the X axis isn't being shown draw the end tick
676
- if (prop['chart.noxaxis'] == true) {
677
- if (prop['chart.yaxispos'] == 'center') {
678
- co.moveTo(halfway + 3, ma.round(y));
679
- co.lineTo(halfway - 3, ma.round(y));
680
-
681
- } else if (prop['chart.yaxispos'] == 'right') {
682
- co.moveTo(ca.width - this.gutterRight, ma.round(y));
683
- co.lineTo(ca.width - this.gutterRight + 3, ma.round(y));
684
-
685
- } else {
686
- co.moveTo(this.gutterLeft, ma.round(y));
687
- co.lineTo( this.gutterLeft - 3, ma.round(y));
688
- }
689
- }
690
- }
691
-
692
-
693
- // Draw the X tickmarks
694
- if ( prop['chart.noxtickmarks'] == false
695
- && prop['chart.noxaxis'] == false
696
- && prop['chart.numxticks'] > 0
697
- && prop['chart.noaxes'] == false) {
698
-
699
- xTickGap = (ca.width - this.gutterLeft - this.gutterRight ) / prop['chart.numxticks'];
700
- yStart = ca.height - this.gutterBottom;
701
- yEnd = (ca.height - this.gutterBottom) + 3;
702
-
703
-
704
-
705
-
706
-
707
- var i = prop['chart.numxticks']
708
-
709
- while(i--) {
710
-
711
- var x = ca.width - this.gutterRight - (i * xTickGap);
712
-
713
- if (prop['chart.yaxispos'] === 'right') {
714
- x -= xTickGap;
715
- }
716
-
717
- co.moveTo(ma.round(x), yStart);
718
- co.lineTo(ma.round(x), yEnd);
719
- }
720
-
721
-
722
-
723
- if (prop['chart.yaxispos'] === 'center') {
724
- var i = 5; while (i--) {
725
- var x = this.gutterLeft + (xTickGap * i);
726
-
727
- co.moveTo(ma.round(x), yStart);
728
- co.lineTo(ma.round(x), yEnd);
729
-
730
- }
731
- }
732
-
733
-
734
-
735
-
736
-
737
- // If the Y axis isn't being shown draw the end tick
738
- if (prop['chart.noyaxis'] == true) {
739
- co.moveTo(this.gutterLeft, ma.round(yStart));
740
- co.lineTo( this.gutterLeft, ma.round(yEnd));
741
- }
742
- }
743
- co.stroke();
744
-
745
- /**
746
- * Reset the linewidth
747
- */
748
- co.lineWidth = 1;
749
- };
750
-
751
-
752
-
753
-
754
- /**
755
- * This draws the labels for the graph
756
- */
757
- this.drawLabels =
758
- this.DrawLabels = function ()
759
- {
760
- var units_pre = prop['chart.units.pre'],
761
- units_post = prop['chart.units.post'],
762
- text_size = prop['chart.text.size'],
763
- font = prop['chart.text.font'],
764
- offsetx = prop['chart.xlabels.offsetx'],
765
- offsety = prop['chart.xlabels.offsety']
766
-
767
-
768
-
769
- /**
770
- * Set the units to blank if they're to be used for ingraph labels only
771
- */
772
- if (prop['chart.units.ingraph']) {
773
- units_pre = '';
774
- units_post = '';
775
- }
776
-
777
-
778
- /**
779
- * Draw the X axis labels
780
- */
781
- if (prop['chart.xlabels']) {
782
-
783
- /**
784
- * Specific X labels
785
- */
786
- if (RG.isArray(prop['chart.xlabels.specific'])) {
787
-
788
- if (prop['chart.yaxispos'] == 'center') {
789
-
790
- var halfGraphWidth = this.graphwidth / 2;
791
- var labels = prop['chart.xlabels.specific'];
792
- var interval = (this.graphwidth / 2) / (labels.length - 1);
793
-
794
- co.fillStyle = prop['chart.text.color'];
795
-
796
- for (var i=0; i<labels.length; i+=1) {
797
- RG.text2(this, {
798
- 'font':font,
799
- 'size':text_size,
800
- 'x':this.gutterLeft + halfGraphWidth + (interval * i) + offsetx,
801
- 'y':ca.height - this.gutterBottom + offsetx,
802
- 'text':labels[i],
803
- 'valign':'top',
804
- 'halign':'center',
805
- 'tag': 'scale'
806
- });
807
- }
808
-
809
- for (var i=(labels.length - 1); i>0; i-=1) {
810
- RG.Text2(this, {
811
- 'font':font,
812
- 'size':text_size,
813
- 'x':this.gutterLeft + (interval * (labels.length - i - 1)) + offsetx,
814
- 'y':ca.height - this.gutterBottom + offsety,
815
- 'text':labels[i],
816
- 'valign':'top',
817
- 'halign':'center',
818
- 'tag': 'scale'
819
- });
820
- }
821
-
822
- } else if (prop['chart.yaxispos'] == 'right') {
823
-
824
- var labels = prop['chart.xlabels.specific'];
825
- var interval = this.graphwidth / (labels.length - 1);
826
-
827
- co.fillStyle = prop['chart.text.color'];
828
-
829
- for (var i=0; i<labels.length; i+=1) {
830
- RG.text2(this, {
831
- 'font': font,
832
- 'size': text_size,
833
- 'x': this.gutterLeft + (interval * i) + offsetx,
834
- 'y': ca.height - this.gutterBottom + offsety,
835
- 'text': labels[labels.length - i - 1],
836
- 'valign':'top',
837
- 'halign':'center',
838
- 'tag': 'scale'
839
- });
840
- }
841
-
842
- } else {
843
-
844
- var labels = prop['chart.xlabels.specific'];
845
- var interval = this.graphwidth / (labels.length - 1);
846
-
847
- co.fillStyle = prop['chart.text.color'];
848
-
849
- for (var i=0; i<labels.length; i+=1) {
850
- RG.text2(this, {
851
- font: font,
852
- size: text_size,
853
- x: this.gutterLeft + (interval * i) + offsetx,
854
- y: ca.height - this.gutterBottom + offsety,
855
- text: labels[i],
856
- valign:'top',
857
- halign:'center',
858
- tag: 'scale'
859
- });
860
- }
861
- }
862
-
863
- /**
864
- * Draw an X scale
865
- */
866
- } else {
867
-
868
- var gap = 7;
869
-
870
- co.beginPath();
871
- co.fillStyle = prop['chart.text.color'];
872
-
873
-
874
- if (prop['chart.yaxispos'] == 'center') {
875
-
876
- for (var i=0; i<this.scale2.labels.length; ++i) {
877
- RG.text2(this, {
878
- 'font':font,
879
- 'size':text_size,
880
- 'x':this.gutterLeft + (this.graphwidth / 2) - ((this.graphwidth / 2) * ((i+1)/this.scale2.labels.length)) + offsetx,
881
- 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
882
- 'text':'-' + this.scale2.labels[i],
883
- 'valign':'center',
884
- 'halign':'center',
885
- 'tag': 'scale'
886
- });
887
- }
888
-
889
- for (var i=0; i<this.scale2.labels.length; ++i) {
890
- RG.text2(this, {
891
- 'font':font,
892
- 'size':text_size,
893
- 'x':this.gutterLeft + ((this.graphwidth / 2) * ((i+1)/this.scale2.labels.length)) + (this.graphwidth / 2) + offsetx,
894
- 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
895
- 'text':this.scale2.labels[i],
896
- 'valign':'center',
897
- 'halign':'center',
898
- 'tag': 'scale'
899
- });
900
- }
901
-
902
- }else if (prop['chart.yaxispos'] == 'right') {
903
-
904
-
905
- for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
906
- RG.Text2(this, {
907
- 'font':font,
908
- 'size':text_size,
909
- 'x':this.gutterLeft + (i * (this.graphwidth / len)) + offsetx,
910
- 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
911
- 'text':'-' + this.scale2.labels[len - 1 - i],
912
- 'valign':'center',
913
- 'halign':'center',
914
- 'tag': 'scale'
915
- });
916
- }
917
-
918
-
919
- } else {
920
- for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
921
- RG.Text2(this, {
922
- 'font':font,
923
- 'size':text_size,
924
- 'x':this.gutterLeft + (this.graphwidth * ((i+1)/len)) + offsetx,
925
- 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
926
- 'text':this.scale2.labels[i],
927
- 'valign':'center',
928
- 'halign':'center',
929
- 'tag': 'scale'
930
- });
931
- }
932
- }
933
-
934
- /**
935
- * If xmin is not zero - draw that
936
- */
937
- if (prop['chart.xmin'] > 0 || prop['chart.noyaxis'] == true || prop['chart.scale.zerostart'] || prop['chart.noaxes']) {
938
-
939
- var x = prop['chart.yaxispos'] == 'center' ? this.gutterLeft + (this.graphwidth / 2): this.gutterLeft;
940
-
941
- /**
942
- * Y axis on the right
943
- */
944
- if (prop['chart.yaxispos'] === 'right') {
945
- var x = ca.width - this.gutterRight;
946
- }
947
-
948
- RG.text2(this, {
949
- 'font':font,
950
- 'size':text_size,
951
- 'x':x + offsetx,
952
- 'y':this.gutterTop + this.halfTextHeight + this.graphheight + gap + offsety,
953
- 'text':RG.numberFormat(this, prop['chart.xmin'].toFixed(prop['chart.xmin'] === 0 ? 0 : prop['chart.scale.decimals']), units_pre, units_post),
954
- 'valign':'center',
955
- 'halign':'center',
956
- 'tag': 'scale'
957
- });
958
- }
959
-
960
- co.fill();
961
- co.stroke();
962
- }
963
- }
964
-
965
-
966
-
967
-
968
-
969
-
970
-
971
- /**
972
- * The Y axis labels
973
- */
974
- if (typeof prop['chart.labels'] == 'object') {
975
-
976
- var xOffset = prop['chart.variant'] === '3d' && prop['chart.yaxispos'] === 'right' ? 15 : 5,
977
- font = prop['chart.text.font'],
978
- color = prop['chart.labels.color'] || prop['chart.text.color'],
979
- bold = prop['chart.labels.bold'],
980
- offsetx = prop['chart.labels.offsetx'],
981
- offsety = prop['chart.labels.offsety']
982
-
983
-
984
- // Draw the X axis labels
985
- co.fillStyle = color;
986
-
987
- // How high is each bar
988
- var barHeight = (ca.height - this.gutterTop - this.gutterBottom ) / prop['chart.labels'].length;
989
-
990
- // Reset the yTickGap
991
- yTickGap = (ca.height - this.gutterTop - this.gutterBottom) / prop['chart.labels'].length
992
-
993
- /**
994
- * If the Y axis is on the right set the alignment and the X position, otherwise on the left
995
- */
996
- if (prop['chart.yaxispos'] === 'right') {
997
- var x = ca.width - this.gutterRight + xOffset;
998
- var halign = 'left'
999
- } else {
1000
- var x = this.gutterLeft - xOffset;
1001
- var halign = 'right'
1002
- }
1003
-
1004
- // Draw the X tickmarks
1005
- var i=0;
1006
- for (y=this.gutterTop + (yTickGap / 2); y<=ca.height - this.gutterBottom; y+=yTickGap) {
1007
-
1008
- RG.text2(this, {
1009
- 'font': font,
1010
- 'size': prop['chart.text.size'],
1011
- 'bold': bold,
1012
- 'x': x + offsetx,
1013
- 'y': y + offsety,
1014
- 'text': String(prop['chart.labels'][i++]),
1015
- 'halign': halign,
1016
- 'valign': 'center',
1017
- 'tag': 'labels'
1018
- });
1019
- }
1020
- }
1021
- };
1022
-
1023
-
1024
-
1025
-
1026
- /**
1027
- * This function draws the bars. It also draw 3D axes as the axes drawing bit
1028
- * is don AFTER the bars are drawn
1029
- */
1030
- this.drawbars =
1031
- this.Drawbars = function ()
1032
- {
1033
- co.lineWidth = prop['chart.linewidth'];
1034
- co.strokeStyle = prop['chart.strokestyle'];
1035
- co.fillStyle = prop['chart.colors'][0];
1036
-
1037
- var prevX = 0,
1038
- prevY = 0;
1039
-
1040
-
1041
- /**
1042
- * Work out the max value
1043
- */
1044
- if (prop['chart.xmax']) {
1045
-
1046
- this.scale2 = RG.getScale2(this, {
1047
- 'max':prop['chart.xmax'],
1048
- 'min':prop['chart.xmin'],
1049
- 'scale.decimals':Number(prop['chart.scale.decimals']),
1050
- 'scale.point':prop['chart.scale.point'],
1051
- 'scale.thousand':prop['chart.scale.thousand'],
1052
- 'scale.round':prop['chart.scale.round'],
1053
- 'units.pre':prop['chart.units.pre'],
1054
- 'units.post':prop['chart.units.post'],
1055
- 'ylabels.count':prop['chart.xlabels.count'],
1056
- 'strict':true
1057
- });
1058
-
1059
- this.max = this.scale2.max;
1060
-
1061
- } else {
1062
-
1063
- var grouping = prop['chart.grouping'];
1064
-
1065
- for (i=0; i<this.data.length; ++i) {
1066
- if (typeof(this.data[i]) == 'object') {
1067
- var value = grouping == 'grouped' ? Number(RG.array_max(this.data[i], true)) : Number(RG.array_sum(this.data[i])) ;
1068
- } else {
1069
- var value = Number(ma.abs(this.data[i]));
1070
- }
1071
-
1072
- this.max = ma.max(Math.abs(this.max), Math.abs(value));
1073
- }
1074
-
1075
- this.scale2 = RG.getScale2(this, {
1076
- 'max':this.max,
1077
- 'min':prop['chart.xmin'],
1078
- 'scale.decimals':Number(prop['chart.scale.decimals']),
1079
- 'scale.point':prop['chart.scale.point'],
1080
- 'scale.thousand':prop['chart.scale.thousand'],
1081
- 'scale.round':prop['chart.scale.round'],
1082
- 'units.pre':prop['chart.units.pre'],
1083
- 'units.post':prop['chart.units.post'],
1084
- 'ylabels.count':prop['chart.xlabels.count']
1085
- });
1086
-
1087
-
1088
- this.max = this.scale2.max;
1089
- this.min = this.scale2.min;
1090
- }
1091
-
1092
- if (prop['chart.scale.decimals'] == null && Number(this.max) == 1) {
1093
- this.Set('chart.scale.decimals', 1);
1094
- }
1095
-
1096
- /**
1097
- * This is here to facilitate sequential colors
1098
- */
1099
- var colorIdx = 0;
1100
-
1101
- //
1102
- // For grouped bars we need to calculate the number of bars
1103
- //
1104
- this.numbars = RG.arrayLinearize(this.data).length;
1105
-
1106
-
1107
-
1108
-
1109
- /**
1110
- * if the chart is adjustable fix the scale so that it doesn't change.
1111
- *
1112
- * It's here (after the scale generation) so that the max value can be
1113
- * set to the maximum scale value)
1114
- */
1115
- if (prop['chart.adjustable'] && !prop['chart.xmax']) {
1116
- this.set('chart.xmax', this.scale2.max);
1117
- }
1118
-
1119
-
1120
-
1121
- // Draw the 3d axes if necessary
1122
- if (prop['chart.variant'] === '3d') {
1123
- RG.draw3DAxes(this);
1124
- }
1125
-
1126
-
1127
-
1128
-
1129
-
1130
-
1131
- /**
1132
- * The bars are drawn HERE
1133
- */
1134
- var graphwidth = (ca.width - this.gutterLeft - this.gutterRight);
1135
- var halfwidth = graphwidth / 2;
1136
-
1137
- for (i=(len=this.data.length-1); i>=0; --i) {
1138
-
1139
- // Work out the width and height
1140
- var width = ma.abs((this.data[i] / this.max) * graphwidth);
1141
- var height = this.graphheight / this.data.length;
1142
-
1143
- var orig_height = height;
1144
-
1145
- var x = this.gutterLeft;
1146
- var y = this.gutterTop + (i * height);
1147
- var vmargin = prop['chart.vmargin'];
1148
-
1149
- // Account for the Y axis being on the right hand side
1150
- if (prop['chart.yaxispos'] === 'right') {
1151
- x = ca.width - this.gutterRight - ma.abs(width);
1152
- }
1153
-
1154
- // Account for negative lengths - Some browsers (eg Chrome) don't like a negative value
1155
- if (width < 0) {
1156
- x -= width;
1157
- width = ma.abs(width);
1158
- }
1159
-
1160
- /**
1161
- * Turn on the shadow if need be
1162
- */
1163
- if (prop['chart.shadow']) {
1164
- co.shadowColor = prop['chart.shadow.color'];
1165
- co.shadowBlur = prop['chart.shadow.blur'];
1166
- co.shadowOffsetX = prop['chart.shadow.offsetx'];
1167
- co.shadowOffsetY = prop['chart.shadow.offsety'];
1168
- }
1169
-
1170
- /**
1171
- * Draw the bar
1172
- */
1173
- co.beginPath();
1174
-
1175
- // Standard (non-grouped and non-stacked) bars here
1176
- if (typeof this.data[i] == 'number' || RG.isNull(this.data[i])) {
1177
-
1178
- var barHeight = height - (2 * vmargin),
1179
- barWidth = ((this.data[i] - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * this.graphwidth,
1180
- barX = this.gutterLeft;
1181
-
1182
- // Account for Y axis pos
1183
- if (prop['chart.yaxispos'] == 'center') {
1184
- barWidth /= 2;
1185
- barX += halfwidth;
1186
-
1187
- if (this.data[i] < 0) {
1188
- barWidth = (ma.abs(this.data[i]) - prop['chart.xmin']) / (this.max - prop['chart.xmin']);
1189
- barWidth = barWidth * (this.graphwidth / 2);
1190
- barX = ((this.graphwidth / 2) + this.gutterLeft) - barWidth;
1191
- }
1192
-
1193
- } else if (prop['chart.yaxispos'] == 'right') {
1194
-
1195
- barWidth = ma.abs(barWidth);
1196
- barX = ca.width - this.gutterRight - barWidth;
1197
-
1198
- }
1199
-
1200
- // Set the fill color
1201
- co.strokeStyle = prop['chart.strokestyle'];
1202
- co.fillStyle = prop['chart.colors'][0];
1203
-
1204
- // Sequential colors
1205
- ++colorIdx;
1206
- if (prop['chart.colors.sequential'] && typeof colorIdx === 'number') {
1207
- if (prop['chart.colors'][this.numbars - colorIdx]) {
1208
- co.fillStyle = prop['chart.colors'][this.numbars - colorIdx];
1209
- } else {
1210
- co.fillStyle = prop['chart.colors'][prop['chart.colors'].length - 1];
1211
- }
1212
- }
1213
-
1214
-
1215
-
1216
-
1217
-
1218
-
1219
-
1220
-
1221
-
1222
-
1223
-
1224
-
1225
-
1226
-
1227
-
1228
-
1229
- co.strokeRect(barX, this.gutterTop + (i * height) + prop['chart.vmargin'], barWidth, barHeight);
1230
- co.fillRect(barX, this.gutterTop + (i * height) + prop['chart.vmargin'], barWidth, barHeight);
1231
-
1232
-
1233
-
1234
-
1235
-
1236
-
1237
-
1238
-
1239
-
1240
-
1241
-
1242
-
1243
-
1244
-
1245
-
1246
-
1247
-
1248
-
1249
-
1250
-
1251
-
1252
-
1253
-
1254
-
1255
- this.coords.push([
1256
- barX,
1257
- y + vmargin,
1258
- barWidth,
1259
- height - (2 * vmargin),
1260
- co.fillStyle,
1261
- this.data[i],
1262
- true
1263
- ]);
1264
-
1265
-
1266
-
1267
-
1268
-
1269
-
1270
- // Draw the 3D effect using the coords that have just been stored
1271
- if (prop['chart.variant'] === '3d' && typeof this.data[i] == 'number') {
1272
-
1273
-
1274
- var prevStrokeStyle = co.strokeStyle,
1275
- prevFillStyle = co.fillStyle;
1276
-
1277
- /**
1278
- * Turn off the shadow for the 3D bits
1279
- */
1280
- RG.noShadow(this);
1281
-
1282
- // DRAW THE 3D BITS HERE
1283
- var barX = barX,
1284
- barY = y + vmargin,
1285
- barW = barWidth,
1286
- barH = height - (2 * vmargin),
1287
- offsetX = prop['chart.variant.threed.offsetx'],
1288
- offsetY = prop['chart.variant.threed.offsety'],
1289
- value = this.data[i];
1290
-
1291
-
1292
- pa2(
1293
- co,
1294
- [
1295
- 'b',
1296
- 'm', barX, barY,
1297
- 'l', barX + offsetX - (prop['chart.yaxispos'] == 'left' && value < 0 ? offsetX : 0), barY - offsetY,
1298
- 'l', barX + barW + offsetX - (prop['chart.yaxispos'] == 'center' && value < 0 ? offsetX : 0), barY - offsetY,
1299
- 'l', barX + barW, barY,
1300
- 'c',
1301
- 's', co.strokeStyle,
1302
- 'f', co.fillStyle,
1303
- 'f','rgba(255,255,255,0.6)'//Fill again to lighten it
1304
- ]
1305
- );
1306
-
1307
- if ( prop['chart.yaxispos'] !== 'right'
1308
- && !(prop['chart.yaxispos'] === 'center' && value < 0)
1309
- && value >= 0
1310
- && !RG.isNull(value)
1311
- ) {
1312
-
1313
- pa2(
1314
- co,
1315
- [
1316
- 'b',
1317
- 'fs', prevFillStyle,
1318
- 'm', barX + barW, barY,
1319
- 'l', barX + barW + offsetX, barY - offsetY,
1320
- 'l', barX + barW + offsetX, barY - offsetY + barH,
1321
- 'l', barX + barW, barY + barH,
1322
- 'c',
1323
- 's', co.strokeStyle,
1324
- 'f', prevFillStyle,
1325
- 'f', 'rgba(0,0,0,0.25)'
1326
- ]
1327
- );
1328
- }
1329
-
1330
- }
1331
-
1332
-
1333
-
1334
-
1335
-
1336
-
1337
- /**
1338
- * Stacked bar chart
1339
- */
1340
- } else if (typeof(this.data[i]) == 'object' && prop['chart.grouping'] == 'stacked') {
1341
-
1342
- if (prop['chart.yaxispos'] == 'center') {
1343
- alert('[HBAR] You can\'t have a stacked chart with the Y axis in the center, change it to grouped');
1344
- } else if (prop['chart.yaxispos'] == 'right') {
1345
- var x = ca.width - this.gutterRight
1346
- }
1347
-
1348
- var barHeight = height - (2 * vmargin);
1349
-
1350
- if (typeof this.coords2[i] == 'undefined') {
1351
- this.coords2[i] = [];
1352
- }
1353
-
1354
- for (j=0; j<this.data[i].length; ++j) {
1355
-
1356
- // The previous 3D segments would have turned the shadow off - so turn it back on
1357
- if (prop['chart.shadow'] && prop['chart.variant'] === '3d') {
1358
- co.shadowColor = prop['chart.shadow.color'];
1359
- co.shadowBlur = prop['chart.shadow.blur'];
1360
- co.shadowOffsetX = prop['chart.shadow.offsetx'];
1361
- co.shadowOffsetY = prop['chart.shadow.offsety'];
1362
- }
1363
-
1364
- //
1365
- // Ensure the number is positive
1366
- //(even though having the X axis on the right implies a
1367
- //negative value)
1368
- //
1369
- if (!RG.isNull(this.data[i][j])) this.data[i][j] = ma.abs(this.data[i][j]);
1370
-
1371
-
1372
- var last = (j === (this.data[i].length - 1) );
1373
-
1374
- // Set the fill/stroke colors
1375
- co.strokeStyle = prop['chart.strokestyle'];
1376
-
1377
- // Sequential colors
1378
- ++colorIdx;
1379
- if (prop['chart.colors.sequential'] && typeof colorIdx === 'number') {
1380
- if (prop['chart.colors'][this.numbars - colorIdx]) {
1381
- co.fillStyle = prop['chart.colors'][this.numbars - colorIdx];
1382
- } else {
1383
- co.fillStyle = prop['chart.colors'][prop['chart.colors'].length - 1];
1384
- }
1385
- } else if (prop['chart.colors'][j]) {
1386
- co.fillStyle = prop['chart.colors'][j];
1387
- }
1388
-
1389
-
1390
- var width = (((this.data[i][j]) / (this.max))) * this.graphwidth;
1391
- var totalWidth = (RG.arraySum(this.data[i]) / this.max) * this.graphwidth;
1392
-
1393
- if (prop['chart.yaxispos'] === 'right') {
1394
- x -= width;
1395
- }
1396
-
1397
-
1398
-
1399
- co.strokeRect(x, this.gutterTop + prop['chart.vmargin'] + (this.graphheight / this.data.length) * i, width, height - (2 * vmargin) );
1400
- co.fillRect(x, this.gutterTop + prop['chart.vmargin'] + (this.graphheight / this.data.length) * i, width, height - (2 * vmargin) );
1401
-
1402
-
1403
- /**
1404
- * Store the coords for tooltips
1405
- */
1406
-
1407
- // The last property of this array is a boolean which tells you whether the value is the last or not
1408
- this.coords.push([
1409
- x,
1410
- y + vmargin,
1411
- width,
1412
- height - (2 * vmargin),
1413
- co.fillStyle,
1414
- RG.array_sum(this.data[i]),
1415
- j == (this.data[i].length - 1)
1416
- ]);
1417
-
1418
- this.coords2[i].push([
1419
- x,
1420
- y + vmargin,
1421
- width,
1422
- height - (2 * vmargin),
1423
- co.fillStyle,
1424
- RG.array_sum(this.data[i]),
1425
- j == (this.data[i].length - 1)
1426
- ]);
1427
-
1428
-
1429
-
1430
-
1431
-
1432
-
1433
- // 3D effect
1434
- if (prop['chart.variant'] === '3d') {
1435
-
1436
- /**
1437
- * Turn off the shadow for the 3D bits
1438
- */
1439
- RG.noShadow(this);
1440
-
1441
- var prevStrokeStyle = co.strokeStyle,
1442
- prevFillStyle = co.fillStyle;
1443
-
1444
- // DRAW THE 3D BITS HERE
1445
- var barX = x,
1446
- barY = y + vmargin,
1447
- barW = width,
1448
- barH = height - (2 * vmargin),
1449
- offsetX = prop['chart.variant.threed.offsetx'],
1450
- offsetY = prop['chart.variant.threed.offsety'],
1451
- value = this.data[i][j];
1452
-
1453
- if (!RG.isNull(value)) {
1454
- pa2(
1455
- co,
1456
- [
1457
- 'b',
1458
- 'm', barX, barY,
1459
- 'l', barX + offsetX, barY - offsetY,
1460
- 'l', barX + barW + offsetX, barY - offsetY,
1461
- 'l', barX + barW, barY,
1462
- 'c',
1463
- 's', co.strokeStyle,
1464
- 'f', co.fillStyle,
1465
- 'f','rgba(255,255,255,0.6)'//Fill again to lighten it
1466
- ]
1467
- );
1468
- }
1469
-
1470
- if ( prop['chart.yaxispos'] !== 'right'
1471
- && !(prop['chart.yaxispos'] === 'center' && value < 0)
1472
- && !RG.isNull(value)
1473
- ) {
1474
-
1475
- pa2(
1476
- co,
1477
- [
1478
- 'fs', prevFillStyle,
1479
- 'b',
1480
- 'm', barX + barW, barY,
1481
- 'l', barX + barW + offsetX, barY - offsetY,
1482
- 'l', barX + barW + offsetX, barY - offsetY + barH,
1483
- 'l', barX + barW, barY + barH,
1484
- 'c',
1485
- 's', co.strokeStyle,
1486
- 'f', prevFillStyle,
1487
- 'f', 'rgba(0,0,0,0.25)'
1488
- ]
1489
- );
1490
- }
1491
-
1492
- co.beginPath();
1493
- co.strokeStyle = prevStrokeStyle;
1494
- co.fillStyle = prevFillStyle;
1495
- }
1496
-
1497
-
1498
-
1499
-
1500
-
1501
-
1502
- if (prop['chart.yaxispos'] !== 'right') {
1503
- x += width;
1504
- }
1505
- }
1506
-
1507
-
1508
-
1509
-
1510
-
1511
-
1512
-
1513
-
1514
- /**
1515
- * A grouped bar chart
1516
- */
1517
- } else if (typeof(this.data[i]) == 'object' && prop['chart.grouping'] == 'grouped') {
1518
-
1519
- var vmarginGrouped = prop['chart.vmargin.grouped'];
1520
- var individualBarHeight = ((height - (2 * vmargin) - ((this.data[i].length - 1) * vmarginGrouped)) / this.data[i].length)
1521
-
1522
- if (typeof this.coords2[i] == 'undefined') {
1523
- this.coords2[i] = [];
1524
- }
1525
-
1526
- for (j=(this.data[i].length - 1); j>=0; --j) {
1527
-
1528
- /**
1529
- * Turn on the shadow if need be
1530
- */
1531
- if (prop['chart.shadow']) {
1532
- RG.setShadow(this, prop['chart.shadow.color'], prop['chart.shadow.offsetx'], prop['chart.shadow.offsety'], prop['chart.shadow.blur']);
1533
- }
1534
-
1535
- // Set the fill/stroke colors
1536
- co.strokeStyle = prop['chart.strokestyle'];
1537
-
1538
- // Sequential colors
1539
- ++colorIdx;
1540
- if (prop['chart.colors.sequential'] && typeof colorIdx === 'number') {
1541
- if (prop['chart.colors'][this.numbars - colorIdx]) {
1542
- co.fillStyle = prop['chart.colors'][this.numbars - colorIdx];
1543
- } else {
1544
- co.fillStyle = prop['chart.colors'][prop['chart.colors'].length - 1];
1545
- }
1546
- } else if (prop['chart.colors'][j]) {
1547
- co.fillStyle = prop['chart.colors'][j];
1548
- }
1549
-
1550
-
1551
-
1552
- var startY = this.gutterTop + (height * i) + (individualBarHeight * j) + vmargin + (vmarginGrouped * j);
1553
- var width = ((this.data[i][j] - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * (ca.width - this.gutterLeft - this.gutterRight );
1554
- var startX = this.gutterLeft;
1555
-
1556
-
1557
-
1558
- // Account for the Y axis being in the middle
1559
- if (prop['chart.yaxispos'] == 'center') {
1560
- width /= 2;
1561
- startX += halfwidth;
1562
-
1563
- // Account for the Y axis being on the right
1564
- } else if (prop['chart.yaxispos'] == 'right') {
1565
- width = ma.abs(width);
1566
- startX = ca.width - this.gutterRight - ma.abs(width);;
1567
- }
1568
-
1569
- if (width < 0) {
1570
- startX += width;
1571
- width *= -1;
1572
- }
1573
-
1574
- co.strokeRect(startX, startY, width, individualBarHeight);
1575
- co.fillRect(startX, startY, width, individualBarHeight);
1576
-
1577
-
1578
-
1579
-
1580
-
1581
-
1582
- this.coords.push([
1583
- startX,
1584
- startY,
1585
- width,
1586
- individualBarHeight,
1587
- co.fillStyle,
1588
- this.data[i][j],
1589
- true
1590
- ]);
1591
-
1592
- this.coords2[i].push([
1593
- startX,
1594
- startY,
1595
- width,
1596
- individualBarHeight,
1597
- co.fillStyle,
1598
- this.data[i][j],
1599
- true
1600
- ]);
1601
-
1602
-
1603
-
1604
-
1605
-
1606
-
1607
-
1608
-
1609
-
1610
-
1611
-
1612
-
1613
- // 3D effect
1614
- if (prop['chart.variant'] === '3d') {
1615
-
1616
- /**
1617
- * Turn off the shadow for the 3D bits
1618
- */
1619
- RG.noShadow(this);
1620
-
1621
- var prevStrokeStyle = co.strokeStyle,
1622
- prevFillStyle = co.fillStyle;
1623
-
1624
- // DRAW THE 3D BITS HERE
1625
- var barX = startX,
1626
- barY = startY,
1627
- barW = width,
1628
- barH = individualBarHeight,
1629
- offsetX = prop['chart.variant.threed.offsetx'],
1630
- offsetY = prop['chart.variant.threed.offsety'],
1631
- value = this.data[i][j];
1632
-
1633
- pa2(
1634
- co,
1635
- [
1636
- 'b',
1637
- 'm', barX, barY,
1638
- 'l', barX + offsetX, barY - offsetY,
1639
- 'l', barX + barW + offsetX - (value < 0 ? offsetX : 0), barY - offsetY,
1640
- 'l', barX + barW, barY,
1641
- 'c',
1642
- 's', co.strokeStyle,
1643
- 'f', co.fillStyle,
1644
- 'f','rgba(255,255,255,0.6)'//Fill again to lighten it
1645
- ]
1646
- );
1647
-
1648
- if ( prop['chart.yaxispos'] !== 'right'
1649
- && !(prop['chart.yaxispos'] === 'center' && value < 0)
1650
- && value >= 0
1651
- && !RG.isNull(value)
1652
- ) {
1653
-
1654
- pa2(
1655
- co,
1656
- [
1657
- 'fs', prevFillStyle,
1658
- 'b',
1659
- 'm', barX + barW, barY,
1660
- 'l', barX + barW + offsetX, barY - offsetY,
1661
- 'l', barX + barW + offsetX, barY - offsetY + barH,
1662
- 'l', barX + barW, barY + barH,
1663
- 'c',
1664
- 's', co.strokeStyle,
1665
- 'f', prevFillStyle,
1666
- 'f', 'rgba(0,0,0,0.25)'
1667
- ]
1668
- );
1669
- }
1670
-
1671
-
1672
-
1673
-
1674
-
1675
- co.beginPath();
1676
- co.strokeStyle = prevStrokeStyle;
1677
- co.fillStyle = prevFillStyle;
1678
- }
1679
-
1680
-
1681
-
1682
-
1683
-
1684
-
1685
- }
1686
-
1687
- startY += vmargin;
1688
- }
1689
-
1690
- co.closePath();
1691
- }
1692
-
1693
- co.stroke();
1694
- co.fill();
1695
-
1696
- // Under certain circumstances we can cover the shadow
1697
- // overspill with a white rectangle
1698
- if (prop['chart,yaxispos'] === 'right') {
1699
- pa2(co, 'cr % % % %',
1700
- ca.width - this.gutterRight + prop['chart.variant.threed.offsetx'],
1701
- '0',
1702
- this.gutterRight,
1703
- ca.height
1704
- );
1705
- }
1706
-
1707
-
1708
-
1709
-
1710
-
1711
-
1712
- // Draw the 3d axes AGAIN if the Y axis is on the right
1713
- if ( prop['chart.yaxispos'] === 'right'
1714
- && prop['chart.variant'] === '3d'
1715
- ) {
1716
- RG.draw3DYAxis(this);
1717
- }
1718
-
1719
- /**
1720
- * Now the bars are stroke()ed, turn off the shadow
1721
- */
1722
- RG.noShadow(this);
1723
-
1724
-
1725
- //
1726
- // Reverse the coords arrays as the bars are drawn from the borrom up now
1727
- //
1728
- this.coords = RG.arrayReverse(this.coords);
1729
-
1730
- if (prop['chart.grouping'] === 'grouped') {
1731
- for (var i=0; i<this.coords2.length; ++i) {
1732
- this.coords2[i] = RG.arrayReverse(this.coords2[i]);
1733
- }
1734
- }
1735
-
1736
-
1737
- this.redrawBars();
1738
- };
1739
-
1740
-
1741
-
1742
-
1743
- /**
1744
- * This function goes over the bars after they been drawn, so that upwards shadows are underneath the bars
1745
- */
1746
- this.redrawBars =
1747
- this.RedrawBars = function ()
1748
- {
1749
- if (prop['chart.noredraw']) {
1750
- return;
1751
- }
1752
-
1753
- var coords = this.coords;
1754
-
1755
- var font = prop['chart.text.font'],
1756
- size = prop['chart.text.size'],
1757
- color = prop['chart.text.color'];
1758
-
1759
- RG.noShadow(this);
1760
- co.strokeStyle = prop['chart.strokestyle'];
1761
-
1762
- for (var i=0; i<coords.length; ++i) {
1763
-
1764
- if (prop['chart.shadow']) {
1765
-
1766
- pa2(co, 'b lw % r % % % % s % f %',
1767
- prop['chart.linewidth'],
1768
- coords[i][0],
1769
- coords[i][1],
1770
- coords[i][2],
1771
- coords[i][3],
1772
- prop['chart.strokestyle'],
1773
- coords[i][4]
1774
- );
1775
- }
1776
-
1777
- /**
1778
- * Draw labels "above" the bar
1779
- */
1780
- var halign = 'left';
1781
- if (prop['chart.labels.above'] && coords[i][6]) {
1782
-
1783
- var border = (coords[i][0] + coords[i][2] + 7 + co.measureText(prop['chart.labels.above.units.pre'] + this.coords[i][5] + prop['chart.labels.above.units.post']).width) > ca.width ? true : false,
1784
- text = RG.numberFormat(this, (this.coords[i][5]).toFixed(prop['chart.labels.above.decimals']), prop['chart.labels.above.units.pre'], prop['chart.labels.above.units.post']);
1785
-
1786
- RG.noShadow(this);
1787
-
1788
- /**
1789
- * Default to the value - then check for specific labels
1790
- */
1791
-
1792
-
1793
- if (typeof prop['chart.labels.above.specific'] === 'object' && prop['chart.labels.above.specific'] && prop['chart.labels.above.specific'][i]) {
1794
- text = prop['chart.labels.above.specific'][i];
1795
- }
1796
-
1797
- var x = coords[i][0] + coords[i][2] + 5;
1798
- var y = coords[i][1] + (coords[i][3] / 2);
1799
-
1800
- if (prop['chart.yaxispos'] === 'right') {
1801
- x = coords[i][0] - 5;
1802
- halign = 'right';
1803
- } else if (prop['chart.yaxispos'] === 'center' && this.data_arr[i] < 0) {
1804
- x = coords[i][0] - 5;
1805
- halign = 'right';
1806
- }
1807
-
1808
- RG.text2(this, {
1809
- font: typeof prop['chart.labels.above.font'] === 'string' ? prop['chart.labels.above.font'] : font,
1810
- size: typeof prop['chart.labels.above.size'] === 'number' ? prop['chart.labels.above.size'] : size,
1811
- color: typeof prop['chart.labels.above.color'] ==='string' ? prop['chart.labels.above.color'] : color,
1812
- x: x,
1813
- y: y,
1814
- bold: prop['chart.labels.above.bold'],
1815
- italic: prop['chart.labels.above.italic'],
1816
- text: text,
1817
- valign: 'center',
1818
- halign: halign,
1819
- tag: 'labels.above'
1820
- });
1821
- }
1822
- }
1823
- };
1824
-
1825
-
1826
-
1827
-
1828
- /**
1829
- * This function can be used to get the appropriate bar information (if any)
1830
- *
1831
- * @param e Event object
1832
- * @return Appriate bar information (if any)
1833
- */
1834
- this.getShape =
1835
- this.getBar = function (e)
1836
- {
1837
- var mouseXY = RG.getMouseXY(e);
1838
-
1839
- /**
1840
- * Loop through the bars determining if the mouse is over a bar
1841
- */
1842
- for (var i=0,len=this.coords.length; i<len; i++) {
1843
-
1844
- var mouseX = mouseXY[0], // In relation to the canvas
1845
- mouseY = mouseXY[1], // In relation to the canvas
1846
- left = this.coords[i][0],
1847
- top = this.coords[i][1],
1848
- width = this.coords[i][2],
1849
- height = this.coords[i][3],
1850
- idx = i;
1851
-
1852
-
1853
-
1854
- // Recreate the path/rectangle so that it can be tested
1855
- // ** DO NOT STROKE OR FILL IT **
1856
- pa2(co,['b','r',left,top,width,height]);
1857
-
1858
- if (co.isPointInPath(mouseX, mouseY)) {
1859
-
1860
- var tooltip = RG.parseTooltipText(prop['chart.tooltips'], i);
1861
-
1862
- return {
1863
- 0: this, 'object': this,
1864
- 1: left, 'x': left,
1865
- 2: top, 'y': top,
1866
- 3: width, 'width': width,
1867
- 4: height, 'height': height,
1868
- 5: idx, 'index': idx,
1869
- 'tooltip': tooltip
1870
- };
1871
- }
1872
- }
1873
- };
1874
-
1875
-
1876
-
1877
-
1878
- /**
1879
- * When you click on the chart, this method can return the X value at that point. It works for any point on the
1880
- * chart (that is inside the gutters) - not just points within the Bars.
1881
- *
1882
- * @param object e The event object
1883
- */
1884
- this.getValue = function (arg)
1885
- {
1886
- if (arg.length == 2) {
1887
- var mouseX = arg[0];
1888
- var mouseY = arg[1];
1889
- } else {
1890
- var mouseCoords = RG.getMouseXY(arg);
1891
- var mouseX = mouseCoords[0];
1892
- var mouseY = mouseCoords[1];
1893
- }
1894
-
1895
- if ( mouseY < this.gutterTop
1896
- || mouseY > (ca.height - this.gutterBottom)
1897
- || mouseX < this.gutterLeft
1898
- || mouseX > (ca.width - this.gutterRight)
1899
- ) {
1900
- return null;
1901
- }
1902
-
1903
-
1904
-
1905
-
1906
-
1907
- if (prop['chart.yaxispos'] == 'center') {
1908
- var value = ((mouseX - this.gutterLeft) / (this.graphwidth / 2)) * (this.max - prop['chart.xmin']);
1909
- value = value - this.max
1910
-
1911
- // Special case if xmin is defined
1912
- if (prop['chart.xmin'] > 0) {
1913
- value = ((mouseX - this.gutterLeft - (this.graphwidth / 2)) / (this.graphwidth / 2)) * (this.max - prop['chart.xmin']);
1914
- value += prop['chart.xmin'];
1915
-
1916
- if (mouseX < (this.gutterLeft + (this.graphwidth / 2))) {
1917
- value -= (2 * prop['chart.xmin']);
1918
- }
1919
- }
1920
-
1921
-
1922
- // TODO This needs fixing
1923
- } else if (prop['chart.yaxispos'] == 'right') {
1924
- var value = ((mouseX - this.gutterLeft) / this.graphwidth) * (this.scale2.max - prop['chart.xmin']);
1925
- value = this.scale2.max - value;
1926
-
1927
- } else {
1928
- var value = ((mouseX - this.gutterLeft) / this.graphwidth) * (this.scale2.max - prop['chart.xmin']);
1929
- value += prop['chart.xmin'];
1930
- }
1931
-
1932
-
1933
-
1934
-
1935
-
1936
-
1937
- return value;
1938
- };
1939
-
1940
-
1941
-
1942
-
1943
- /**
1944
- * Each object type has its own Highlight() function which highlights the appropriate shape
1945
- *
1946
- * @param object shape The shape to highlight
1947
- */
1948
- this.highlight =
1949
- this.Highlight = function (shape)
1950
- {
1951
- if (typeof prop['chart.highlight.style'] === 'function') {
1952
- (prop['chart.highlight.style'])(shape);
1953
- } else {
1954
- RG.Highlight.Rect(this, shape);
1955
- }
1956
- };
1957
-
1958
-
1959
-
1960
-
1961
- /**
1962
- * The getObjectByXY() worker method. Don't call this call:
1963
- *
1964
- * RG.ObjectRegistry.getObjectByXY(e)
1965
- *
1966
- * @param object e The event object
1967
- */
1968
- this.getObjectByXY = function (e)
1969
- {
1970
- var mouseXY = RG.getMouseXY(e);
1971
-
1972
- // Adjust the mouse Y coordinate for when the bar chart is
1973
- // a 3D variant
1974
- if (prop['chart.variant'] === '3d') {
1975
- var adjustment = prop['chart.variant.threed.angle'] * mouseXY[0];
1976
- mouseXY[1] -= adjustment;
1977
- }
1978
-
1979
-
1980
- if (
1981
- mouseXY[0] >= this.gutterLeft
1982
- && mouseXY[0] <= (ca.width - this.gutterRight)
1983
- && mouseXY[1] >= this.gutterTop
1984
- && mouseXY[1] <= (ca.height - this.gutterBottom)
1985
- ) {
1986
-
1987
- return this;
1988
- }
1989
- };
1990
-
1991
-
1992
-
1993
-
1994
- /**
1995
- * This function positions a tooltip when it is displayed
1996
- *
1997
- * @param obj object The chart object
1998
- * @param int x The X coordinate specified for the tooltip
1999
- * @param int y The Y coordinate specified for the tooltip
2000
- * @param objec tooltip The tooltips DIV element
2001
- *
2002
- this.positionTooltip = function (obj, x, y, tooltip, idx)
2003
- {
2004
- var coordX = obj.coords[tooltip.__index__][0],
2005
- coordY = obj.coords[tooltip.__index__][1],
2006
- coordW = obj.coords[tooltip.__index__][2],
2007
- coordH = obj.coords[tooltip.__index__][3],
2008
- canvasXY = RG.getCanvasXY(obj.canvas),
2009
- gutterLeft = obj.gutterLeft,
2010
- gutterTop = obj.gutterTop,
2011
- width = tooltip.offsetWidth,
2012
- height = tooltip.offsetHeight,
2013
- mouseXY = RG.getMouseXY(window.event);
2014
-
2015
- // If the chart is a 3D version the tooltip Y position needs this
2016
- // adjustment
2017
- if (prop['chart.variant'] === '3d' && coordW) {
2018
- var adjustment = (prop['chart.variant.threed.angle'] * ((coordX + coordW) / 2));
2019
- }
2020
-
2021
-
2022
-
2023
- // Set the top position
2024
- tooltip.style.left = 0;
2025
- tooltip.style.top = window.event.pageY - height - 5 + 'px';
2026
-
2027
- // By default any overflow is hidden
2028
- tooltip.style.overflow = '';
2029
-
2030
- // Reposition the tooltip if at the edges:
2031
-
2032
- // LEFT edge
2033
- if (canvasXY[0] + mouseXY[0] - (width / 2) < 0) {
2034
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
2035
-
2036
- // RIGHT edge
2037
- } else if (canvasXY[0] + mouseXY[0] + (width / 2) > doc.body.offsetWidth) {
2038
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
2039
-
2040
- // Default positioning - CENTERED
2041
- } else {
2042
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
2043
- }
2044
- };*/
2045
-
2046
-
2047
-
2048
-
2049
- /**
2050
- * Returns the appropriate Y coord for the given value
2051
- *
2052
- * @param number value The value to get the coord for
2053
- */
2054
- this.getXCoord = function (value)
2055
- {
2056
-
2057
- if (prop['chart.yaxispos'] == 'center') {
2058
-
2059
- // Range checking
2060
- if (value > this.max || value < (-1 * this.max)) {
2061
- return null;
2062
- }
2063
-
2064
- var width = (ca.width - prop['chart.gutter.left'] - prop['chart.gutter.right']) / 2;
2065
- var coord = (((value - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * width) + width;
2066
-
2067
- coord = prop['chart.gutter.left'] + coord;
2068
- } else {
2069
-
2070
- // Range checking
2071
- if (value > this.max || value < 0) {
2072
- return null;
2073
- }
2074
-
2075
- var width = ca.width - prop['chart.gutter.left'] - prop['chart.gutter.right'];
2076
- var coord = ((value - prop['chart.xmin']) / (this.max - prop['chart.xmin'])) * width;
2077
-
2078
- coord = prop['chart.gutter.left'] + coord;
2079
- }
2080
-
2081
- return coord;
2082
- };
2083
-
2084
-
2085
-
2086
-
2087
- /**
2088
- *
2089
- */
2090
- this.parseColors = function ()
2091
- {
2092
- // Save the original colors so that they can be restored when the canvas is reset
2093
- if (this.original_colors.length === 0) {
2094
- //this.original_colors['chart.'] = RG.array_clone(prop['chart.']);
2095
- this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
2096
- this.original_colors['chart.background.grid.color'] = RG.array_clone(prop['chart.background.grid.color']);
2097
- this.original_colors['chart.background.color'] = RG.array_clone(prop['chart.background.color']);
2098
- this.original_colors['chart.background.barcolor1'] = RG.array_clone(prop['chart.background.barcolor1']);
2099
- this.original_colors['chart.background.barcolor2'] = RG.array_clone(prop['chart.background.barcolor2']);
2100
- this.original_colors['chart.text.color'] = RG.array_clone(prop['chart.text.color']);
2101
- this.original_colors['chart.labels.colors'] = RG.array_clone(prop['chart.labels.colors']);
2102
- this.original_colors['chart.strokestyle'] = RG.array_clone(prop['chart.strokestyle']);
2103
- this.original_colors['chart.axis.color'] = RG.array_clone(prop['chart.axis.color']);
2104
- this.original_colors['chart.highlight.fill'] = RG.array_clone(prop['chart.highlight.fill']);
2105
- this.original_colors['chart.highlight.stroke'] = RG.array_clone(prop['chart.highlight.stroke']);
2106
-
2107
- }
2108
-
2109
- var colors = prop['chart.colors'];
2110
-
2111
- for (var i=0; i<colors.length; ++i) {
2112
- colors[i] = this.parseSingleColorForGradient(colors[i]);
2113
- }
2114
-
2115
- prop['chart.background.grid.color'] = this.parseSingleColorForGradient(prop['chart.background.grid.color']);
2116
- prop['chart.background.color'] = this.parseSingleColorForGradient(prop['chart.background.color']);
2117
- prop['chart.background.barcolor1'] = this.parseSingleColorForGradient(prop['chart.background.barcolor1']);
2118
- prop['chart.background.barcolor2'] = this.parseSingleColorForGradient(prop['chart.background.barcolor2']);
2119
- prop['chart.text.color'] = this.parseSingleColorForGradient(prop['chart.text.color']);
2120
- prop['chart.labels.colors'] = this.parseSingleColorForGradient(prop['chart.labels.colors']);
2121
- prop['chart.strokestyle'] = this.parseSingleColorForGradient(prop['chart.strokestyle']);
2122
- prop['chart.axis.color'] = this.parseSingleColorForGradient(prop['chart.axis.color']);
2123
- prop['chart.highlight.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.fill']);
2124
- prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
2125
- };
2126
-
2127
-
2128
-
2129
-
2130
- /**
2131
- * Use this function to reset the object to the post-constructor state. Eg reset colors if
2132
- * need be etc
2133
- */
2134
- this.reset = function ()
2135
- {
2136
- };
2137
-
2138
-
2139
-
2140
- /**
2141
- * This parses a single color value
2142
- */
2143
- this.parseSingleColorForGradient = function (color)
2144
- {
2145
- if (!color || typeof(color) != 'string') {
2146
- return color;
2147
- }
2148
-
2149
- if (color.match(/^gradient\((.*)\)$/i)) {
2150
-
2151
- var parts = RegExp.$1.split(':');
2152
-
2153
- if (prop['chart.yaxispos'] === 'right') {
2154
- parts = RG.arrayReverse(parts);
2155
- }
2156
-
2157
- // Create the gradient
2158
- var grad = co.createLinearGradient(prop['chart.gutter.left'],0,ca.width - prop['chart.gutter.right'],0);
2159
-
2160
- var diff = 1 / (parts.length - 1);
2161
-
2162
- grad.addColorStop(0, RG.trim(parts[0]));
2163
-
2164
- for (var j=1; j<parts.length; ++j) {
2165
- grad.addColorStop(j * diff, RG.trim(parts[j]));
2166
- }
2167
- }
2168
-
2169
- return grad ? grad : color;
2170
- };
2171
-
2172
-
2173
-
2174
-
2175
- /**
2176
- * This function handles highlighting an entire data-series for the interactive
2177
- * key
2178
- *
2179
- * @param int index The index of the data series to be highlighted
2180
- */
2181
- this.interactiveKeyHighlight = function (index)
2182
- {
2183
- var obj = this;
2184
-
2185
- this.coords2.forEach(function (value, idx, arr)
2186
- {
2187
- var shape = obj.coords2[idx][index]
2188
- var pre_linewidth = co.lineWidth;
2189
- co.lineWidth = 2;
2190
- co.fillStyle = prop['chart.key.interactive.highlight.chart.fill'];
2191
- co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
2192
- co.fillRect(shape[0], shape[1], shape[2], shape[3]);
2193
- co.strokeRect(shape[0], shape[1], shape[2], shape[3]);
2194
-
2195
- // Reset the lineWidth
2196
- co.lineWidth = pre_linewidth;
2197
- });
2198
- };
2199
-
2200
-
2201
-
2202
-
2203
- /**
2204
- * Using a function to add events makes it easier to facilitate method chaining
2205
- *
2206
- * @param string type The type of even to add
2207
- * @param function func
2208
- */
2209
- this.on = function (type, func)
2210
- {
2211
- if (type.substr(0,2) !== 'on') {
2212
- type = 'on' + type;
2213
- }
2214
-
2215
- if (typeof this[type] !== 'function') {
2216
- this[type] = func;
2217
- } else {
2218
- RG.addCustomEventListener(this, type, func);
2219
- }
2220
-
2221
- return this;
2222
- };
2223
-
2224
-
2225
-
2226
-
2227
- /**
2228
- * This function runs once only
2229
- * (put at the end of the file (before any effects))
2230
- */
2231
- this.firstDrawFunc = function ()
2232
- {
2233
- };
2234
-
2235
-
2236
-
2237
-
2238
- /**
2239
- * This retrives the bar based on the X coordinate only.
2240
- *
2241
- * @param object e The event object
2242
- * @param object OPTIONAL You can pass in the bar object instead of the
2243
- * function using "this"
2244
- */
2245
- this.getShapeByY = function (e)
2246
- {
2247
- var mouseXY = RG.getMouseXY(e);
2248
-
2249
-
2250
- // This facilitates you being able to pass in the bar object as a parameter instead of
2251
- // the function getting it from itself
2252
- var obj = arguments[1] ? arguments[1] : this;
2253
-
2254
-
2255
- /**
2256
- * Loop through the bars determining if the mouse is over a bar
2257
- */
2258
- for (var i=0,len=obj.coords.length; i<len; i++) {
2259
-
2260
- if (obj.coords[i].length == 0) {
2261
- continue;
2262
- }
2263
-
2264
- var mouseX = mouseXY[0],
2265
- mouseY = mouseXY[1],
2266
- left = obj.coords[i][0],
2267
- top = obj.coords[i][1],
2268
- width = obj.coords[i][2],
2269
- height = obj.coords[i][3];
2270
-
2271
- if (mouseY >= top && mouseY <= (top + height)) {
2272
-
2273
- if (prop['chart.tooltips']) {
2274
- var tooltip = RG.parseTooltipText ? RG.parseTooltipText(prop['chart.tooltips'], i) : prop['chart.tooltips'][i];
2275
- }
2276
-
2277
- return {
2278
- 0: obj, object: obj,
2279
- 1: left, x: left,
2280
- 2: top, y: top,
2281
- 3: width, width: width,
2282
- 4: height, height: height,
2283
- 5: i, index: i,
2284
- tooltip: tooltip
2285
- };
2286
- }
2287
- }
2288
-
2289
- return null;
2290
- };
2291
-
2292
-
2293
-
2294
-
2295
- /**
2296
- * This method handles the adjusting calculation for when the mouse is moved
2297
- *
2298
- * @param object e The event object
2299
- */
2300
- this.adjusting_mousemove =
2301
- this.Adjusting_mousemove = function (e)
2302
- {
2303
- /**
2304
- * Handle adjusting for the Bar
2305
- */
2306
- if (prop['chart.adjustable'] && RG.Registry.get('chart.adjusting') && RG.Registry.get('chart.adjusting').uid == this.uid) {
2307
-
2308
- // Rounding the value to the given number of decimals make the chart step
2309
- var value = Number(this.getValue(e)),
2310
- shape = RG.Registry.get('chart.adjusting.shape');
2311
-
2312
- if (shape) {
2313
-
2314
- RG.Registry.Set('chart.adjusting.shape', shape);
2315
-
2316
- if (this.stackedOrGrouped && prop['chart.grouping'] == 'grouped') {
2317
-
2318
- var indexes = RG.sequentialIndexToGrouped(shape['index'], this.data);
2319
-
2320
- if (typeof this.data[indexes[0]] == 'number') {
2321
- this.data[indexes[0]] = Number(value);
2322
- } else if (!RG.is_null(this.data[indexes[0]])) {
2323
- this.data[indexes[0]][indexes[1]] = Number(value);
2324
- }
2325
- } else if (typeof this.data[shape['index']] == 'number') {
2326
-
2327
- this.data[shape['index']] = Number(value);
2328
- }
2329
-
2330
- RG.redrawCanvas(e.target);
2331
- RG.fireCustomEvent(this, 'onadjust');
2332
- }
2333
- }
2334
- };
2335
-
2336
-
2337
-
2338
-
2339
- /**
2340
- * Grow
2341
- *
2342
- * The HBar chart Grow effect gradually increases the values of the bars
2343
- *
2344
- * @param object OPTIONAL Options for the effect. You can pass frames here
2345
- * @param function OPTIONAL A callback function
2346
- */
2347
- this.grow = function ()
2348
- {
2349
- var obj = this,
2350
- opt = arguments[0] || {},
2351
- frames = opt.frames || 30,
2352
- frame = 0,
2353
- callback = arguments[1] || function () {},
2354
- labelsAbove = prop['chart.labels.above'];
2355
-
2356
- this.set('labelsAbove', false);
2357
-
2358
-
2359
- // Save the data
2360
- obj.original_data = RG.arrayClone(obj.data);
2361
-
2362
-
2363
- // Stop the scale from changing by setting chart.xmax (if it's not already set)
2364
- if (prop['chart.xmax'] == 0) {
2365
-
2366
- var xmax = 0;
2367
-
2368
- for (var i=0; i<obj.data.length; ++i) {
2369
- if (RG.isArray(obj.data[i]) && prop['chart.grouping'] == 'stacked') {
2370
- xmax = ma.max(xmax, RG.arraySum(obj.data[i]));
2371
- } else if (RG.isArray(obj.data[i]) && prop['chart.grouping'] == 'grouped') {
2372
- xmax = ma.max(xmax, RG.arrayMax(obj.data[i]));
2373
- } else {
2374
- xmax = ma.max(xmax, ma.abs(RG.arrayMax(obj.data[i])));
2375
- }
2376
- }
2377
-
2378
- var scale2 = RG.getScale2(obj, {'max':xmax});
2379
- obj.Set('chart.xmax', scale2.max);
2380
- }
2381
-
2382
- function iterator ()
2383
- {
2384
- // Alter the Bar chart data depending on the frame
2385
- for (var j=0,len=obj.original_data.length; j<len; ++j) {
2386
-
2387
- // This stops the animation from being completely linear
2388
- var easingFactor = RG.Effects.getEasingMultiplier(frames, frame);
2389
-
2390
- if (typeof obj.data[j] === 'object' && obj.data[j]) {
2391
- for (var k=0,len2=obj.data[j].length; k<len2; ++k) {
2392
- obj.data[j][k] = RG.isNull(obj.data[j][k]) ? null : obj.original_data[j][k] * easingFactor;
2393
- }
2394
- } else {
2395
- obj.data[j] = RG.isNull(obj.data[j]) ? null : obj.original_data[j] * easingFactor;
2396
- }
2397
- }
2398
-
2399
-
2400
-
2401
- RG.redrawCanvas(obj.canvas);
2402
-
2403
- if (frame < frames) {
2404
- frame += 1;
2405
- RG.Effects.updateCanvas(iterator);
2406
- } else {
2407
-
2408
- if (labelsAbove) {
2409
- obj.set('labelsAbove', true);
2410
- RG.redraw();
2411
- }
2412
-
2413
- callback(obj);
2414
- }
2415
- }
2416
-
2417
- iterator();
2418
-
2419
- return this;
2420
- };
2421
-
2422
-
2423
-
2424
-
2425
-
2426
-
2427
-
2428
-
2429
- /**
2430
- * Grow
2431
- *
2432
- * The HBar chart Grow effect gradually increases the values of the bars
2433
- *
2434
- * @param object An object of options - eg: {frames: 30}
2435
- * @param function A function to call when the effect is complete
2436
- */
2437
- this.grow = function ()
2438
- {
2439
- // Callback
2440
- var opt = arguments[0] || {},
2441
- frames = opt.frames || 30,
2442
- frame = 0,
2443
- callback = arguments[1] || function () {},
2444
- obj = this,
2445
- labelsAbove = this.get('labelsAbove')
2446
-
2447
-
2448
-
2449
-
2450
- this.original_data = RG.arrayClone(this.data);
2451
-
2452
-
2453
-
2454
- // Stop the scale from changing by setting chart.xmax (if it's not already set)
2455
- if (prop['chart.xmax'] == 0) {
2456
-
2457
- var xmax = 0;
2458
-
2459
- for (var i=0; i<obj.data.length; ++i) {
2460
- if (RG.isArray(obj.data[i]) && prop['chart.grouping'] == 'stacked') {
2461
- xmax = ma.max(xmax, RG.arraySum(obj.data[i]));
2462
- } else if (RG.isArray(obj.data[i]) && prop['chart.grouping'] == 'grouped') {
2463
- xmax = ma.max(xmax, RG.arrayMax(obj.data[i]));
2464
- } else {
2465
- xmax = ma.max(xmax, ma.abs(RG.arrayMax(obj.data[i])));
2466
- }
2467
- }
2468
-
2469
- var scale2 = RG.getScale2(obj, {'max':xmax});
2470
- obj.Set('chart.xmax', scale2.max);
2471
- }
2472
-
2473
-
2474
- // Go through the data and change string arguments of the format +/-[0-9]
2475
- // to absolute numbers
2476
- if (RG.isArray(opt.data)) {
2477
-
2478
- var xmax = 0;
2479
-
2480
- for (var i=0; i<opt.data.length; ++i) {
2481
- if (typeof opt.data[i] === 'object') {
2482
- for (var j=0; j<opt.data[i].length; ++j) {
2483
- if (typeof opt.data[i][j] === 'string'&& opt.data[i][j].match(/(\+|\-)([0-9]+)/)) {
2484
- if (RegExp.$1 === '+') {
2485
- opt.data[i][j] = this.original_data[i][j] + parseInt(RegExp.$2);
2486
- } else {
2487
- opt.data[i][j] = this.original_data[i][j] - parseInt(RegExp.$2);
2488
- }
2489
- }
2490
-
2491
- xmax = ma.max(xmax, opt.data[i][j]);
2492
- }
2493
- } else if (typeof opt.data[i] === 'string' && opt.data[i].match(/(\+|\-)([0-9]+)/)) {
2494
- if (RegExp.$1 === '+') {
2495
- opt.data[i] = this.original_data[i] + parseFloat(RegExp.$2);
2496
- } else {
2497
- opt.data[i] = this.original_data[i] - parseFloat(RegExp.$2);
2498
- }
2499
-
2500
- xmax = ma.max(xmax, opt.data[i]);
2501
- } else {
2502
- xmax = ma.max(xmax, opt.data[i]);
2503
- }
2504
- }
2505
-
2506
-
2507
- var scale = RG.getScale2(this, {'max':xmax});
2508
- if (typeof this.get('chart.xmax') === 'null') {
2509
- this.set('chart.xmax', scale.max);
2510
- }
2511
- }
2512
-
2513
-
2514
-
2515
-
2516
-
2517
-
2518
- //
2519
- // turn off the labelsAbove option whilst animating
2520
- //
2521
- this.set('labelsAbove', false);
2522
-
2523
-
2524
-
2525
-
2526
-
2527
-
2528
- // Stop the scale from changing by setting chart.xmax (if it's not already set)
2529
- if (RG.isNull(prop['chart.xmax'])) {
2530
-
2531
- var xmax = 0;
2532
-
2533
- for (var i=0; i<obj.data.length; ++i) {
2534
- if (RG.isArray(this.data[i]) && prop['chart.grouping'] === 'stacked') {
2535
- xmax = ma.max(xmax, ma.abs(RG.arraySum(this.data[i])));
2536
-
2537
- } else if (RG.isArray(this.data[i]) && prop['chart.grouping'] === 'grouped') {
2538
-
2539
- for (var j=0,group=[]; j<this.data[i].length; j++) {
2540
- group.push(ma.abs(this.data[i][j]));
2541
- }
2542
-
2543
- xmax = ma.max(xmax, ma.abs(RG.arrayMax(group)));
2544
-
2545
- } else {
2546
- xmax = ma.max(xmax, ma.abs(this.data[i]));
2547
- }
2548
- }
2549
-
2550
- var scale = RG.getScale2(this, {'max':xmax});
2551
- this.Set('chart.xmax', scale.max);
2552
- }
2553
-
2554
- // You can give an xmax to the grow function
2555
- if (typeof opt.xmax === 'number') {
2556
- obj.set('xmax', opt.xmax);
2557
- }
2558
-
2559
-
2560
-
2561
- var iterator = function ()
2562
- {
2563
- var easingMultiplier = RG.Effects.getEasingMultiplier(frames, frame);
2564
-
2565
- // Alter the Bar chart data depending on the frame
2566
- for (var j=0,len=obj.original_data.length; j<len; ++j) {
2567
- if (typeof obj.data[j] === 'object' && !RG.isNull(obj.data[j])) {
2568
- for (var k=0,len2=obj.data[j].length; k<len2; ++k) {
2569
- if (obj.firstDraw || !opt.data) {
2570
- obj.data[j][k] = easingMultiplier * obj.original_data[j][k];
2571
- } else if (opt.data && opt.data.length === obj.original_data.length) {
2572
- var diff = opt.data[j][k] - obj.original_data[j][k];
2573
- obj.data[j][k] = (easingMultiplier * diff) + obj.original_data[j][k];
2574
- }
2575
- }
2576
- } else {
2577
-
2578
- if (obj.firstDraw || !opt.data) {
2579
- obj.data[j] = easingMultiplier * obj.original_data[j];
2580
- } else if (opt.data && opt.data.length === obj.original_data.length) {
2581
- var diff = opt.data[j] - obj.original_data[j];
2582
- obj.data[j] = (easingMultiplier * diff) + obj.original_data[j];
2583
- }
2584
- }
2585
- }
2586
-
2587
-
2588
-
2589
-
2590
- //RGraph.clear(obj.canvas);
2591
- RG.redrawCanvas(obj.canvas);
2592
-
2593
-
2594
-
2595
-
2596
- if (frame < frames) {
2597
- frame += 1;
2598
-
2599
- RG.Effects.updateCanvas(iterator);
2600
-
2601
- // Call the callback function
2602
- } else {
2603
-
2604
-
2605
-
2606
-
2607
-
2608
- // Do some housekeeping if new data was specified thats done in
2609
- // the constructor - but needs to be redone because new data
2610
- // has been specified
2611
- if (RG.isArray(opt.data)) {
2612
-
2613
- var linear_data = RG.arrayLinearize(data);
2614
-
2615
- for (var i=0; i<linear_data.length; ++i) {
2616
- if (!obj['$' + i]) {
2617
- obj['$' + i] = {};
2618
- }
2619
- }
2620
- }
2621
-
2622
-
2623
-
2624
- obj.data = data;
2625
- obj.original_data = RG.arrayClone(data);
2626
-
2627
-
2628
-
2629
-
2630
-
2631
- if (labelsAbove) {
2632
- obj.set('labelsAbove', true);
2633
- RG.redraw();
2634
- }
2635
- callback(obj);
2636
- }
2637
- };
2638
-
2639
- iterator();
2640
-
2641
- return this;
2642
- };
2643
-
2644
-
2645
-
2646
-
2647
-
2648
-
2649
-
2650
-
2651
- /**
2652
- * (new) Bar chart Wave effect. This is a rewrite that should be smoother
2653
- * because it just uses a single loop and not setTimeout
2654
- *
2655
- * @param object OPTIONAL An object map of options. You specify 'frames' here to give the number of frames in the effect
2656
- * @param function OPTIONAL A function that will be called when the effect is complete
2657
- */
2658
- this.wave = function ()
2659
- {
2660
- var obj = this,
2661
- opt = arguments[0] || {};
2662
- opt.frames = opt.frames || 60;
2663
- opt.startFrames = [];
2664
- opt.counters = [];
2665
-
2666
- var framesperbar = opt.frames / 3,
2667
- frame = -1,
2668
- callback = arguments[1] || function () {},
2669
- original = RG.arrayClone(obj.data),
2670
- labelsAbove = prop['chart.labels.above'];
2671
-
2672
- this.set('labelsAbove', false);
2673
-
2674
- for (var i=0,len=obj.data.length; i<len; i+=1) {
2675
- opt.startFrames[i] = ((opt.frames / 2) / (obj.data.length - 1)) * i;
2676
-
2677
- if (typeof obj.data[i] === 'object' && obj.data[i]) {
2678
- opt.counters[i] = [];
2679
- for (var j=0; j<obj.data[i].length; j++) {
2680
- opt.counters[i][j] = 0;
2681
- }
2682
- } else {
2683
- opt.counters[i] = 0;
2684
- }
2685
- }
2686
-
2687
- /**
2688
- * This stops the chart from jumping
2689
- */
2690
- obj.draw();
2691
- obj.Set('xmax', obj.scale2.max);
2692
- RG.clear(obj.canvas);
2693
-
2694
- function iterator ()
2695
- {
2696
- ++frame;
2697
-
2698
- for (var i=0,len=obj.data.length; i<len; i+=1) {
2699
- if (frame > opt.startFrames[i]) {
2700
- if (typeof obj.data[i] === 'number') {
2701
-
2702
- obj.data[i] = ma.min(
2703
- ma.abs(original[i]),
2704
- ma.abs(original[i] * ( (opt.counters[i]++) / framesperbar))
2705
- );
2706
-
2707
- // Make the number negative if the original was
2708
- if (original[i] < 0) {
2709
- obj.data[i] *= -1;
2710
- }
2711
- } else if (!RG.isNull(obj.data[i])) {
2712
- for (var j=0,len2=obj.data[i].length; j<len2; j+=1) {
2713
-
2714
- obj.data[i][j] = ma.min(
2715
- ma.abs(original[i][j]),
2716
- ma.abs(original[i][j] * ( (opt.counters[i][j]++) / framesperbar))
2717
- );
2718
-
2719
- // Make the number negative if the original was
2720
- if (original[i][j] < 0) {
2721
- obj.data[i][j] *= -1;
2722
- }
2723
- }
2724
- }
2725
- } else {
2726
- obj.data[i] = typeof obj.data[i] === 'object' && obj.data[i] ? RG.arrayPad([], obj.data[i].length, 0) : (RG.isNull(obj.data[i]) ? null : 0);
2727
- }
2728
- }
2729
-
2730
-
2731
- if (frame >= opt.frames) {
2732
-
2733
- if (labelsAbove) {
2734
- obj.set('labelsAbove', true);
2735
- RG.redrawCanvas(obj.canvas);
2736
- }
2737
-
2738
- callback(obj);
2739
- } else {
2740
- RG.redrawCanvas(obj.canvas);
2741
- RG.Effects.updateCanvas(iterator);
2742
- }
2743
- }
2744
-
2745
- iterator();
2746
-
2747
- return this;
2748
- };
2749
-
2750
-
2751
-
2752
-
2753
- //
2754
- // Determines whether the given shape is adjustable or not
2755
- //
2756
- // @param object The shape that pertains to the relevant bar
2757
- //
2758
- this.isAdjustable = function (shape)
2759
- {
2760
- if (RG.isNull(prop['chart.adjustable.only'])) {
2761
- return true;
2762
- }
2763
-
2764
- if (RG.isArray(prop['chart.adjustable.only']) && prop['chart.adjustable.only'][shape.index]) {
2765
- return true;
2766
- }
2767
-
2768
- return false;
2769
- };
2770
-
2771
-
2772
-
2773
-
2774
- /**
2775
- * Charts are now always registered
2776
- */
2777
- RG.Register(this);
2778
-
2779
-
2780
-
2781
-
2782
- /**
2783
- * This is the 'end' of the constructor so if the first argument
2784
- * contains configuration data - handle that.
2785
- */
2786
- if (parseConfObjectForOptions) {
2787
- RG.parseObjectStyleConfig(this, conf.options);
2788
- }
2789
- };
2
+ RGraph=window.RGraph||{isRGraph:true};RGraph.HBar=function(conf)
3
+ {if(typeof conf==='object'&&typeof conf.data==='object'&&typeof conf.id==='string'){var id=conf.id
4
+ var canvas=document.getElementById(id);var data=conf.data;var parseConfObjectForOptions=true;}else{var id=conf;var canvas=document.getElementById(id);var data=arguments[1];}
5
+ this.id=id;this.canvas=canvas;this.context=this.canvas.getContext?this.canvas.getContext("2d",{alpha:(typeof id==='object'&&id.alpha===false)?false:true}):null;this.canvas.__object__=this;this.data=data;this.type='hbar';this.isRGraph=true;this.uid=RGraph.CreateUID();this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID();this.colorsParsed=false;this.coords=[];this.coords2=[];this.coordsText=[];this.original_colors=[];this.firstDraw=true;this.max=0;this.stackedOrGrouped=false;this.properties={'chart.gutter.left':75,'chart.gutter.left.autosize':false,'chart.gutter.right':25,'chart.gutter.top':25,'chart.gutter.bottom':25,'chart.background.grid':true,'chart.background.grid.color':'#ddd','chart.background.grid.width':1,'chart.background.grid.hsize':25,'chart.background.grid.vsize':25,'chart.background.barcolor1':'rgba(0,0,0,0)','chart.background.barcolor2':'rgba(0,0,0,0)','chart.background.grid.hlines':true,'chart.background.grid.vlines':true,'chart.background.grid.border':true,'chart.background.grid.autofit':true,'chart.background.grid.autofit.align':true,'chart.background.grid.autofit.numhlines':null,'chart.background.grid.autofit.numvlines':5,'chart.background.grid.dashed':false,'chart.background.grid.dotted':false,'chart.background.color':null,'chart.linewidth':1,'chart.title':'','chart.title.background':null,'chart.title.xaxis':'','chart.title.xaxis.bold':true,'chart.title.xaxis.size':null,'chart.title.xaxis.font':null,'chart.title.yaxis':'','chart.title.yaxis.bold':true,'chart.title.yaxis.size':null,'chart.title.yaxis.font':null,'chart.title.yaxis.color':null,'chart.title.xaxis.pos':null,'chart.title.yaxis.pos':0.8,'chart.title.yaxis.x':null,'chart.title.yaxis.y':null,'chart.title.xaxis.x':null,'chart.title.xaxis.y':null,'chart.title.xaxis.color':null,'chart.title.hpos':null,'chart.title.vpos':null,'chart.title.bold':true,'chart.title.font':null,'chart.title.x':null,'chart.title.y':null,'chart.title.halign':null,'chart.title.valign':null,'chart.text.size':12,'chart.text.color':'black','chart.text.font':'Segoe UI, Arial, Verdana, sans-serif','chart.text.angle':0,'chart.text.accessible':true,'chart.text.accessible.overflow':'visible','chart.text.accessible.pointerevents':true,'chart.colors':['red','blue','green','pink','yellow','cyan','navy','gray','black'],'chart.colors.sequential':false,'chart.xlabels.specific':null,'chart.labels':[],'chart.labels.bold':false,'chart.labels.color':null,'chart.labels.above':false,'chart.labels.above.decimals':0,'chart.labels.above.specific':null,'chart.labels.above.color':null,'chart.labels.above.units.pre':'','chart.labels.above.units.post':'','chart.labels.above.font':null,'chart.labels.above.size':null,'chart.labels.above.bold':false,'chart.labels.above.italic':false,'chart.labels.offsetx':0,'chart.labels.offsety':0,'chart.xlabels.offsetx':0,'chart.xlabels.offsety':0,'chart.xlabels':true,'chart.xlabels.count':5,'chart.contextmenu':null,'chart.key':null,'chart.key.background':'white','chart.key.position':'graph','chart.key.halign':'right','chart.key.shadow':false,'chart.key.shadow.color':'#666','chart.key.shadow.blur':3,'chart.key.shadow.offsetx':2,'chart.key.shadow.offsety':2,'chart.key.position.gutter.boxed':false,'chart.key.position.x':null,'chart.key.position.y':null,'chart.key.color.shape':'square','chart.key.rounded':true,'chart.key.linewidth':1,'chart.key.colors':null,'chart.key.interactive':false,'chart.key.interactive.highlight.chart.stroke':'black','chart.key.interactive.highlight.chart.fill':'rgba(255,255,255,0.7)','chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)','chart.key.text.color':'black','chart.units.pre':'','chart.units.post':'','chart.units.ingraph':false,'chart.strokestyle':'rgba(0,0,0,0)','chart.xmin':0,'chart.xmax':0,'chart.axis.color':'black','chart.shadow':false,'chart.shadow.color':'#666','chart.shadow.blur':3,'chart.shadow.offsetx':3,'chart.shadow.offsety':3,'chart.vmargin':2,'chart.vmargin.grouped':2,'chart.grouping':'grouped','chart.tooltips':null,'chart.tooltips.event':'onclick','chart.tooltips.effect':'fade','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.highlight':true,'chart.highlight.fill':'rgba(255,255,255,0.7)','chart.highlight.stroke':'rgba(0,0,0,0)','chart.highlight.style':null,'chart.annotatable':false,'chart.annotate.color':'black','chart.zoom.factor':1.5,'chart.zoom.fade.in':true,'chart.zoom.fade.out':true,'chart.zoom.hdir':'right','chart.zoom.vdir':'down','chart.zoom.frames':25,'chart.zoom.delay':16.666,'chart.zoom.shadow':true,'chart.zoom.background':true,'chart.zoom.action':'zoom','chart.resizable':false,'chart.resize.handle.adjust':[0,0],'chart.resize.handle.background':null,'chart.scale.point':'.','chart.scale.thousand':',','chart.scale.decimals':null,'chart.scale.zerostart':true,'chart.noredraw':false,'chart.events.click':null,'chart.events.mousemove':null,'chart.noxaxis':false,'chart.noyaxis':false,'chart.noaxes':false,'chart.noxtickmarks':false,'chart.noytickmarks':false,'chart.numyticks':data.length,'chart.numxticks':10,'chart.variant':'hbar','chart.variant.threed.angle':0.1,'chart.variant.threed.offsetx':10,'chart.variant.threed.offsety':5,'chart.variant.threed.xaxis':true,'chart.variant.threed.yaxis':true,'chart.yaxispos':'left','chart.variant':'hbar','chart.clearto':'rgba(0,0,0,0)','chart.adjustable':false,'chart.adjustable.only':null}
6
+ if(!this.canvas){alert('[HBAR] No canvas support');return;}
7
+ for(i=0,len=this.data.length;i<len;++i){if(typeof this.data[i]=='object'&&!RGraph.isNull(this.data[i])){this.stackedOrGrouped=true;for(var j=0,len2=this.data[i].length;j<len2;++j){if(typeof this.data[i][j]==='string'){this.data[i][j]=parseFloat(this.data[i][j]);}}}else if(typeof this.data[i]=='string'){this.data[i]=parseFloat(this.data[i])||0;}else if(typeof this.data[i]==='undefined'){this.data[i]=null;}}
8
+ var linear_data=RGraph.arrayLinearize(data);for(var i=0,len=linear_data.length;i<len;++i){this['$'+i]={};}
9
+ this.data_arr=RGraph.arrayLinearize(this.data);if(!this.canvas.__rgraph_aa_translated__){this.context.translate(0.5,0.5);this.canvas.__rgraph_aa_translated__=true;}
10
+ var RG=RGraph,ca=this.canvas,co=ca.getContext('2d'),prop=this.properties,pa2=RG.path2,win=window,doc=document,ma=Math
11
+ if(RG.Effects&&typeof RG.Effects.decorate==='function'){RG.Effects.decorate(this);}
12
+ this.set=this.Set=function(name)
13
+ {var value=typeof arguments[1]==='undefined'?null:arguments[1];if(arguments.length===1&&typeof name==='object'){RG.parseObjectStyleConfig(this,name);return this;}
14
+ if(name.substr(0,6)!='chart.'){name='chart.'+name;}
15
+ while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
16
+ if(name=='chart.labels.abovebar'){name='chart.labels.above';}
17
+ prop[name]=value;return this;};this.get=this.Get=function(name)
18
+ {if(name.substr(0,6)!='chart.'){name='chart.'+name;}
19
+ while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
20
+ if(name=='chart.labels.abovebar'){name='chart.labels.above';}
21
+ return prop[name];};this.draw=this.Draw=function()
22
+ {RG.fireCustomEvent(this,'onbeforedraw');if(prop['chart.adjustable']&&prop['chart.grouping']==='stacked'){alert('[RGRAPH] The HBar does not support stacked charts with adjusting');}
23
+ if(prop['chart.variant']==='3d'){if(prop['chart.text.accessible']){}else{co.setTransform(1,prop['chart.variant.threed.angle'],0,1,0.5,0.5);}
24
+ if(prop['chart.gutter.bottom']===25){this.set('gutterBottom',80);}}
25
+ if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
26
+ if(prop['chart.gutter.left.autosize']){var len=0;var labels=prop['chart.labels'];var font=prop['chart.text.font'];var size=prop['chart.text.size'];for(var i=0;i<labels.length;i+=1){var length=RG.measureText(labels[i],false,font,size)[0]||0
27
+ len=ma.max(len,length);}
28
+ prop['chart.gutter.left']=len+10;}
29
+ this.gutterLeft=prop['chart.gutter.left'];this.gutterRight=prop['chart.gutter.right'];this.gutterTop=prop['chart.gutter.top'];this.gutterBottom=prop['chart.gutter.bottom'];this.coords=[];this.coords2=[];this.coordsText=[];this.max=0;if(prop['chart.xmin']>0&&prop['chart.grouping']=='stacked'){alert('[HBAR] Using chart.xmin is not supported with stacked charts, resetting chart.xmin to zero');this.Set('chart.xmin',0);}
30
+ this.graphwidth=ca.width-this.gutterLeft-this.gutterRight;this.graphheight=ca.height-this.gutterTop-this.gutterBottom;this.halfgrapharea=this.grapharea/2;this.halfTextHeight=prop['chart.text.size']/2;this.halfway=ma.round((this.graphwidth/2)+this.gutterLeft)
31
+ RG.Background.draw(this);this.drawbars();this.drawAxes();this.drawLabels();if(prop['chart.key']&&prop['chart.key'].length){RG.DrawKey(this,prop['chart.key'],prop['chart.colors']);}
32
+ if(prop['chart.contextmenu']){RG.ShowContext(this);}
33
+ RG.DrawInGraphLabels(this);if(prop['chart.resizable']){RG.AllowResizing(this);}
34
+ RG.InstallEventListeners(this);if(this.firstDraw){this.firstDraw=false;RG.fireCustomEvent(this,'onfirstdraw');this.firstDrawFunc();}
35
+ RG.FireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
36
+ {func(this);return this;};this.drawAxes=this.DrawAxes=function()
37
+ {var halfway=this.halfway
38
+ co.beginPath();co.lineWidth=prop['chart.axis.linewidth']?prop['chart.axis.linewidth']+0.001:1.001;co.strokeStyle=prop['chart.axis.color'];if(prop['chart.noyaxis']==false&&prop['chart.noaxes']==false){if(prop['chart.yaxispos']=='center'){co.moveTo(halfway,this.gutterTop);co.lineTo(halfway,ca.height-this.gutterBottom);}else if(prop['chart.yaxispos']=='right'){co.moveTo(ca.width-this.gutterRight,this.gutterTop);co.lineTo(ca.width-this.gutterRight,ca.height-this.gutterBottom);}else{co.moveTo(this.gutterLeft,this.gutterTop);co.lineTo(this.gutterLeft,ca.height-this.gutterBottom);}}
39
+ if(prop['chart.noxaxis']==false&&prop['chart.noaxes']==false){co.moveTo(this.gutterLeft+0.001,ca.height-this.gutterBottom+0.001);co.lineTo(ca.width-this.gutterRight+0.001,ca.height-this.gutterBottom+0.001);}
40
+ if(prop['chart.noytickmarks']==false&&prop['chart.noyaxis']==false&&prop['chart.numyticks']>0&&prop['chart.noaxes']==false){var yTickGap=(ca.height-this.gutterTop-this.gutterBottom)/(prop['chart.numyticks']>0?prop['chart.numyticks']:this.data.length);for(y=this.gutterTop;y<(ca.height-this.gutterBottom-1);y+=yTickGap){if(prop['chart.yaxispos']=='center'){co.moveTo(halfway+3,ma.round(y));co.lineTo(halfway-3,ma.round(y));}else if(prop['chart.yaxispos']=='right'){co.moveTo(ca.width-this.gutterRight,ma.round(y));co.lineTo(ca.width-this.gutterRight+3,ma.round(y));}else{co.moveTo(this.gutterLeft,ma.round(y));co.lineTo(this.gutterLeft-3,ma.round(y));}}
41
+ if(prop['chart.noxaxis']==true){if(prop['chart.yaxispos']=='center'){co.moveTo(halfway+3,ma.round(y));co.lineTo(halfway-3,ma.round(y));}else if(prop['chart.yaxispos']=='right'){co.moveTo(ca.width-this.gutterRight,ma.round(y));co.lineTo(ca.width-this.gutterRight+3,ma.round(y));}else{co.moveTo(this.gutterLeft,ma.round(y));co.lineTo(this.gutterLeft-3,ma.round(y));}}}
42
+ if(prop['chart.noxtickmarks']==false&&prop['chart.noxaxis']==false&&prop['chart.numxticks']>0&&prop['chart.noaxes']==false){xTickGap=(ca.width-this.gutterLeft-this.gutterRight)/prop['chart.numxticks'];yStart=ca.height-this.gutterBottom;yEnd=(ca.height-this.gutterBottom)+3;var i=prop['chart.numxticks']
43
+ while(i--){var x=ca.width-this.gutterRight-(i*xTickGap);if(prop['chart.yaxispos']==='right'){x-=xTickGap;}
44
+ co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}
45
+ if(prop['chart.yaxispos']==='center'){var i=5;while(i--){var x=this.gutterLeft+(xTickGap*i);co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}}
46
+ if(prop['chart.noyaxis']==true){co.moveTo(this.gutterLeft,ma.round(yStart));co.lineTo(this.gutterLeft,ma.round(yEnd));}}
47
+ co.stroke();co.lineWidth=1;};this.drawLabels=this.DrawLabels=function()
48
+ {var units_pre=prop['chart.units.pre'],units_post=prop['chart.units.post'],text_size=prop['chart.text.size'],font=prop['chart.text.font'],offsetx=prop['chart.xlabels.offsetx'],offsety=prop['chart.xlabels.offsety']
49
+ if(prop['chart.units.ingraph']){units_pre='';units_post='';}
50
+ if(prop['chart.xlabels']){if(RG.isArray(prop['chart.xlabels.specific'])){if(prop['chart.yaxispos']=='center'){var halfGraphWidth=this.graphwidth/2;var labels=prop['chart.xlabels.specific'];var interval=(this.graphwidth/2)/(labels.length-1);co.fillStyle=prop['chart.text.color'];for(var i=0;i<labels.length;i+=1){RG.text2(this,{font:font,size:text_size,x:this.gutterLeft+halfGraphWidth+(interval*i)+offsetx,y:ca.height-this.gutterBottom+offsetx,text:labels[i],valign:'top',halign:prop['chart.text.angle']!==0?'right':'center',tag:'scale',angle:-1*prop['chart.text.angle']});}
51
+ for(var i=(labels.length-1);i>0;i-=1){RG.Text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(interval*(labels.length-i-1))+offsetx,'y':ca.height-this.gutterBottom+offsety,'text':labels[i],'valign':'top','halign':prop['chart.text.angle']!==0?'right':'center','tag':'scale',angle:-1*prop['chart.text.angle']});}}else if(prop['chart.yaxispos']=='right'){var labels=prop['chart.xlabels.specific'];var interval=this.graphwidth/(labels.length-1);co.fillStyle=prop['chart.text.color'];for(var i=0;i<labels.length;i+=1){RG.text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(interval*i)+offsetx,'y':ca.height-this.gutterBottom+offsety,'text':labels[labels.length-i-1],'valign':'top','halign':prop['chart.text.angle']!==0?'right':'center','tag':'scale',angle:-1*prop['chart.text.angle']});}}else{var labels=prop['chart.xlabels.specific'];var interval=this.graphwidth/(labels.length-1);co.fillStyle=prop['chart.text.color'];for(var i=0;i<labels.length;i+=1){RG.text2(this,{font:font,size:text_size,x:this.gutterLeft+(interval*i)+offsetx,y:ca.height-this.gutterBottom+offsety,text:labels[i],valign:'top',halign:prop['chart.text.angle']!==0?'right':'center',tag:'scale',angle:-1*prop['chart.text.angle']});}}}else{var gap=7;co.beginPath();co.fillStyle=prop['chart.text.color'];if(prop['chart.yaxispos']=='center'){for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{font:font,size:text_size,x:this.gutterLeft+(this.graphwidth/2)-((this.graphwidth/2)*((i+1)/this.scale2.labels.length))+offsetx,y:this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,text:'-'+this.scale2.labels[i],valign:'center',halign:(typeof prop['chart.text.angle']==='number'&&prop['chart.text.angle']!==0)?'right':'center',tag:'scale',angle:-1*prop['chart.text.angle']});}
52
+ for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{font:font,size:text_size,x:this.gutterLeft+((this.graphwidth/2)*((i+1)/this.scale2.labels.length))+(this.graphwidth/2)+offsetx,y:this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,text:this.scale2.labels[i],valign:'center',halign:prop['chart.text.angle']!==0?'right':'center',tag:'scale',angle:-1*prop['chart.text.angle']});}}else if(prop['chart.yaxispos']=='right'){for(var i=0,len=this.scale2.labels.length;i<len;++i){RG.Text2(this,{'font':font,'size':text_size,'x':this.gutterLeft+(i*(this.graphwidth/len))+offsetx,'y':this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,'text':'-'+this.scale2.labels[len-1-i],'valign':'center','halign':prop['chart.text.angle']!==0?'right':'center','tag':'scale',angle:-1*prop['chart.text.angle']});}}else{for(var i=0,len=this.scale2.labels.length;i<len;++i){RG.Text2(this,{font:font,size:text_size,x:this.gutterLeft+(this.graphwidth*((i+1)/len))+offsetx,y:this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,text:this.scale2.labels[i],valign:'center',halign:prop['chart.text.angle']!==0?'right':'center',tag:'scale',angle:-1*prop['chart.text.angle']});}}
53
+ if(prop['chart.xmin']>0||prop['chart.noyaxis']==true||prop['chart.scale.zerostart']||prop['chart.noaxes']){var x=prop['chart.yaxispos']=='center'?this.gutterLeft+(this.graphwidth/2):this.gutterLeft;if(prop['chart.yaxispos']==='right'){var x=ca.width-this.gutterRight;}
54
+ RG.text2(this,{'font':font,'size':text_size,'x':x+offsetx,'y':this.gutterTop+this.halfTextHeight+this.graphheight+gap+offsety,'text':RG.numberFormat(this,prop['chart.xmin'].toFixed(prop['chart.xmin']===0?0:prop['chart.scale.decimals']),units_pre,units_post),'valign':'center',halign:prop['chart.text.angle']!==0?'right':'center','tag':'scale',angle:-1*prop['chart.text.angle']});}
55
+ co.fill();co.stroke();}}
56
+ if(typeof prop['chart.labels']=='object'){var xOffset=prop['chart.variant']==='3d'&&prop['chart.yaxispos']==='right'?15:5,font=prop['chart.text.font'],color=prop['chart.labels.color']||prop['chart.text.color'],bold=prop['chart.labels.bold'],offsetx=prop['chart.labels.offsetx'],offsety=prop['chart.labels.offsety']
57
+ co.fillStyle=color;var barHeight=(ca.height-this.gutterTop-this.gutterBottom)/prop['chart.labels'].length;yTickGap=(ca.height-this.gutterTop-this.gutterBottom)/prop['chart.labels'].length
58
+ if(prop['chart.yaxispos']==='right'){var x=ca.width-this.gutterRight+xOffset;var halign='left'}else{var x=this.gutterLeft-xOffset;var halign='right'}
59
+ var i=0;for(y=this.gutterTop+(yTickGap/2);y<=ca.height-this.gutterBottom;y+=yTickGap){RG.text2(this,{'font':font,'size':prop['chart.text.size'],'bold':bold,'x':x+offsetx,'y':y+offsety,'text':String(prop['chart.labels'][i++]),'halign':halign,'valign':'center','tag':'labels'});}}};this.drawbars=this.Drawbars=function()
60
+ {co.lineWidth=prop['chart.linewidth'];co.strokeStyle=prop['chart.strokestyle'];co.fillStyle=prop['chart.colors'][0];var prevX=0,prevY=0;if(prop['chart.xmax']){this.scale2=RG.getScale2(this,{'max':prop['chart.xmax'],'min':prop['chart.xmin'],'scale.decimals':Number(prop['chart.scale.decimals']),'scale.point':prop['chart.scale.point'],'scale.thousand':prop['chart.scale.thousand'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post'],'ylabels.count':prop['chart.xlabels.count'],'strict':true});this.max=this.scale2.max;}else{var grouping=prop['chart.grouping'];for(i=0;i<this.data.length;++i){if(typeof(this.data[i])=='object'){var value=grouping=='grouped'?Number(RG.array_max(this.data[i],true)):Number(RG.array_sum(this.data[i]));}else{var value=Number(ma.abs(this.data[i]));}
61
+ this.max=ma.max(Math.abs(this.max),Math.abs(value));}
62
+ this.scale2=RG.getScale2(this,{'max':this.max,'min':prop['chart.xmin'],'scale.decimals':Number(prop['chart.scale.decimals']),'scale.point':prop['chart.scale.point'],'scale.thousand':prop['chart.scale.thousand'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post'],'ylabels.count':prop['chart.xlabels.count']});this.max=this.scale2.max;this.min=this.scale2.min;}
63
+ if(prop['chart.scale.decimals']==null&&Number(this.max)==1){this.Set('chart.scale.decimals',1);}
64
+ var colorIdx=0;this.numbars=RG.arrayLinearize(this.data).length;if(prop['chart.adjustable']&&!prop['chart.xmax']){this.set('chart.xmax',this.scale2.max);}
65
+ if(prop['chart.variant']==='3d'){RG.draw3DAxes(this);}
66
+ var graphwidth=(ca.width-this.gutterLeft-this.gutterRight);var halfwidth=graphwidth/2;for(i=(len=this.data.length-1);i>=0;--i){var width=ma.abs((this.data[i]/this.max)*graphwidth);var height=this.graphheight/this.data.length;var orig_height=height;var x=this.gutterLeft;var y=this.gutterTop+(i*height);var vmargin=prop['chart.vmargin'];if(prop['chart.yaxispos']==='right'){x=ca.width-this.gutterRight-ma.abs(width);}
67
+ if(width<0){x-=width;width=ma.abs(width);}
68
+ if(prop['chart.shadow']){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];}
69
+ co.beginPath();if(typeof this.data[i]=='number'||RG.isNull(this.data[i])){var barHeight=height-(2*vmargin),barWidth=((this.data[i]-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*this.graphwidth,barX=this.gutterLeft;if(prop['chart.yaxispos']=='center'){barWidth/=2;barX+=halfwidth;if(this.data[i]<0){barWidth=(ma.abs(this.data[i])-prop['chart.xmin'])/(this.max-prop['chart.xmin']);barWidth=barWidth*(this.graphwidth/2);barX=((this.graphwidth/2)+this.gutterLeft)-barWidth;}}else if(prop['chart.yaxispos']=='right'){barWidth=ma.abs(barWidth);barX=ca.width-this.gutterRight-barWidth;}
70
+ co.strokeStyle=prop['chart.strokestyle'];co.fillStyle=prop['chart.colors'][0];++colorIdx;if(prop['chart.colors.sequential']&&typeof colorIdx==='number'){if(prop['chart.colors'][this.numbars-colorIdx]){co.fillStyle=prop['chart.colors'][this.numbars-colorIdx];}else{co.fillStyle=prop['chart.colors'][prop['chart.colors'].length-1];}}
71
+ co.strokeRect(barX,this.gutterTop+(i*height)+prop['chart.vmargin'],barWidth,barHeight);co.fillRect(barX,this.gutterTop+(i*height)+prop['chart.vmargin'],barWidth,barHeight);this.coords.push([barX,y+vmargin,barWidth,height-(2*vmargin),co.fillStyle,this.data[i],true]);if(prop['chart.variant']==='3d'&&typeof this.data[i]=='number'){var prevStrokeStyle=co.strokeStyle,prevFillStyle=co.fillStyle;RG.noShadow(this);var barX=barX,barY=y+vmargin,barW=barWidth,barH=height-(2*vmargin),offsetX=prop['chart.variant.threed.offsetx'],offsetY=prop['chart.variant.threed.offsety'],value=this.data[i];pa2(co,['b','m',barX,barY,'l',barX+offsetX-(prop['chart.yaxispos']=='left'&&value<0?offsetX:0),barY-offsetY,'l',barX+barW+offsetX-(prop['chart.yaxispos']=='center'&&value<0?offsetX:0),barY-offsetY,'l',barX+barW,barY,'c','s',co.strokeStyle,'f',co.fillStyle,'f','rgba(255,255,255,0.6)']);if(prop['chart.yaxispos']!=='right'&&!(prop['chart.yaxispos']==='center'&&value<0)&&value>=0&&!RG.isNull(value)){pa2(co,['b','fs',prevFillStyle,'m',barX+barW,barY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY+barH,'l',barX+barW,barY+barH,'c','s',co.strokeStyle,'f',prevFillStyle,'f','rgba(0,0,0,0.25)']);}}}else if(typeof(this.data[i])=='object'&&prop['chart.grouping']=='stacked'){if(prop['chart.yaxispos']=='center'){alert('[HBAR] You can\'t have a stacked chart with the Y axis in the center, change it to grouped');}else if(prop['chart.yaxispos']=='right'){var x=ca.width-this.gutterRight}
72
+ var barHeight=height-(2*vmargin);if(typeof this.coords2[i]=='undefined'){this.coords2[i]=[];}
73
+ for(j=0;j<this.data[i].length;++j){if(prop['chart.shadow']&&prop['chart.variant']==='3d'){co.shadowColor=prop['chart.shadow.color'];co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];}
74
+ if(!RG.isNull(this.data[i][j]))this.data[i][j]=ma.abs(this.data[i][j]);var last=(j===(this.data[i].length-1));co.strokeStyle=prop['chart.strokestyle'];++colorIdx;if(prop['chart.colors.sequential']&&typeof colorIdx==='number'){if(prop['chart.colors'][this.numbars-colorIdx]){co.fillStyle=prop['chart.colors'][this.numbars-colorIdx];}else{co.fillStyle=prop['chart.colors'][prop['chart.colors'].length-1];}}else if(prop['chart.colors'][j]){co.fillStyle=prop['chart.colors'][j];}
75
+ var width=(((this.data[i][j])/(this.max)))*this.graphwidth;var totalWidth=(RG.arraySum(this.data[i])/this.max)*this.graphwidth;if(prop['chart.yaxispos']==='right'){x-=width;}
76
+ co.strokeRect(x,this.gutterTop+prop['chart.vmargin']+(this.graphheight/this.data.length)*i,width,height-(2*vmargin));co.fillRect(x,this.gutterTop+prop['chart.vmargin']+(this.graphheight/this.data.length)*i,width,height-(2*vmargin));this.coords.push([x,y+vmargin,width,height-(2*vmargin),co.fillStyle,RG.array_sum(this.data[i]),j==(this.data[i].length-1)]);this.coords2[i].push([x,y+vmargin,width,height-(2*vmargin),co.fillStyle,RG.array_sum(this.data[i]),j==(this.data[i].length-1)]);if(prop['chart.variant']==='3d'){RG.noShadow(this);var prevStrokeStyle=co.strokeStyle,prevFillStyle=co.fillStyle;var barX=x,barY=y+vmargin,barW=width,barH=height-(2*vmargin),offsetX=prop['chart.variant.threed.offsetx'],offsetY=prop['chart.variant.threed.offsety'],value=this.data[i][j];if(!RG.isNull(value)){pa2(co,['b','m',barX,barY,'l',barX+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW,barY,'c','s',co.strokeStyle,'f',co.fillStyle,'f','rgba(255,255,255,0.6)']);}
77
+ if(prop['chart.yaxispos']!=='right'&&!(prop['chart.yaxispos']==='center'&&value<0)&&!RG.isNull(value)){pa2(co,['fs',prevFillStyle,'b','m',barX+barW,barY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY+barH,'l',barX+barW,barY+barH,'c','s',co.strokeStyle,'f',prevFillStyle,'f','rgba(0,0,0,0.25)']);}
78
+ co.beginPath();co.strokeStyle=prevStrokeStyle;co.fillStyle=prevFillStyle;}
79
+ if(prop['chart.yaxispos']!=='right'){x+=width;}}}else if(typeof(this.data[i])=='object'&&prop['chart.grouping']=='grouped'){var vmarginGrouped=prop['chart.vmargin.grouped'];var individualBarHeight=((height-(2*vmargin)-((this.data[i].length-1)*vmarginGrouped))/this.data[i].length)
80
+ if(typeof this.coords2[i]=='undefined'){this.coords2[i]=[];}
81
+ for(j=(this.data[i].length-1);j>=0;--j){if(prop['chart.shadow']){RG.setShadow(this,prop['chart.shadow.color'],prop['chart.shadow.offsetx'],prop['chart.shadow.offsety'],prop['chart.shadow.blur']);}
82
+ co.strokeStyle=prop['chart.strokestyle'];++colorIdx;if(prop['chart.colors.sequential']&&typeof colorIdx==='number'){if(prop['chart.colors'][this.numbars-colorIdx]){co.fillStyle=prop['chart.colors'][this.numbars-colorIdx];}else{co.fillStyle=prop['chart.colors'][prop['chart.colors'].length-1];}}else if(prop['chart.colors'][j]){co.fillStyle=prop['chart.colors'][j];}
83
+ var startY=this.gutterTop+(height*i)+(individualBarHeight*j)+vmargin+(vmarginGrouped*j);var width=((this.data[i][j]-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*(ca.width-this.gutterLeft-this.gutterRight);var startX=this.gutterLeft;if(prop['chart.yaxispos']=='center'){width/=2;startX+=halfwidth;}else if(prop['chart.yaxispos']=='right'){width=ma.abs(width);startX=ca.width-this.gutterRight-ma.abs(width);;}
84
+ if(width<0){startX+=width;width*=-1;}
85
+ co.strokeRect(startX,startY,width,individualBarHeight);co.fillRect(startX,startY,width,individualBarHeight);this.coords.push([startX,startY,width,individualBarHeight,co.fillStyle,this.data[i][j],true]);this.coords2[i].push([startX,startY,width,individualBarHeight,co.fillStyle,this.data[i][j],true]);if(prop['chart.variant']==='3d'){RG.noShadow(this);var prevStrokeStyle=co.strokeStyle,prevFillStyle=co.fillStyle;var barX=startX,barY=startY,barW=width,barH=individualBarHeight,offsetX=prop['chart.variant.threed.offsetx'],offsetY=prop['chart.variant.threed.offsety'],value=this.data[i][j];pa2(co,['b','m',barX,barY,'l',barX+offsetX,barY-offsetY,'l',barX+barW+offsetX-(value<0?offsetX:0),barY-offsetY,'l',barX+barW,barY,'c','s',co.strokeStyle,'f',co.fillStyle,'f','rgba(255,255,255,0.6)']);if(prop['chart.yaxispos']!=='right'&&!(prop['chart.yaxispos']==='center'&&value<0)&&value>=0&&!RG.isNull(value)){pa2(co,['fs',prevFillStyle,'b','m',barX+barW,barY,'l',barX+barW+offsetX,barY-offsetY,'l',barX+barW+offsetX,barY-offsetY+barH,'l',barX+barW,barY+barH,'c','s',co.strokeStyle,'f',prevFillStyle,'f','rgba(0,0,0,0.25)']);}
86
+ co.beginPath();co.strokeStyle=prevStrokeStyle;co.fillStyle=prevFillStyle;}}
87
+ startY+=vmargin;}
88
+ co.closePath();}
89
+ co.stroke();co.fill();if(prop['chart,yaxispos']==='right'){pa2(co,'cr % % % %',ca.width-this.gutterRight+prop['chart.variant.threed.offsetx'],'0',this.gutterRight,ca.height);}
90
+ if(prop['chart.yaxispos']==='right'&&prop['chart.variant']==='3d'){RG.draw3DYAxis(this);}
91
+ RG.noShadow(this);this.coords=RG.arrayReverse(this.coords);if(prop['chart.grouping']==='grouped'){for(var i=0;i<this.coords2.length;++i){this.coords2[i]=RG.arrayReverse(this.coords2[i]);}}
92
+ this.redrawBars();};this.redrawBars=this.RedrawBars=function()
93
+ {if(prop['chart.noredraw']){return;}
94
+ var coords=this.coords;var font=prop['chart.text.font'],size=prop['chart.text.size'],color=prop['chart.text.color'];RG.noShadow(this);co.strokeStyle=prop['chart.strokestyle'];for(var i=0;i<coords.length;++i){if(prop['chart.shadow']){pa2(co,'b lw % r % % % % s % f %',prop['chart.linewidth'],coords[i][0],coords[i][1],coords[i][2],coords[i][3],prop['chart.strokestyle'],coords[i][4]);}
95
+ var halign='left';if(prop['chart.labels.above']&&coords[i][6]){var border=(coords[i][0]+coords[i][2]+7+co.measureText(prop['chart.labels.above.units.pre']+this.coords[i][5]+prop['chart.labels.above.units.post']).width)>ca.width?true:false,text=RG.numberFormat(this,(this.coords[i][5]).toFixed(prop['chart.labels.above.decimals']),prop['chart.labels.above.units.pre'],prop['chart.labels.above.units.post']);RG.noShadow(this);if(typeof prop['chart.labels.above.specific']==='object'&&prop['chart.labels.above.specific']&&prop['chart.labels.above.specific'][i]){text=prop['chart.labels.above.specific'][i];}
96
+ var x=coords[i][0]+coords[i][2]+5;var y=coords[i][1]+(coords[i][3]/2);if(prop['chart.yaxispos']==='right'){x=coords[i][0]-5;halign='right';}else if(prop['chart.yaxispos']==='center'&&this.data_arr[i]<0){x=coords[i][0]-5;halign='right';}
97
+ RG.text2(this,{font:typeof prop['chart.labels.above.font']==='string'?prop['chart.labels.above.font']:font,size:typeof prop['chart.labels.above.size']==='number'?prop['chart.labels.above.size']:size,color:typeof prop['chart.labels.above.color']==='string'?prop['chart.labels.above.color']:color,x:x,y:y,bold:prop['chart.labels.above.bold'],italic:prop['chart.labels.above.italic'],text:text,valign:'center',halign:halign,tag:'labels.above'});}}};this.getShape=this.getBar=function(e)
98
+ {var mouseXY=RG.getMouseXY(e);for(var i=0,len=this.coords.length;i<len;i++){var mouseX=mouseXY[0],mouseY=mouseXY[1],left=this.coords[i][0],top=this.coords[i][1],width=this.coords[i][2],height=this.coords[i][3],idx=i;pa2(co,['b','r',left,top,width,height]);if(co.isPointInPath(mouseX,mouseY)){var tooltip=RG.parseTooltipText(prop['chart.tooltips'],i);return{0:this,'object':this,1:left,'x':left,2:top,'y':top,3:width,'width':width,4:height,'height':height,5:idx,'index':idx,'tooltip':tooltip};}}};this.getValue=function(arg)
99
+ {if(arg.length==2){var mouseX=arg[0];var mouseY=arg[1];}else{var mouseCoords=RG.getMouseXY(arg);var mouseX=mouseCoords[0];var mouseY=mouseCoords[1];}
100
+ if(mouseY<this.gutterTop||mouseY>(ca.height-this.gutterBottom)||mouseX<this.gutterLeft||mouseX>(ca.width-this.gutterRight)){return null;}
101
+ if(prop['chart.yaxispos']=='center'){var value=((mouseX-this.gutterLeft)/(this.graphwidth/2))*(this.max-prop['chart.xmin']);value=value-this.max
102
+ if(prop['chart.xmin']>0){value=((mouseX-this.gutterLeft-(this.graphwidth/2))/(this.graphwidth/2))*(this.max-prop['chart.xmin']);value+=prop['chart.xmin'];if(mouseX<(this.gutterLeft+(this.graphwidth/2))){value-=(2*prop['chart.xmin']);}}}else if(prop['chart.yaxispos']=='right'){var value=((mouseX-this.gutterLeft)/this.graphwidth)*(this.scale2.max-prop['chart.xmin']);value=this.scale2.max-value;}else{var value=((mouseX-this.gutterLeft)/this.graphwidth)*(this.scale2.max-prop['chart.xmin']);value+=prop['chart.xmin'];}
103
+ return value;};this.highlight=this.Highlight=function(shape)
104
+ {if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else{RG.Highlight.Rect(this,shape);}};this.getObjectByXY=function(e)
105
+ {var mouseXY=RG.getMouseXY(e);if(prop['chart.variant']==='3d'){var adjustment=prop['chart.variant.threed.angle']*mouseXY[0];mouseXY[1]-=adjustment;}
106
+ if(mouseXY[0]>=this.gutterLeft&&mouseXY[0]<=(ca.width-this.gutterRight)&&mouseXY[1]>=this.gutterTop&&mouseXY[1]<=(ca.height-this.gutterBottom)){return this;}};this.getXCoord=function(value)
107
+ {if(prop['chart.yaxispos']=='center'){if(value>this.max||value<(-1*this.max)){return null;}
108
+ var width=(ca.width-prop['chart.gutter.left']-prop['chart.gutter.right'])/2;var coord=(((value-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*width)+width;coord=prop['chart.gutter.left']+coord;}else{if(value>this.max||value<0){return null;}
109
+ var width=ca.width-prop['chart.gutter.left']-prop['chart.gutter.right'];var coord=((value-prop['chart.xmin'])/(this.max-prop['chart.xmin']))*width;coord=prop['chart.gutter.left']+coord;}
110
+ return coord;};this.parseColors=function()
111
+ {if(this.original_colors.length===0){this.original_colors['chart.colors']=RG.array_clone(prop['chart.colors']);this.original_colors['chart.background.grid.color']=RG.array_clone(prop['chart.background.grid.color']);this.original_colors['chart.background.color']=RG.array_clone(prop['chart.background.color']);this.original_colors['chart.background.barcolor1']=RG.array_clone(prop['chart.background.barcolor1']);this.original_colors['chart.background.barcolor2']=RG.array_clone(prop['chart.background.barcolor2']);this.original_colors['chart.text.color']=RG.array_clone(prop['chart.text.color']);this.original_colors['chart.labels.colors']=RG.array_clone(prop['chart.labels.colors']);this.original_colors['chart.strokestyle']=RG.array_clone(prop['chart.strokestyle']);this.original_colors['chart.axis.color']=RG.array_clone(prop['chart.axis.color']);this.original_colors['chart.highlight.fill']=RG.array_clone(prop['chart.highlight.fill']);this.original_colors['chart.highlight.stroke']=RG.array_clone(prop['chart.highlight.stroke']);}
112
+ var colors=prop['chart.colors'];for(var i=0;i<colors.length;++i){colors[i]=this.parseSingleColorForGradient(colors[i]);}
113
+ prop['chart.background.grid.color']=this.parseSingleColorForGradient(prop['chart.background.grid.color']);prop['chart.background.color']=this.parseSingleColorForGradient(prop['chart.background.color']);prop['chart.background.barcolor1']=this.parseSingleColorForGradient(prop['chart.background.barcolor1']);prop['chart.background.barcolor2']=this.parseSingleColorForGradient(prop['chart.background.barcolor2']);prop['chart.text.color']=this.parseSingleColorForGradient(prop['chart.text.color']);prop['chart.labels.colors']=this.parseSingleColorForGradient(prop['chart.labels.colors']);prop['chart.strokestyle']=this.parseSingleColorForGradient(prop['chart.strokestyle']);prop['chart.axis.color']=this.parseSingleColorForGradient(prop['chart.axis.color']);prop['chart.highlight.fill']=this.parseSingleColorForGradient(prop['chart.highlight.fill']);prop['chart.highlight.stroke']=this.parseSingleColorForGradient(prop['chart.highlight.stroke']);};this.reset=function()
114
+ {};this.parseSingleColorForGradient=function(color)
115
+ {if(!color||typeof(color)!='string'){return color;}
116
+ if(color.match(/^gradient\((.*)\)$/i)){var parts=RegExp.$1.split(':');if(prop['chart.yaxispos']==='right'){parts=RG.arrayReverse(parts);}
117
+ var grad=co.createLinearGradient(prop['chart.gutter.left'],0,ca.width-prop['chart.gutter.right'],0);var diff=1/(parts.length-1);grad.addColorStop(0,RG.trim(parts[0]));for(var j=1;j<parts.length;++j){grad.addColorStop(j*diff,RG.trim(parts[j]));}}
118
+ return grad?grad:color;};this.interactiveKeyHighlight=function(index)
119
+ {var obj=this;this.coords2.forEach(function(value,idx,arr)
120
+ {var shape=obj.coords2[idx][index]
121
+ var pre_linewidth=co.lineWidth;co.lineWidth=2;co.fillStyle=prop['chart.key.interactive.highlight.chart.fill'];co.strokeStyle=prop['chart.key.interactive.highlight.chart.stroke'];co.fillRect(shape[0],shape[1],shape[2],shape[3]);co.strokeRect(shape[0],shape[1],shape[2],shape[3]);co.lineWidth=pre_linewidth;});};this.on=function(type,func)
122
+ {if(type.substr(0,2)!=='on'){type='on'+type;}
123
+ if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
124
+ return this;};this.firstDrawFunc=function()
125
+ {};this.getShapeByY=function(e)
126
+ {var mouseXY=RG.getMouseXY(e);var obj=arguments[1]?arguments[1]:this;for(var i=0,len=obj.coords.length;i<len;i++){if(obj.coords[i].length==0){continue;}
127
+ var mouseX=mouseXY[0],mouseY=mouseXY[1],left=obj.coords[i][0],top=obj.coords[i][1],width=obj.coords[i][2],height=obj.coords[i][3];if(mouseY>=top&&mouseY<=(top+height)){if(prop['chart.tooltips']){var tooltip=RG.parseTooltipText?RG.parseTooltipText(prop['chart.tooltips'],i):prop['chart.tooltips'][i];}
128
+ return{0:obj,object:obj,1:left,x:left,2:top,y:top,3:width,width:width,4:height,height:height,5:i,index:i,tooltip:tooltip};}}
129
+ return null;};this.adjusting_mousemove=this.Adjusting_mousemove=function(e)
130
+ {if(prop['chart.adjustable']&&RG.Registry.get('chart.adjusting')&&RG.Registry.get('chart.adjusting').uid==this.uid){var value=Number(this.getValue(e)),shape=RG.Registry.get('chart.adjusting.shape');if(shape){RG.Registry.Set('chart.adjusting.shape',shape);if(this.stackedOrGrouped&&prop['chart.grouping']=='grouped'){var indexes=RG.sequentialIndexToGrouped(shape['index'],this.data);if(typeof this.data[indexes[0]]=='number'){this.data[indexes[0]]=Number(value);}else if(!RG.is_null(this.data[indexes[0]])){this.data[indexes[0]][indexes[1]]=Number(value);}}else if(typeof this.data[shape['index']]=='number'){this.data[shape['index']]=Number(value);}
131
+ RG.redrawCanvas(e.target);RG.fireCustomEvent(this,'onadjust');}}};this.grow=function()
132
+ {var obj=this,opt=arguments[0]||{},frames=opt.frames||30,frame=0,callback=arguments[1]||function(){},labelsAbove=prop['chart.labels.above'];this.set('labelsAbove',false);obj.original_data=RG.arrayClone(obj.data);if(prop['chart.xmax']==0){var xmax=0;for(var i=0;i<obj.data.length;++i){if(RG.isArray(obj.data[i])&&prop['chart.grouping']=='stacked'){xmax=ma.max(xmax,RG.arraySum(obj.data[i]));}else if(RG.isArray(obj.data[i])&&prop['chart.grouping']=='grouped'){xmax=ma.max(xmax,RG.arrayMax(obj.data[i]));}else{xmax=ma.max(xmax,ma.abs(RG.arrayMax(obj.data[i])));}}
133
+ var scale2=RG.getScale2(obj,{'max':xmax});obj.Set('chart.xmax',scale2.max);}
134
+ function iterator()
135
+ {for(var j=0,len=obj.original_data.length;j<len;++j){var easingFactor=RG.Effects.getEasingMultiplier(frames,frame);if(typeof obj.data[j]==='object'&&obj.data[j]){for(var k=0,len2=obj.data[j].length;k<len2;++k){obj.data[j][k]=RG.isNull(obj.data[j][k])?null:obj.original_data[j][k]*easingFactor;}}else{obj.data[j]=RG.isNull(obj.data[j])?null:obj.original_data[j]*easingFactor;}}
136
+ RG.redrawCanvas(obj.canvas);if(frame<frames){frame+=1;RG.Effects.updateCanvas(iterator);}else{if(labelsAbove){obj.set('labelsAbove',true);RG.redraw();}
137
+ callback(obj);}}
138
+ iterator();return this;};this.grow=function()
139
+ {var opt=arguments[0]||{},frames=opt.frames||30,frame=0,callback=arguments[1]||function(){},obj=this,labelsAbove=this.get('labelsAbove')
140
+ this.original_data=RG.arrayClone(this.data);if(prop['chart.xmax']==0){var xmax=0;for(var i=0;i<obj.data.length;++i){if(RG.isArray(obj.data[i])&&prop['chart.grouping']=='stacked'){xmax=ma.max(xmax,RG.arraySum(obj.data[i]));}else if(RG.isArray(obj.data[i])&&prop['chart.grouping']=='grouped'){xmax=ma.max(xmax,RG.arrayMax(obj.data[i]));}else{xmax=ma.max(xmax,ma.abs(RG.arrayMax(obj.data[i])));}}
141
+ var scale2=RG.getScale2(obj,{'max':xmax});obj.Set('chart.xmax',scale2.max);}
142
+ if(RG.isArray(opt.data)){var xmax=0;for(var i=0;i<opt.data.length;++i){if(typeof opt.data[i]==='object'){for(var j=0;j<opt.data[i].length;++j){if(typeof opt.data[i][j]==='string'&&opt.data[i][j].match(/(\+|\-)([0-9]+)/)){if(RegExp.$1==='+'){opt.data[i][j]=this.original_data[i][j]+parseInt(RegExp.$2);}else{opt.data[i][j]=this.original_data[i][j]-parseInt(RegExp.$2);}}
143
+ xmax=ma.max(xmax,opt.data[i][j]);}}else if(typeof opt.data[i]==='string'&&opt.data[i].match(/(\+|\-)([0-9]+)/)){if(RegExp.$1==='+'){opt.data[i]=this.original_data[i]+parseFloat(RegExp.$2);}else{opt.data[i]=this.original_data[i]-parseFloat(RegExp.$2);}
144
+ xmax=ma.max(xmax,opt.data[i]);}else{xmax=ma.max(xmax,opt.data[i]);}}
145
+ var scale=RG.getScale2(this,{'max':xmax});if(typeof this.get('chart.xmax')==='null'){this.set('chart.xmax',scale.max);}}
146
+ this.set('labelsAbove',false);if(RG.isNull(prop['chart.xmax'])){var xmax=0;for(var i=0;i<obj.data.length;++i){if(RG.isArray(this.data[i])&&prop['chart.grouping']==='stacked'){xmax=ma.max(xmax,ma.abs(RG.arraySum(this.data[i])));}else if(RG.isArray(this.data[i])&&prop['chart.grouping']==='grouped'){for(var j=0,group=[];j<this.data[i].length;j++){group.push(ma.abs(this.data[i][j]));}
147
+ xmax=ma.max(xmax,ma.abs(RG.arrayMax(group)));}else{xmax=ma.max(xmax,ma.abs(this.data[i]));}}
148
+ var scale=RG.getScale2(this,{'max':xmax});this.Set('chart.xmax',scale.max);}
149
+ if(typeof opt.xmax==='number'){obj.set('xmax',opt.xmax);}
150
+ var iterator=function()
151
+ {var easingMultiplier=RG.Effects.getEasingMultiplier(frames,frame);for(var j=0,len=obj.original_data.length;j<len;++j){if(typeof obj.data[j]==='object'&&!RG.isNull(obj.data[j])){for(var k=0,len2=obj.data[j].length;k<len2;++k){if(obj.firstDraw||!opt.data){obj.data[j][k]=easingMultiplier*obj.original_data[j][k];}else if(opt.data&&opt.data.length===obj.original_data.length){var diff=opt.data[j][k]-obj.original_data[j][k];obj.data[j][k]=(easingMultiplier*diff)+obj.original_data[j][k];}}}else{if(obj.firstDraw||!opt.data){obj.data[j]=easingMultiplier*obj.original_data[j];}else if(opt.data&&opt.data.length===obj.original_data.length){var diff=opt.data[j]-obj.original_data[j];obj.data[j]=(easingMultiplier*diff)+obj.original_data[j];}}}
152
+ RG.redrawCanvas(obj.canvas);if(frame<frames){frame+=1;RG.Effects.updateCanvas(iterator);}else{if(RG.isArray(opt.data)){var linear_data=RG.arrayLinearize(data);for(var i=0;i<linear_data.length;++i){if(!obj['$'+i]){obj['$'+i]={};}}}
153
+ obj.data=data;obj.original_data=RG.arrayClone(data);if(labelsAbove){obj.set('labelsAbove',true);RG.redraw();}
154
+ callback(obj);}};iterator();return this;};this.wave=function()
155
+ {var obj=this,opt=arguments[0]||{};opt.frames=opt.frames||60;opt.startFrames=[];opt.counters=[];var framesperbar=opt.frames/3,frame=-1,callback=arguments[1]||function(){},original=RG.arrayClone(obj.data),labelsAbove=prop['chart.labels.above'];this.set('labelsAbove',false);for(var i=0,len=obj.data.length;i<len;i+=1){opt.startFrames[i]=((opt.frames/2)/(obj.data.length-1))*i;if(typeof obj.data[i]==='object'&&obj.data[i]){opt.counters[i]=[];for(var j=0;j<obj.data[i].length;j++){opt.counters[i][j]=0;}}else{opt.counters[i]=0;}}
156
+ obj.draw();obj.Set('xmax',obj.scale2.max);RG.clear(obj.canvas);function iterator()
157
+ {++frame;for(var i=0,len=obj.data.length;i<len;i+=1){if(frame>opt.startFrames[i]){if(typeof obj.data[i]==='number'){obj.data[i]=ma.min(ma.abs(original[i]),ma.abs(original[i]*((opt.counters[i]++)/framesperbar)));if(original[i]<0){obj.data[i]*=-1;}}else if(!RG.isNull(obj.data[i])){for(var j=0,len2=obj.data[i].length;j<len2;j+=1){obj.data[i][j]=ma.min(ma.abs(original[i][j]),ma.abs(original[i][j]*((opt.counters[i][j]++)/framesperbar)));if(original[i][j]<0){obj.data[i][j]*=-1;}}}}else{obj.data[i]=typeof obj.data[i]==='object'&&obj.data[i]?RG.arrayPad([],obj.data[i].length,0):(RG.isNull(obj.data[i])?null:0);}}
158
+ if(frame>=opt.frames){if(labelsAbove){obj.set('labelsAbove',true);RG.redrawCanvas(obj.canvas);}
159
+ callback(obj);}else{RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iterator);}}
160
+ iterator();return this;};this.isAdjustable=function(shape)
161
+ {if(RG.isNull(prop['chart.adjustable.only'])){return true;}
162
+ if(RG.isArray(prop['chart.adjustable.only'])&&prop['chart.adjustable.only'][shape.index]){return true;}
163
+ return false;};RG.Register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}};