rgraph-rails 1.0.5 → 1.0.6

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