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,3765 +1,240 @@
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 99GBP 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
-
21
-
22
- /**
23
- * The bar chart constructor
24
- *
25
- * @param object canvas The canvas object
26
- * @param array data The chart data
27
- */
28
- RGraph.Bar = function (conf)
29
- {
30
- /**
31
- * Allow for object config style
32
- */
33
- if (typeof conf === 'object' && typeof conf.data === 'object'&& typeof conf.id === 'string') {
34
- var id = conf.id,
35
- canvas = document.getElementById(id),
36
- data = conf.data,
37
- parseConfObjectForOptions = true // Set this so the config is parsed (at the end of the constructor)
38
- } else {
39
- var id = conf,
40
- canvas = document.getElementById(id),
41
- data = arguments[1]
42
- }
43
-
44
-
45
-
46
-
47
- // Get the canvas and context objects
48
- this.id = id;
49
- this.canvas = canvas;
50
- this.context = this.canvas.getContext('2d');
51
- this.canvas.__object__ = this;
52
- this.type = 'bar';
53
- this.max = 0;
54
- this.stackedOrGrouped = false;
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.original_colors = [];
60
- this.cachedBackgroundCanvas = null;
61
- this.firstDraw = true; // After the first draw this will be false
62
-
63
-
64
- /**
65
- * Compatibility with older browsers
66
- */
67
- //RGraph.OldBrowserCompat(this.context);
68
-
69
-
70
- // Various config type stuff
71
- this.properties =
72
- {
73
- 'chart.background.barcolor1': 'rgba(0,0,0,0)',
74
- 'chart.background.barcolor2': 'rgba(0,0,0,0)',
75
- 'chart.background.grid': true,
76
- 'chart.background.grid.color': '#ddd',
77
- 'chart.background.grid.width': 1,
78
- 'chart.background.grid.hsize': 20,
79
- 'chart.background.grid.vsize': 20,
80
- 'chart.background.grid.vlines': true,
81
- 'chart.background.grid.hlines': true,
82
- 'chart.background.grid.border': true,
83
- 'chart.background.grid.autofit':true,
84
- 'chart.background.grid.autofit.align': true,
85
- 'chart.background.grid.autofit.numhlines': 5,
86
- 'chart.background.grid.autofit.numvlines': 20,
87
- 'chart.background.grid.dashed': false,
88
- 'chart.background.grid.dotted': false,
89
- 'chart.background.image.stretch': true,
90
- 'chart.background.image.x': null,
91
- 'chart.background.image.y': null,
92
- 'chart.background.image.w': null,
93
- 'chart.background.image.h': null,
94
- 'chart.background.image.align': null,
95
- 'chart.background.color': null,
96
- 'chart.background.hbars': null,
97
- 'chart.numyticks': 10,
98
- 'chart.hmargin': 5,
99
- 'chart.hmargin.grouped': 1,
100
- 'chart.strokecolor': 'rgba(0,0,0,0)',
101
- 'chart.axis.color': 'black',
102
- 'chart.axis.linewidth': 1,
103
- 'chart.gutter.top': 25,
104
- 'chart.gutter.bottom': 30,
105
- 'chart.gutter.left': 25,
106
- 'chart.gutter.right': 25,
107
- 'chart.labels': null,
108
- 'chart.labels.bold': false,
109
- 'chart.labels.color': null,
110
- 'chart.labels.ingraph': null,
111
- 'chart.labels.above': false,
112
- 'chart.labels.above.decimals': 0,
113
- 'chart.labels.above.size': null,
114
- 'chart.labels.above.color': null,
115
- 'chart.labels.above.background':'rgba(0,0,0,0)',
116
- 'chart.labels.above.angle': null,
117
- 'chart.labels.above.offset': 4,
118
- 'chart.labels.above.units.pre': '',
119
- 'chart.labels.above.units.post':'',
120
- 'chart.ylabels': true,
121
- 'chart.ylabels.count': 5,
122
- 'chart.ylabels.inside': false,
123
- 'chart.ylabels.offsetx': 0,
124
- 'chart.ylabels.offsety': 0,
125
- 'chart.labels.offsetx': 0,
126
- 'chart.labels.offsety': 0,
127
- 'chart.xaxispos': 'bottom',
128
- 'chart.yaxispos': 'left',
129
- 'chart.text.angle': 0,
130
- 'chart.text.color': 'black', // Gradients aren't supported for this color
131
- 'chart.text.size': 12,
132
- 'chart.text.font': 'Segoe UI, Arial, Verdana, sans-serif',
133
- 'chart.text.accessible': true,
134
- 'chart.text.accessible.overflow': 'visible',
135
- 'chart.text.accessible.pointerevents': false,
136
- 'chart.ymin': 0,
137
- 'chart.ymax': null,
138
- 'chart.title': '',
139
- 'chart.title.font': null,
140
- 'chart.title.background': null, // Gradients aren't supported for this color
141
- 'chart.title.hpos': null,
142
- 'chart.title.vpos': null,
143
- 'chart.title.bold': true,
144
- 'chart.title.xaxis': '',
145
- 'chart.title.xaxis.bold': true,
146
- 'chart.title.xaxis.size': null,
147
- 'chart.title.xaxis.font': null,
148
- 'chart.title.yaxis': '',
149
- 'chart.title.yaxis.bold': true,
150
- 'chart.title.yaxis.size': null,
151
- 'chart.title.yaxis.font': null,
152
- 'chart.title.yaxis.color': null, // Gradients aren't supported for this color
153
- 'chart.title.xaxis.pos': null,
154
- 'chart.title.yaxis.pos': null,
155
- 'chart.title.yaxis.x': null,
156
- 'chart.title.yaxis.y': null,
157
- 'chart.title.xaxis.x': null,
158
- 'chart.title.xaxis.y': null,
159
- 'chart.title.x': null,
160
- 'chart.title.y': null,
161
- 'chart.title.halign': null,
162
- 'chart.title.valign': null,
163
- 'chart.colors': [
164
- 'Gradient(#F9D5C9:#E65F2D:#E65F2D:#E65F2D)',
165
- 'Gradient(#F7DCD1:#D4592A:#D4592A:#D4592A)',
166
- 'Gradient(#DEE5EA:#B5C3CE:#B5C3CE:#B5C3CE)',
167
- 'Gradient(#E5E5E3:#545451:#545451:#545451)',
168
- 'Gradient(#F6E5D2:#E9C294:#E9C294:#E9C294)',
169
- 'Gradient(#F5EAD3:#D6AA4E:#D6AA4E:#D6AA4E)'
170
- ],
171
- 'chart.colors.sequential': false,
172
- 'chart.colors.reverse': false,
173
- 'chart.grouping': 'grouped',
174
- 'chart.variant': 'bar',
175
- 'chart.variant.sketch.verticals': true,
176
- 'chart.variant.threed.xaxis': true,
177
- 'chart.variant.threed.yaxis': true,
178
- 'chart.variant.threed.angle': 0.1,
179
- 'chart.variant.threed.offsetx': 10,
180
- 'chart.variant.threed.offsety': 5,
181
- 'chart.shadow': true,
182
- 'chart.shadow.color': '#aaa', // Gradients aren't supported for this color
183
- 'chart.shadow.offsetx': 0,
184
- 'chart.shadow.offsety': 0,
185
- 'chart.shadow.blur': 15,
186
- 'chart.tooltips': null,
187
- 'chart.tooltips.effect': 'fade',
188
- 'chart.tooltips.css.class': 'RGraph_tooltip',
189
- 'chart.tooltips.event': 'onclick',
190
- 'chart.tooltips.highlight': true,
191
- 'chart.tooltips.hotspot.xonly': false,
192
- 'chart.highlight.stroke': 'rgba(0,0,0,0)',
193
- 'chart.highlight.fill': 'rgba(255,255,255,0.7)',
194
- 'chart.key': null,
195
- 'chart.key.background': 'white',
196
- 'chart.key.position': 'graph',
197
- 'chart.key.shadow': false,
198
- 'chart.key.shadow.color': '#666',
199
- 'chart.key.shadow.blur': 3,
200
- 'chart.key.shadow.offsetx': 2,
201
- 'chart.key.shadow.offsety': 2,
202
- 'chart.key.position.gutter.boxed':false,
203
- 'chart.key.position.x': null,
204
- 'chart.key.position.y': null,
205
- 'chart.key.interactive': false,
206
- 'chart.key.interactive.highlight.chart.stroke':'black',
207
- 'chart.key.interactive.highlight.chart.fill':'rgba(255,255,255,0.7)',
208
- 'chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)',
209
- 'chart.key.halign': 'right',
210
- 'chart.key.color.shape': 'square',
211
- 'chart.key.rounded': true,
212
- 'chart.key.text.size': 10,
213
- 'chart.key.linewidth': 1,
214
- 'chart.key.colors': null,
215
- 'chart.key.text.color': 'black',
216
- 'chart.contextmenu': null,
217
- 'chart.units.pre': '',
218
- 'chart.units.post': '',
219
- 'chart.scale.decimals': 0,
220
- 'chart.scale.point': '.',
221
- 'chart.scale.thousand': ',',
222
- 'chart.scale.round': false,
223
- 'chart.scale.zerostart': true,
224
- 'chart.crosshairs': false,
225
- 'chart.crosshairs.color': '#333',
226
- 'chart.crosshairs.hline': true,
227
- 'chart.crosshairs.vline': true,
228
- 'chart.linewidth': 1,
229
- 'chart.annotatable': false,
230
- 'chart.annotate.color': 'black',
231
- 'chart.zoom.factor': 1.5,
232
- 'chart.zoom.fade.in': true,
233
- 'chart.zoom.fade.out': true,
234
- 'chart.zoom.hdir': 'right',
235
- 'chart.zoom.vdir': 'down',
236
- 'chart.zoom.frames': 25,
237
- 'chart.zoom.delay': 16.666,
238
- 'chart.zoom.shadow': true,
239
- 'chart.zoom.background': true,
240
- 'chart.resizable': false,
241
- 'chart.resize.handle.background': null,
242
- 'chart.adjustable': false,
243
- 'chart.noaxes': false,
244
- 'chart.noxaxis': false,
245
- 'chart.noyaxis': false,
246
- 'chart.events.click': null,
247
- 'chart.events.mousemove': null,
248
- 'chart.numxticks': null,
249
- 'chart.bevel': false,
250
- 'chart.errorbars': false,
251
- 'chart.errorbars.color': 'black',
252
- 'chart.errorbars.capped': true,
253
- 'chart.errorbars.capped.width': 14,
254
- 'chart.errorbars.linewidth': 1,
255
- 'chart.combinedchart.effect': null,
256
- 'chart.combinedchart.effect.options': null,
257
- 'chart.combinedchart.effect.callback': null,
258
- 'chart.clearto': 'rgba(0,0,0,0)'
259
- }
260
-
261
- // Check for support
262
- if (!this.canvas) {
263
- alert('[BAR] No canvas support');
264
- return;
265
- }
266
-
267
-
268
- //
269
- // Convert strings into numbers
270
- //
271
- for (var i=0; i<data.length; ++i) {
272
- if (typeof data[i] === 'string') {
273
- data[i] = parseFloat(data[i]);
274
- } else if (typeof data[i] === 'object' && data[i]) {
275
- for (var j=0; j<data[i].length; ++j) {
276
- if (typeof data[i][j] === 'string') {
277
- data[i][j] = parseFloat(data[i][j]);
278
- }
279
- }
280
- }
281
- }
282
-
283
- /**
284
- * Determine whether the chart will contain stacked or grouped bars
285
- */
286
- for (var i=0; i<data.length; ++i) {
287
- if (typeof data[i] === 'object' && !RGraph.is_null(data[i])) {
288
- this.stackedOrGrouped = true;
289
- }
290
- }
291
-
292
-
293
- /**
294
- * Create the dollar objects so that functions can be added to them
295
- */
296
- var linear_data = RGraph.array_linearize(data);
297
-
298
- for (var i=0; i<linear_data.length; ++i) {
299
- this['$' + i] = {};
300
- }
301
-
302
-
303
- // Store the data
304
- this.data = data;
305
-
306
- // Used to store the coords of the bars
307
- this.coords = [];
308
- this.coords2 = [];
309
- this.coordsText = [];
310
-
311
-
312
-
313
- /**
314
- * This linearises the data. Doing so can make it easier to pull
315
- * out the appropriate data from tooltips
316
- */
317
- this.data_arr = RGraph.array_linearize(this.data);
318
-
319
-
320
- /**
321
- * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
322
- * done already
323
- */
324
- if (!this.canvas.__rgraph_aa_translated__) {
325
- this.context.translate(0.5,0.5);
326
-
327
- this.canvas.__rgraph_aa_translated__ = true;
328
- }
329
-
330
-
331
-
332
-
333
-
334
- // Short variable names
335
- var RG = RGraph,
336
- ca = this.canvas,
337
- co = ca.getContext('2d'),
338
- prop = this.properties,
339
- pa2 = RG.path2,
340
- win = window,
341
- doc = document,
342
- ma = Math
343
-
344
-
345
-
346
- /**
347
- * "Decorate" the object with the generic effects if the effects library has been included
348
- */
349
- if (RG.Effects && typeof RG.Effects.decorate === 'function') {
350
- RG.Effects.decorate(this);
351
- }
352
-
353
-
354
-
355
-
356
-
357
- /**
358
- * A setter
359
- *
360
- * @param name string The name of the property to set
361
- * @param value mixed The value of the property
362
- */
363
- this.set =
364
- this.Set = function (name)
365
- {
366
- var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
367
-
368
- /**
369
- * the number of arguments is only one and it's an
370
- * object - parse it for configuration data and return.
371
- */
372
- if (arguments.length === 1 && typeof arguments[0] === 'object') {
373
- RG.parseObjectStyleConfig(this, arguments[0]);
374
- return this;
375
- }
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
- /**
385
- * This should be done first - prepend the propertyy name with "chart." if necessary
386
- */
387
- if (name.substr(0,6) != 'chart.') {
388
- name = 'chart.' + name;
389
- }
390
-
391
-
392
-
393
-
394
- // Convert uppercase letters to dot+lower case letter
395
- while(name.match(/([A-Z])/)) {
396
- name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
397
- }
398
-
399
-
400
- // BC accommodation
401
- if (name === 'chart.xlabels.offset') {
402
- name = 'chart.labels.offsety';
403
- }
404
-
405
- if (name == 'chart.labels.abovebar') {
406
- name = 'chart.labels.above';
407
- }
408
-
409
- if (name == 'chart.strokestyle') {
410
- name = 'chart.strokecolor';
411
- }
412
-
413
- /**
414
- * Check for xaxispos
415
- */
416
- if (name == 'chart.xaxispos' ) {
417
- if (value != 'bottom' && value != 'center' && value != 'top') {
418
- alert('[BAR] (' + this.id + ') chart.xaxispos should be top, center or bottom. Tried to set it to: ' + value + ' Changing it to center');
419
- value = 'center';
420
- }
421
-
422
- if (value == 'top') {
423
- for (var i=0; i<this.data.length; ++i) {
424
- if (typeof(this.data[i]) == 'number' && this.data[i] > 0) {
425
- alert('[BAR] The data element with index ' + i + ' should be negative');
426
- }
427
- }
428
- }
429
- }
430
-
431
- /**
432
- * lineWidth doesn't appear to like a zero setting
433
- */
434
- if (name.toLowerCase() == 'chart.linewidth' && value == 0) {
435
- value = 0.0001;
436
- }
437
-
438
-
439
-
440
-
441
-
442
-
443
- prop[name] = value;
444
-
445
- return this;
446
- };
447
-
448
-
449
-
450
-
451
- /**
452
- * A getter
453
- *
454
- * @param name string The name of the property to get
455
- */
456
- this.get =
457
- this.Get = function (name)
458
- {
459
- /**
460
- * This should be done first - prepend the property name with "chart." if necessary
461
- */
462
- if (name.substr(0,6) != 'chart.') {
463
- name = 'chart.' + name;
464
- }
465
-
466
- // Convert uppercase letters to dot+lower case letter
467
- name = name.replace(/([A-Z])/g, function (str)
468
- {
469
- return '.' + String(RegExp.$1).toLowerCase()
470
- });
471
-
472
- return prop[name];
473
- };
474
-
475
-
476
-
477
-
478
- /**
479
- * The function you call to draw the bar chart
480
- */
481
- this.draw =
482
- this.Draw = function ()
483
- {
484
- // MUST be the first thing done!
485
- if (typeof(prop['chart.background.image']) == 'string') {
486
- RG.DrawBackgroundImage(this);
487
- }
488
-
489
- /**
490
- * Fire the onbeforedraw event
491
- */
492
- RG.FireCustomEvent(this, 'onbeforedraw');
493
-
494
-
495
-
496
- //
497
- // If the chart is 3d then angle it it
498
- //
499
- if (prop['chart.variant'] === '3d') {
500
- if (prop['chart.text.accessible']) {
501
- // Nada
502
- } else {
503
- co.setTransform(1,prop['chart.variant.threed.angle'],0,1,0.5,0.5);
504
- }
505
- }
506
-
507
-
508
-
509
- /**
510
- * Parse the colors. This allows for simple gradient syntax
511
- */
512
- if (!this.colorsParsed) {
513
- this.parseColors();
514
-
515
- // Don't want to do this again
516
- this.colorsParsed = true;
517
- }
518
-
519
-
520
-
521
- /**
522
- * This is new in May 2011 and facilitates indiviual gutter settings,
523
- * eg chart.gutter.left
524
- */
525
- this.gutterLeft = prop['chart.gutter.left'];
526
- this.gutterRight = prop['chart.gutter.right'];
527
- this.gutterTop = prop['chart.gutter.top'];
528
- this.gutterBottom = prop['chart.gutter.bottom'];
529
-
530
- // Cache this in a class variable as it's used rather a lot
531
-
532
- /**
533
- * Check for tooltips and alert the user that they're not supported
534
- * with pyramid charts
535
- */
536
- if ( (prop['chart.variant'] == 'pyramid' || prop['chart.variant'] == 'dot')
537
- && typeof(prop['chart.tooltips']) == 'object'
538
- && prop['chart.tooltips']
539
- && prop['chart.tooltips'].length > 0) {
540
-
541
- alert('[BAR] (' + this.id + ') Sorry, tooltips are not supported with dot or pyramid charts');
542
- }
543
-
544
- /**
545
- * Stop the coords arrays from growing uncontrollably
546
- */
547
- this.coords = [];
548
- this.coords2 = [];
549
- this.coordsText = [];
550
-
551
- /**
552
- * Work out a few things. They need to be here because they depend on things you can change before you
553
- * call Draw() but after you instantiate the object
554
- */
555
- this.max = 0;
556
- this.grapharea = ca.height - this.gutterTop - this.gutterBottom;
557
- this.halfgrapharea = this.grapharea / 2;
558
- this.halfTextHeight = prop['chart.text.size'] / 2;
559
-
560
-
561
-
562
-
563
-
564
- // Now draw the background on to the main canvas
565
- RG.background.Draw(this);
566
-
567
-
568
-
569
-
570
- //If it's a sketch chart variant, draw the axes first
571
- //if (prop['chart.variant'] == 'sketch') {
572
- // this.DrawAxes();
573
- // this.Drawbars();
574
- //} else {
575
- this.drawbars();
576
- this.drawAxes();
577
- //}
578
-
579
- this.DrawLabels();
580
-
581
-
582
- /**
583
- * Draw the bevel if required
584
- */
585
- if (prop['chart.bevel'] || prop['chart.bevelled']) {
586
- this.DrawBevel();
587
- }
588
-
589
-
590
- // Draw the key if necessary
591
- if (prop['chart.key'] && prop['chart.key'].length) {
592
- RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
593
- }
594
-
595
-
596
- /**
597
- * Setup the context menu if required
598
- */
599
- if (prop['chart.contextmenu']) {
600
- RG.ShowContext(this);
601
- }
602
-
603
-
604
-
605
-
606
- /**
607
- * Draw errorbars
608
- */
609
- if (prop['chart.errorbars']) {
610
- this.drawErrorbars();
611
- }
612
-
613
-
614
-
615
-
616
- /**
617
- * Draw "in graph" labels
618
- */
619
- if (prop['chart.labels.ingraph']) {
620
- RG.DrawInGraphLabels(this);
621
- }
622
-
623
-
624
- /**
625
- * This function enables resizing
626
- */
627
- if (prop['chart.resizable']) {
628
- RG.AllowResizing(this);
629
- }
630
-
631
-
632
- /**
633
- * This installs the event listeners
634
- */
635
- RG.InstallEventListeners(this);
636
-
637
-
638
- /**
639
- * Fire the onfirstdraw event
640
- */
641
- if (this.firstDraw) {
642
- RG.fireCustomEvent(this, 'onfirstdraw');
643
- this.firstDraw = false;
644
- this.firstDrawFunc();
645
- }
646
-
647
-
648
- /**
649
- * Fire the RGraph ondraw event
650
- */
651
- RG.fireCustomEvent(this, 'ondraw');
652
-
653
- return this;
654
- };
655
-
656
-
657
-
658
- /**
659
- * Used in chaining. Runs a function there and then - not waiting for
660
- * the events to fire (eg the onbeforedraw event)
661
- *
662
- * @param function func The function to execute
663
- */
664
- this.exec = function (func)
665
- {
666
- func(this);
667
-
668
- return this;
669
- };
670
-
671
-
672
-
673
-
674
- /**
675
- * Draws the charts axes
676
- */
677
- this.drawAxes =
678
- this.DrawAxes = function ()
679
- {
680
- if (prop['chart.noaxes']) {
681
- return;
682
- }
683
-
684
- var xaxispos = prop['chart.xaxispos'];
685
- var yaxispos = prop['chart.yaxispos'];
686
- var isSketch = prop['chart.variant'] == 'sketch';
687
-
688
- co.beginPath();
689
- co.strokeStyle = prop['chart.axis.color'];
690
- co.lineWidth = prop['chart.axis.linewidth'] + 0.001;
691
-
692
-
693
- if (RG.ISSAFARI == -1) {
694
- co.lineCap = 'square';
695
- }
696
-
697
-
698
- // Draw the Y axis
699
- if (prop['chart.noyaxis'] == false) {
700
- if (yaxispos == 'right') {
701
- co.moveTo(ca.width - this.gutterRight + (isSketch ? 3 : 0), this.gutterTop - (isSketch ? 3 : 0));
702
- co.lineTo(ca.width - this.gutterRight - (isSketch ? 2 : 0), ca.height - this.gutterBottom + (isSketch ? 5 : 0));
703
- } else {
704
- co.moveTo(this.gutterLeft - (isSketch ? 2 : 0), this.gutterTop - (isSketch ? 5 : 0));
705
- co.lineTo(this.gutterLeft - (isSketch ? 1 : 0), ca.height - this.gutterBottom + (isSketch ? 5 : 0));
706
- }
707
- }
708
-
709
- // Draw the X axis
710
- if (prop['chart.noxaxis'] == false) {
711
- if (xaxispos == 'center') {
712
- co.moveTo(this.gutterLeft - (isSketch ? 5 : 0), Math.round(((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop + (isSketch ? 2 : 0)));
713
- co.lineTo(ca.width - this.gutterRight + (isSketch ? 5 : 0), Math.round(((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop - (isSketch ? 2 : 0)));
714
- } else if (xaxispos == 'top') {
715
- co.moveTo(this.gutterLeft - (isSketch ? 3 : 0), this.gutterTop - (isSketch ? 3 : 0));
716
- co.lineTo(ca.width - this.gutterRight + (isSketch ? 5 : 0), this.gutterTop + (isSketch ? 2 : 0));
717
- } else {
718
- co.moveTo(
719
- this.gutterLeft - (isSketch ? 5 : 0),
720
- ma.round(this.getYCoord(0) - (isSketch ? 2 : 0))
721
- );
722
- co.lineTo(
723
- ca.width - this.gutterRight + (isSketch ? 8 : 0),
724
- ma.round(this.getYCoord(0) + (isSketch ? 2 : 0))
725
- );
726
-
727
- }
728
- }
729
-
730
- var numYTicks = prop['chart.numyticks'];
731
-
732
- //
733
- // DRAW THE Y TICKMARKS
734
- //
735
- if (prop['chart.noyaxis'] == false && !isSketch) {
736
-
737
- var yTickGap = (ca.height - this.gutterTop - this.gutterBottom) / numYTicks;
738
- var xpos = yaxispos == 'left' ? this.gutterLeft : ca.width - this.gutterRight;
739
-
740
- if (this.properties['chart.numyticks'] > 0) {
741
- for (y=this.gutterTop;
742
- xaxispos == 'center' ? y <= (ca.height - this.gutterBottom) : y < (ca.height - this.gutterBottom + (xaxispos == 'top' ? 1 : 0));
743
- y += yTickGap) {
744
-
745
- if (xaxispos == 'center' && y == (this.gutterTop + (this.grapharea / 2))) {
746
- continue;
747
- }
748
-
749
- // X axis at the top
750
- if (xaxispos == 'top' && y == this.gutterTop) {
751
- continue;
752
- }
753
-
754
- co.moveTo(xpos + (yaxispos == 'left' ? 0 : 0), ma.round(y));
755
- co.lineTo(xpos + (yaxispos == 'left' ? -3 : 3), ma.round(y));
756
- }
757
-
758
- //
759
- // If the X axis is offset (ie not at the bottom when xaxispos
760
- // is set to bottom) - draw an extra tick
761
- //
762
- if (xaxispos === 'bottom' && prop['chart.ymin'] !== 0) {
763
- co.moveTo(xpos + (yaxispos == 'left' ? 0 : 0), ma.round(ca.height - prop['chart.gutter.bottom']));
764
- co.lineTo(xpos + (yaxispos == 'left' ? -3 : 3), ma.round(ca.height - prop['chart.gutter.bottom']));
765
- }
766
- }
767
-
768
- /**
769
- * If the X axis is not being shown, draw an extra tick
770
- */
771
- if (prop['chart.noxaxis']) {
772
- if (xaxispos == 'center') {
773
- co.moveTo(xpos + (yaxispos == 'left' ? -3 : 3), Math.round(ca.height / 2));
774
- co.lineTo(xpos, Math.round(ca.height / 2));
775
- } else if (xaxispos == 'top') {
776
- co.moveTo(xpos + (yaxispos == 'left' ? -3 : 3), Math.round(this.gutterTop));
777
- co.lineTo(xpos, Math.round(this.gutterTop));
778
- } else {
779
- co.moveTo(xpos + (yaxispos == 'left' ? -3 : 3), Math.round(ca.height - this.gutterBottom));
780
- co.lineTo(xpos, Math.round(ca.height - this.gutterBottom));
781
- }
782
- }
783
- }
784
-
785
-
786
- // Draw the X tickmarks
787
- if (prop['chart.noxaxis'] == false && !isSketch) {
788
-
789
- if (typeof(prop['chart.numxticks']) == 'number') {
790
- var xTickGap = (ca.width - this.gutterLeft - this.gutterRight) / prop['chart.numxticks'];
791
- } else {
792
- var xTickGap = (ca.width - this.gutterLeft - this.gutterRight) / this.data.length;
793
- }
794
-
795
- if (xaxispos == 'bottom') {
796
- yStart = prop['chart.ymin'] < 0 ? this.getYCoord(0) - 3 : this.getYCoord(0);
797
- yEnd = this.getYCoord(0) + 3;
798
- } else if (xaxispos == 'top') {
799
- yStart = this.gutterTop - 3;
800
- yEnd = this.gutterTop;
801
- } else if (xaxispos == 'center') {
802
- yStart = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop + 3;
803
- yEnd = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop - 3;
804
- }
805
-
806
- //yStart = yStart;
807
- //yEnd = yEnd;
808
-
809
- //////////////// X TICKS ////////////////
810
- var noEndXTick = prop['chart.noendxtick'];
811
-
812
- for (x=this.gutterLeft + (yaxispos == 'left' ? xTickGap : 0),len=(ca.width - this.gutterRight + (yaxispos == 'left' ? 5 : 0)); x<len; x+=xTickGap) {
813
-
814
- if (yaxispos == 'left' && !noEndXTick && x > this.gutterLeft) {
815
- co.moveTo(ma.round(x), yStart);
816
- co.lineTo(ma.round(x), yEnd);
817
-
818
- } else if (yaxispos == 'left' && noEndXTick && x > this.gutterLeft && x < (ca.width - this.gutterRight) ) {
819
- co.moveTo(ma.round(x), yStart);
820
- co.lineTo(ma.round(x), yEnd);
821
-
822
- } else if (yaxispos == 'right' && x < (ca.width - this.gutterRight) && !noEndXTick) {
823
- co.moveTo(ma.round(x), yStart);
824
- co.lineTo(ma.round(x), yEnd);
825
-
826
- } else if (yaxispos == 'right' && x < (ca.width - this.gutterRight) && x > (this.gutterLeft) && noEndXTick) {
827
- co.moveTo(ma.round(x), yStart);
828
- co.lineTo(ma.round(x), yEnd);
829
- }
830
- }
831
-
832
- if (prop['chart.noyaxis'] || prop['chart.numxticks'] == null) {
833
- if (typeof(prop['chart.numxticks']) == 'number' && prop['chart.numxticks'] > 0) {
834
- co.moveTo(Math.round(this.gutterLeft), yStart);
835
- co.lineTo(Math.round(this.gutterLeft), yEnd);
836
- }
837
- }
838
-
839
- //////////////// X TICKS ////////////////
840
- }
841
-
842
- /**
843
- * If the Y axis is not being shown, draw an extra tick
844
- */
845
- if (prop['chart.noyaxis'] && prop['chart.noxaxis'] == false && prop['chart.numxticks'] == null) {
846
- if (xaxispos == 'center') {
847
- co.moveTo(ma.round(this.gutterLeft), (ca.height / 2) - 3);
848
- co.lineTo(ma.round(this.gutterLeft), (ca.height / 2) + 3);
849
- } else {
850
- co.moveTo(ma.round(this.gutterLeft), ca.height - this.gutterBottom);
851
- co.lineTo(ma.round(this.gutterLeft), ca.height - this.gutterBottom + 3);
852
- }
853
- }
854
-
855
- co.stroke();
856
- };
857
-
858
-
859
-
860
-
861
- /**
862
- * Draws the bars
863
- */
864
- this.drawbars =
865
- this.Drawbars = function ()
866
- {
867
- co.lineWidth = prop['chart.linewidth'];
868
- co.strokeStyle = prop['chart.strokecolor'];
869
- co.fillStyle = prop['chart.colors'][0];
870
-
871
- var prevX = 0,
872
- prevY = 0,
873
- decimals = prop['chart.scale.decimals'];
874
-
875
-
876
- /**
877
- * Work out the max value
878
- */
879
- if (prop['chart.ymax']) {
880
-
881
- this.scale2 = RG.getScale2(this, {
882
- 'max':prop['chart.ymax'],
883
- 'strict': prop['chart.scale.round'] ? false : true,
884
- 'min':prop['chart.ymin'],
885
- 'scale.thousand':prop['chart.scale.thousand'],
886
- 'scale.point':prop['chart.scale.point'],
887
- 'scale.decimals':prop['chart.scale.decimals'],
888
- 'ylabels.count':prop['chart.ylabels.count'],
889
- 'scale.round':prop['chart.scale.round'],
890
- 'units.pre': prop['chart.units.pre'],
891
- 'units.post': prop['chart.units.post']
892
- });
893
-
894
- } else {
895
-
896
-
897
-
898
-
899
-
900
- //
901
- // If errorbars are given as a number then convert the nuumber to an
902
- // array.
903
- //
904
- var errorbars = prop['chart.errorbars'];
905
-
906
- if (typeof errorbars === 'number') {
907
-
908
- var value = errorbars;
909
-
910
- prop['chart.errorbars'] = [];
911
-
912
- for (var i=0; i<this.data.length; ++i) {
913
- if (typeof this.data[i] === 'number') {
914
- prop['chart.errorbars'].push([value, null]);
915
-
916
- } else if (typeof this.data[i] === 'object' && !RG.isNull(this.data[i])) {
917
- for (var j=0; j<this.data[i].length; ++j) {
918
- prop['chart.errorbars'].push([value, null]);
919
- }
920
- }
921
- }
922
-
923
- errorbars = prop['chart.errorbars'];
924
- }
925
-
926
-
927
-
928
-
929
-
930
-
931
-
932
-
933
- for (i=0; i<this.data.length; ++i) {
934
- if (typeof(this.data[i]) == 'object') {
935
- var value = prop['chart.grouping'] === 'grouped' ? Number(RG.arrayMax(this.data[i], true)) : Number(RG.array_sum(this.data[i]));
936
-
937
- } else {
938
- var value = Number(this.data[i]);
939
- }
940
-
941
- this.max = ma.max(ma.abs(this.max), ma.abs(value) +
942
-
943
- Number(
944
- (
945
- typeof prop['chart.errorbars'] === 'object'
946
- && typeof prop['chart.errorbars'][i] === 'object'
947
- && !RG.isNull(prop['chart.errorbars'][i])
948
- && typeof prop['chart.errorbars'][i][0] === 'number'
949
- ) ? prop['chart.errorbars'][i][0] : 0
950
- )
951
- );
952
- }
953
-
954
-
955
-
956
-
957
-
958
-
959
-
960
- this.scale2 = RGraph.getScale2(this, {
961
- 'max':this.max,
962
- 'min':prop['chart.ymin'],
963
- 'scale.thousand':prop['chart.scale.thousand'],
964
- 'scale.point':prop['chart.scale.point'],
965
- 'scale.decimals':prop['chart.scale.decimals'],
966
- 'ylabels.count':prop['chart.ylabels.count'],
967
- 'scale.round':prop['chart.scale.round'],
968
- 'units.pre': prop['chart.units.pre'],
969
- 'units.post': prop['chart.units.post']
970
- });
971
-
972
- this.max = this.scale2.max;
973
- }
974
-
975
- /**
976
- * if the chart is adjustable fix the scale so that it doesn't change.
977
- */
978
- if (prop['chart.adjustable'] && !prop['chart.ymax']) {
979
- this.Set('chart.ymax', this.scale2.max);
980
- }
981
-
982
- /**
983
- * Draw horizontal bars here
984
- */
985
- if (prop['chart.background.hbars'] && prop['chart.background.hbars'].length > 0) {
986
- RGraph.DrawBars(this);
987
- }
988
-
989
- var variant = prop['chart.variant'];
990
-
991
- /**
992
- * Draw the 3D axes is necessary
993
- */
994
- if (variant === '3d') {
995
- RG.draw3DAxes(this);
996
- }
997
-
998
- /**
999
- * Get the variant once, and draw the bars, be they regular, stacked or grouped
1000
- */
1001
-
1002
- // Get these variables outside of the loop
1003
- var xaxispos = prop['chart.xaxispos'],
1004
- width = (ca.width - this.gutterLeft - this.gutterRight ) / this.data.length,
1005
- orig_height = height,
1006
- hmargin = prop['chart.hmargin'],
1007
- shadow = prop['chart.shadow'],
1008
- shadowColor = prop['chart.shadow.color'],
1009
- shadowBlur = prop['chart.shadow.blur'],
1010
- shadowOffsetX = prop['chart.shadow.offsetx'],
1011
- shadowOffsetY = prop['chart.shadow.offsety'],
1012
- strokeStyle = prop['chart.strokecolor'],
1013
- colors = prop['chart.colors'],
1014
- sequentialColorIndex = 0
1015
-
1016
- var height;
1017
-
1018
- for (i=0,len=this.data.length; i<len; i+=1) {
1019
-
1020
-
1021
-
1022
-
1023
-
1024
- // Work out the height
1025
- //The width is up outside the loop
1026
- if (RG.arraySum(this.data[i]) < 0) {
1027
- var height = (RG.arraySum(this.data[i]) + this.scale2.min) / (this.scale2.max - this.scale2.min);
1028
- } else {
1029
- var height = (RG.arraySum(this.data[i]) - this.scale2.min) / (this.scale2.max - this.scale2.min);
1030
- }
1031
-
1032
- height *= ma.abs(this.getYCoord(this.scale2.max) - this.getYCoord(this.scale2.min));
1033
-
1034
-
1035
-
1036
-
1037
-
1038
-
1039
- var x = (i * width) + this.gutterLeft;
1040
- var y = xaxispos == 'center' ? ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop - height
1041
- : ca.height - height - this.gutterBottom;
1042
-
1043
- // xaxispos is top
1044
- if (xaxispos == 'top') {
1045
- y = this.gutterTop + ma.abs(height);
1046
- }
1047
-
1048
-
1049
- // Account for negative lengths - Some browsers don't like a negative value
1050
- if (height < 0) {
1051
- y += height;
1052
- height = ma.abs(height);
1053
- }
1054
-
1055
-
1056
-
1057
-
1058
-
1059
-
1060
- /**
1061
- * Turn on the shadow if need be
1062
- */
1063
- if (shadow) {
1064
- co.shadowColor = shadowColor;
1065
- co.shadowBlur = shadowBlur;
1066
- co.shadowOffsetX = shadowOffsetX;
1067
- co.shadowOffsetY = shadowOffsetY;
1068
- }
1069
-
1070
- /**
1071
- * Draw the bar
1072
- */
1073
- co.beginPath();
1074
- if (typeof this.data[i] == 'number') {
1075
-
1076
-
1077
- // If the Y axis is offset change the bar start (the top of the bar)
1078
- if (xaxispos === 'bottom' && prop['chart.ymin'] < 0) {
1079
- if (this.data[i] >= 0) {
1080
- height = ma.abs(this.getYCoord(0) - this.getYCoord(this.data[i]));
1081
- } else {
1082
- y = this.getYCoord(0);
1083
- height = ma.abs(this.getYCoord(0) - this.getYCoord(this.data[i]));
1084
- }
1085
- }
1086
-
1087
- var barWidth = width - (2 * hmargin);
1088
-
1089
- /**
1090
- * Check for a negative bar width
1091
- */
1092
- if (barWidth < 0) {
1093
- alert('[RGRAPH] Warning: you have a negative bar width. This may be caused by the chart.hmargin being too high or the width of the canvas not being sufficient.');
1094
- }
1095
-
1096
- // Set the fill color
1097
- co.strokeStyle = strokeStyle;
1098
- co.fillStyle = colors[0];
1099
-
1100
- /**
1101
- * Sequential colors
1102
- */
1103
- if (prop['chart.colors.sequential']) {
1104
- co.fillStyle = colors[i];
1105
- }
1106
-
1107
- if (variant == 'sketch') {
1108
-
1109
- co.lineCap = 'round';
1110
-
1111
- var sketchOffset = 3;
1112
-
1113
- co.beginPath();
1114
-
1115
- co.strokeStyle = colors[0];
1116
-
1117
- /**
1118
- * Sequential colors
1119
- */
1120
- if (prop['chart.colors.sequential']) {
1121
- co.strokeStyle = colors[i];
1122
- }
1123
-
1124
- // Left side
1125
- co.moveTo(x + hmargin + 2, y + height - 2);
1126
- co.lineTo(x + hmargin - 1, y - 4);
1127
-
1128
- // The top
1129
- co.moveTo(x + hmargin - 3, y + -2 + (this.data[i] < 0 ? height : 0));
1130
- co.bezierCurveTo(
1131
- x + ((hmargin + width) * 0.33),
1132
- y + 15 + (this.data[i] < 0 ? height - 10: 0),
1133
- x + ((hmargin + width) * 0.66),
1134
- y + 5 + (this.data[i] < 0 ? height - 10 : 0),x + hmargin + width + -1, y + 0 + (this.data[i] < 0 ? height : 0)
1135
- );
1136
-
1137
-
1138
- // The right side
1139
- co.moveTo(x + hmargin + width - 5, y - 5);
1140
- co.lineTo(x + hmargin + width - 3, y + height - 3);
1141
-
1142
- if (prop['chart.variant.sketch.verticals']) {
1143
- for (var r=0.2; r<=0.8; r+=0.2) {
1144
- co.moveTo(x + hmargin + width + (r > 0.4 ? -1 : 3) - (r * width),y - 1);
1145
- co.lineTo(x + hmargin + width - (r > 0.4 ? 1 : -1) - (r * width), y + height + (r == 0.2 ? 1 : -2));
1146
- }
1147
- }
1148
-
1149
- co.stroke();
1150
-
1151
- // Regular bar
1152
- } else if (variant == 'bar' || variant == '3d' || variant == 'glass' || variant == 'bevel') {
1153
-
1154
- if (RGraph.ISOLD && shadow) {
1155
- this.DrawIEShadow([x + hmargin, y, barWidth, height]);
1156
- }
1157
-
1158
- if (variant == 'glass') {
1159
- RGraph.filledCurvyRect(co, x + hmargin, y, barWidth, height, 3, this.data[i] > 0, this.data[i] > 0, this.data[i] < 0, this.data[i] < 0);
1160
- RGraph.strokedCurvyRect(co, x + hmargin, y, barWidth, height, 3, this.data[i] > 0, this.data[i] > 0, this.data[i] < 0, this.data[i] < 0);
1161
- } else {
1162
- // On 9th April 2013 these two were swapped around so that the stroke happens SECOND so that any
1163
- // shadow that is cast by the fill does not overwrite the stroke
1164
-
1165
- co.beginPath();
1166
- co.rect(x + hmargin, y, barWidth, height);
1167
- co.fill();
1168
-
1169
- // Turn the shadow off so that the stroke doesn't cast any "extra" shadow
1170
- // that would show inside the bar
1171
- RG.NoShadow(this);
1172
-
1173
- co.beginPath();
1174
- co.rect(x + hmargin, y, barWidth, height);
1175
- co.stroke();
1176
- }
1177
-
1178
- // 3D effect
1179
- if (variant == '3d') {
1180
-
1181
- var prevStrokeStyle = co.strokeStyle;
1182
- var prevFillStyle = co.fillStyle;
1183
-
1184
- // Draw the top (if the value is positive - otherwise there's no point)
1185
- if (this.data[i] >= 0) {
1186
- co.beginPath();
1187
- co.moveTo(x + hmargin, y);
1188
- co.lineTo(x + hmargin + prop['chart.variant.threed.offsetx'], y - prop['chart.variant.threed.offsety']);
1189
- co.lineTo(x + hmargin + prop['chart.variant.threed.offsetx'] + barWidth, y - prop['chart.variant.threed.offsety']);
1190
- co.lineTo(x + hmargin + barWidth, y);
1191
- co.closePath();
1192
-
1193
- co.stroke();
1194
- co.fill();
1195
- }
1196
-
1197
- // Draw the right hand side
1198
- co.beginPath();
1199
- co.moveTo(x + hmargin + barWidth, y);
1200
- co.lineTo(
1201
- x + hmargin + barWidth + prop['chart.variant.threed.offsetx'],
1202
- this.data[i] < 0 && xaxispos === 'bottom' ?
1203
- this.getYCoord(0) : (
1204
- this.data[i] < 0 && (y - prop['chart.variant.threed.offsety'])
1205
- < (this.gutterTop + this.halfgrapharea)
1206
-
1207
- ?
1208
-
1209
- (this.gutterTop + this.halfgrapharea)
1210
-
1211
- : (y - prop['chart.variant.threed.offsety']))
1212
- );
1213
-
1214
- co.lineTo(
1215
- x + hmargin + barWidth + prop['chart.variant.threed.offsetx'],
1216
-
1217
-
1218
- this.data[i] < 0 && (y - prop['chart.variant.threed.offsety'] + height) < (this.gutterTop + this.getYCoord(0))
1219
- ? this.getYCoord(this.data[i]) - prop['chart.variant.threed.offsety']
1220
- : (this.data[i] > 0 ?
1221
- y - prop['chart.variant.threed.offsety'] + height :
1222
- ma.min(y - prop['chart.variant.threed.offsety'] + height, ca.height - this.gutterBottom)
1223
- )
1224
- );
1225
- co.lineTo(x + hmargin + barWidth, y + height);
1226
- co.closePath();
1227
- co.stroke();
1228
- co.fill();
1229
-
1230
-
1231
-
1232
-
1233
- // Draw the lighter top section
1234
- if (this.data[i] > 0) {
1235
- co.beginPath();
1236
- co.fillStyle = 'rgba(255,255,255,0.5)';
1237
- co.moveTo(x + hmargin, y);
1238
- co.lineTo(x + hmargin + prop['chart.variant.threed.offsetx'], y - prop['chart.variant.threed.offsety']);
1239
- co.lineTo(x + hmargin + prop['chart.variant.threed.offsetx'] + barWidth, y - prop['chart.variant.threed.offsety']);
1240
- co.lineTo(x + hmargin + barWidth, y);
1241
- co.lineTo(x + hmargin, y);
1242
- co.closePath();
1243
- co.stroke();
1244
- co.fill();
1245
- }
1246
-
1247
-
1248
-
1249
-
1250
- // Draw the darker right side section
1251
- co.beginPath();
1252
- co.fillStyle = 'rgba(0,0,0,0.4)';
1253
- // TL
1254
- co.moveTo(x + hmargin + barWidth, y);
1255
-
1256
- // TR
1257
- co.lineTo(
1258
- x + hmargin + barWidth + prop['chart.variant.threed.offsetx'],
1259
- this.data[i] < 0 && xaxispos === 'bottom' ? this.getYCoord(0) : (this.data[i] < 0 && (y - prop['chart.variant.threed.offsety']) < (this.gutterTop + this.halfgrapharea) ? (this.gutterTop + this.halfgrapharea) : y - prop['chart.variant.threed.offsety'])
1260
- );
1261
-
1262
- // BR
1263
- co.lineTo(
1264
- x + hmargin + barWidth + prop['chart.variant.threed.offsetx'],
1265
-
1266
- this.data[i] < 0 && (y - prop['chart.variant.threed.offsety'] + height) < this.getYCoord(0)
1267
- ? this.getYCoord(0)
1268
- : this.data[i] > 0 ? y - prop['chart.variant.threed.offsety'] + height : ma.min(y - prop['chart.variant.threed.offsety'] + height, ca.height - this.gutterBottom)
1269
- );
1270
- // BL
1271
- co.lineTo(x + hmargin + barWidth, y + height);
1272
- co.lineTo(x + hmargin + barWidth, y);
1273
- co.closePath();
1274
-
1275
- co.stroke();
1276
- co.fill();
1277
-
1278
- co.strokeStyle = prevStrokeStyle;
1279
- co.fillStyle = prevFillStyle;
1280
-
1281
- // Glass variant
1282
- } else if (variant == 'glass') {
1283
-
1284
- var grad = co.createLinearGradient(x + hmargin,y,x + hmargin + (barWidth / 2),y);
1285
- grad.addColorStop(0, 'rgba(255,255,255,0.9)');
1286
- grad.addColorStop(1, 'rgba(255,255,255,0.5)');
1287
-
1288
- co.beginPath();
1289
- co.fillStyle = grad;
1290
- co.fillRect(x + hmargin + 2,y + (this.data[i] > 0 ? 2 : 0),(barWidth / 2) - 2,height - 2);
1291
- co.fill();
1292
- }
1293
-
1294
-
1295
- // Dot chart
1296
- } else if (variant == 'dot') {
1297
-
1298
- co.beginPath();
1299
- co.moveTo(x + (width / 2), y);
1300
- co.lineTo(x + (width / 2), y + height);
1301
- co.stroke();
1302
-
1303
- co.beginPath();
1304
- co.fillStyle = this.properties['chart.colors'][i];
1305
- co.arc(x + (width / 2), y + (this.data[i] > 0 ? 0 : height), 2, 0, 6.28, 0);
1306
-
1307
- // Set the colour for the dots
1308
- co.fillStyle = prop['chart.colors'][0];
1309
-
1310
- /**
1311
- * Sequential colors
1312
- */
1313
- if (prop['chart.colors.sequential']) {
1314
- co.fillStyle = colors[i];
1315
- }
1316
-
1317
- co.stroke();
1318
- co.fill();
1319
-
1320
-
1321
-
1322
- // Unknown variant type
1323
- } else {
1324
- alert('[BAR] Warning! Unknown chart.variant: ' + variant);
1325
- }
1326
-
1327
- this.coords.push([x + hmargin, y, width - (2 * hmargin), height]);
1328
-
1329
- if (typeof this.coords2[i] == 'undefined') {
1330
- this.coords2[i] = [];
1331
- }
1332
- this.coords2[i].push([x + hmargin, y, width - (2 * hmargin), height]);
1333
-
1334
-
1335
- /**
1336
- * Stacked bar
1337
- */
1338
- } else if (this.data[i] && typeof(this.data[i]) == 'object' && prop['chart.grouping'] == 'stacked') {
1339
-
1340
- if (this.scale2.min) {
1341
- alert("[ERROR] Stacked Bar charts with a Y min are not supported");
1342
- }
1343
-
1344
- var barWidth = width - (2 * hmargin);
1345
- var redrawCoords = [];// Necessary to draw if the shadow is enabled
1346
- var startY = 0;
1347
- var dataset = this.data[i];
1348
-
1349
- /**
1350
- * Check for a negative bar width
1351
- */
1352
- if (barWidth < 0) {
1353
- alert('[RGRAPH] Warning: you have a negative bar width. This may be caused by the chart.hmargin being too high or the width of the canvas not being sufficient.');
1354
- }
1355
-
1356
- for (j=0; j<dataset.length; ++j) {
1357
-
1358
- // Stacked bar chart and X axis pos in the middle - poitless since negative values are not permitted
1359
- if (xaxispos == 'center') {
1360
- alert("[BAR] It's pointless having the X axis position at the center on a stacked bar chart.");
1361
- return;
1362
- }
1363
-
1364
- // Negative values not permitted for the stacked chart
1365
- if (this.data[i][j] < 0) {
1366
- alert('[BAR] Negative values are not permitted with a stacked bar chart. Try a grouped one instead.');
1367
- return;
1368
- }
1369
-
1370
- /**
1371
- * Set the fill and stroke colors
1372
- */
1373
- co.strokeStyle = strokeStyle
1374
- co.fillStyle = colors[j];
1375
-
1376
- if (prop['chart.colors.reverse']) {
1377
- co.fillStyle = colors[this.data[i].length - j - 1];
1378
- }
1379
-
1380
- if (prop['chart.colors.sequential'] && colors[sequentialColorIndex]) {
1381
- co.fillStyle = colors[sequentialColorIndex++];
1382
- } else if (prop['chart.colors.sequential']) {
1383
- co.fillStyle = colors[sequentialColorIndex - 1];
1384
- }
1385
-
1386
- var height = (dataset[j] / this.scale2.max) * (ca.height - this.gutterTop - this.gutterBottom );
1387
-
1388
- // If the X axis pos is in the center, we need to half the height
1389
- if (xaxispos == 'center') {
1390
- height /= 2;
1391
- }
1392
-
1393
- var totalHeight = (RGraph.array_sum(dataset) / this.scale2.max) * (ca.height - hmargin - this.gutterTop - this.gutterBottom);
1394
-
1395
- /**
1396
- * Store the coords for tooltips
1397
- */
1398
- this.coords.push([x + hmargin, y, width - (2 * hmargin), height]);
1399
- if (typeof this.coords2[i] == 'undefined') {
1400
- this.coords2[i] = [];
1401
- }
1402
- this.coords2[i].push([x + hmargin, y, width - (2 * hmargin), height]);
1403
-
1404
- // MSIE shadow
1405
- if (RGraph.ISOLD && shadow) {
1406
- this.DrawIEShadow([x + hmargin, y, width - (2 * hmargin), height + 1]);
1407
- }
1408
-
1409
- if (height > 0) {
1410
- co.strokeRect(x + hmargin, y, width - (2 * hmargin), height);
1411
- co.fillRect(x + hmargin, y, width - (2 * hmargin), height);
1412
- }
1413
-
1414
-
1415
- if (j == 0) {
1416
- var startY = y;
1417
- var startX = x;
1418
- }
1419
-
1420
- /**
1421
- * Store the redraw coords if the shadow is enabled
1422
- */
1423
- if (shadow) {
1424
- redrawCoords.push([x + hmargin, y, width - (2 * hmargin), height, co.fillStyle]);
1425
- }
1426
-
1427
- /**
1428
- * Stacked 3D effect
1429
- */
1430
- if (variant == '3d') {
1431
-
1432
- var prevFillStyle = co.fillStyle;
1433
- var prevStrokeStyle = co.strokeStyle;
1434
-
1435
-
1436
- // Draw the top side
1437
- if (j == 0) {
1438
- co.beginPath();
1439
- co.moveTo(startX + hmargin, y);
1440
- co.lineTo(startX + prop['chart.variant.threed.offsetx'] + hmargin, y - prop['chart.variant.threed.offsety']);
1441
- co.lineTo(startX + prop['chart.variant.threed.offsetx'] + barWidth + hmargin, y - prop['chart.variant.threed.offsety']);
1442
- co.lineTo(startX + barWidth + hmargin, y);
1443
- co.closePath();
1444
-
1445
- co.fill();
1446
- co.stroke();
1447
- }
1448
-
1449
- // Draw the side section
1450
- co.beginPath();
1451
- co.moveTo(startX + barWidth + hmargin, y);
1452
- co.lineTo(startX + barWidth + hmargin + prop['chart.variant.threed.offsetx'], y - prop['chart.variant.threed.offsety']);
1453
- co.lineTo(startX + barWidth + hmargin + prop['chart.variant.threed.offsetx'], y - prop['chart.variant.threed.offsety'] + height);
1454
- co.lineTo(startX + barWidth + hmargin , y + height);
1455
- co.closePath();
1456
-
1457
- co.fill();
1458
- co.stroke();
1459
-
1460
- // Draw the lighter top side
1461
- if (j == 0) {
1462
- co.fillStyle = 'rgba(255,255,255,0.5)';
1463
- co.beginPath();
1464
- co.moveTo(startX + hmargin, y);
1465
- co.lineTo(startX + prop['chart.variant.threed.offsetx'] + hmargin, y - prop['chart.variant.threed.offsety']);
1466
- co.lineTo(startX + prop['chart.variant.threed.offsetx'] + barWidth + hmargin, y - prop['chart.variant.threed.offsety']);
1467
- co.lineTo(startX + barWidth + hmargin, y);
1468
- co.closePath();
1469
-
1470
- co.fill();
1471
- co.stroke();
1472
- }
1473
-
1474
- // Draw the darker side section
1475
- co.fillStyle = 'rgba(0,0,0,0.4)';
1476
- co.beginPath();
1477
- co.moveTo(startX + barWidth + hmargin, y);
1478
- co.lineTo(startX + barWidth + hmargin + prop['chart.variant.threed.offsetx'], y - prop['chart.variant.threed.offsety']);
1479
- co.lineTo(startX + barWidth + hmargin + prop['chart.variant.threed.offsetx'], y - prop['chart.variant.threed.offsety'] + height);
1480
- co.lineTo(startX + barWidth + hmargin , y + height);
1481
- co.closePath();
1482
-
1483
- co.fill();
1484
- co.stroke();
1485
-
1486
- co.strokeStyle = prevStrokeStyle;
1487
- co.fillStyle = prevFillStyle;
1488
- }
1489
-
1490
- y += height;
1491
- }
1492
-
1493
-
1494
-
1495
- /**
1496
- * Redraw the bars if the shadow is enabled due to hem being drawn from the bottom up, and the
1497
- * shadow spilling over to higher up bars
1498
- */
1499
- if (shadow) {
1500
-
1501
- RGraph.NoShadow(this);
1502
-
1503
- for (k=0; k<redrawCoords.length; ++k) {
1504
- co.strokeStyle = strokeStyle;
1505
- co.fillStyle = redrawCoords[k][4];
1506
- co.strokeRect(redrawCoords[k][0], redrawCoords[k][1], redrawCoords[k][2], redrawCoords[k][3]);
1507
- co.fillRect(redrawCoords[k][0], redrawCoords[k][1], redrawCoords[k][2], redrawCoords[k][3]);
1508
-
1509
- co.stroke();
1510
- co.fill();
1511
- }
1512
-
1513
- // Reset the redraw coords to be empty
1514
- redrawCoords = [];
1515
- }
1516
-
1517
- /**
1518
- * Grouped bar
1519
- */
1520
- } else if (this.data[i] && typeof(this.data[i]) == 'object' && prop['chart.grouping'] == 'grouped') {
1521
-
1522
- var redrawCoords = [];
1523
- co.lineWidth = prop['chart.linewidth'];
1524
-
1525
- for (j=0; j<this.data[i].length; ++j) {
1526
-
1527
- // Set the fill and stroke colors
1528
- co.strokeStyle = strokeStyle;
1529
- co.fillStyle = colors[j];
1530
-
1531
- /**
1532
- * Sequential colors
1533
- */
1534
- if (prop['chart.colors.sequential'] && colors[sequentialColorIndex]) {
1535
- co.fillStyle = colors[sequentialColorIndex++];
1536
- } else if (prop['chart.colors.sequential']) {
1537
- co.fillStyle = colors[sequentialColorIndex - 1];
1538
- }
1539
-
1540
- var individualBarWidth = (width - (2 * hmargin)) / this.data[i].length;
1541
- var height = ((this.data[i][j] + (this.data[i][j] < 0 ? this.scale2.min : (-1 * this.scale2.min) )) / (this.scale2.max - this.scale2.min) ) * (ca.height - this.gutterTop - this.gutterBottom );
1542
- var groupedMargin = prop['chart.hmargin.grouped'];
1543
- var startX = x + hmargin + (j * individualBarWidth);
1544
-
1545
- /**
1546
- * Check for a negative bar width
1547
- */
1548
- if (individualBarWidth < 0) {
1549
- alert('[RGRAPH] Warning: you have a negative bar width. This may be caused by the chart.hmargin being too high or the width of the canvas not being sufficient.');
1550
- }
1551
-
1552
- // If the X axis pos is in the center, we need to half the height
1553
- if (xaxispos == 'center') {
1554
- height /= 2;
1555
- }
1556
-
1557
- /**
1558
- * Determine the start positioning for the bar
1559
- */
1560
- if (xaxispos == 'top') {
1561
- var startY = this.gutterTop;
1562
- var height = Math.abs(height);
1563
-
1564
- } else if (xaxispos == 'center') {
1565
- var startY = this.gutterTop + (this.grapharea / 2) - height;
1566
-
1567
- } else {
1568
- var startY = this.getYCoord(0);//ca.height - this.gutterBottom - height;
1569
- var height = ma.abs(ma.abs(this.getYCoord(this.data[i][j])) - this.getYCoord(0));
1570
-
1571
- if (this.data[i][j] >= 0) {
1572
- startY -= height;
1573
- }
1574
-
1575
- }
1576
-
1577
- co.strokeRect(startX + groupedMargin, startY, individualBarWidth - (2 * groupedMargin), height);
1578
- co.fillRect(startX + groupedMargin, startY, individualBarWidth - (2 * groupedMargin), height);
1579
- y += height;
1580
-
1581
-
1582
-
1583
- /**
1584
- * Grouped 3D effect
1585
- */
1586
- if (variant == '3d') {
1587
-
1588
- var prevFillStyle = co.fillStyle;
1589
- var prevStrokeStyle = co.strokeStyle;
1590
- var hmarginGrouped = prop['chart.hmargin.grouped'];
1591
-
1592
- // Draw the top side
1593
- if (this.data[i][j] >= 0) {
1594
-
1595
- co.beginPath();
1596
- co.moveTo(startX + hmarginGrouped, startY);
1597
- co.lineTo(startX + hmarginGrouped + prop['chart.variant.threed.offsetx'], startY - prop['chart.variant.threed.offsety']);
1598
- co.lineTo(startX + prop['chart.variant.threed.offsetx'] + individualBarWidth - hmarginGrouped, startY - prop['chart.variant.threed.offsety']);
1599
- co.lineTo(startX + individualBarWidth - hmarginGrouped, startY);
1600
- co.closePath();
1601
- co.fill();
1602
- co.stroke();
1603
- }
1604
-
1605
- // Draw the side section
1606
- co.beginPath();
1607
- co.moveTo(startX + individualBarWidth - hmarginGrouped - 1, startY);
1608
- co.lineTo(
1609
- startX + individualBarWidth - hmarginGrouped + prop['chart.variant.threed.offsetx'],
1610
- this.data[i][j] < 0 ? (this.getYCoord(0) + ma.abs(height) - prop['chart.variant.threed.offsety']) : this.getYCoord(0) - height - prop['chart.variant.threed.offsety']
1611
- );
1612
-
1613
- co.lineTo(
1614
- startX + individualBarWidth - hmarginGrouped + prop['chart.variant.threed.offsetx'],
1615
- this.data[i][j] < 0 && (startY + height - prop['chart.variant.threed.offsety']) < (this.gutterTop + this.halfgrapharea) ? (this.gutterTop + this.halfgrapharea) : (startY + height - prop['chart.variant.threed.offsety'])
1616
- );
1617
- co.lineTo(startX + individualBarWidth - hmarginGrouped - 1, startY + height);
1618
- co.closePath();
1619
- co.fill();
1620
- co.stroke();
1621
-
1622
-
1623
- // Draw the lighter top side - but only if the current value is positive
1624
- if (this.data[i][j] >= 0) {
1625
- co.fillStyle = 'rgba(255,255,255,0.5)';
1626
- co.beginPath();
1627
- // BL
1628
- co.moveTo(startX + hmarginGrouped, startY);
1629
-
1630
- // BR
1631
- co.lineTo(startX + hmarginGrouped + prop['chart.variant.threed.offsetx'], startY - prop['chart.variant.threed.offsety']);
1632
-
1633
- // TR
1634
- co.lineTo(startX + prop['chart.variant.threed.offsetx'] + individualBarWidth - hmarginGrouped, startY - prop['chart.variant.threed.offsety']);
1635
-
1636
- // TL
1637
- co.lineTo(startX + individualBarWidth - hmarginGrouped, startY);
1638
- co.closePath();
1639
-
1640
- co.fill();
1641
- co.stroke();
1642
- }
1643
-
1644
- // Draw the darker side section
1645
- co.fillStyle = 'rgba(0,0,0,0.4)';
1646
- co.beginPath();
1647
- // TL corner
1648
- co.moveTo(
1649
- startX + individualBarWidth - hmarginGrouped,
1650
- startY
1651
- );
1652
-
1653
-
1654
- co.lineTo(
1655
- startX + individualBarWidth + prop['chart.variant.threed.offsetx'] - hmarginGrouped,
1656
- this.data[i][j] < 0 ? (this.getYCoord(0) + ma.abs(height) - prop['chart.variant.threed.offsety']) : this.getYCoord(0) - height - prop['chart.variant.threed.offsety']
1657
- );
1658
-
1659
- // TR corner
1660
- co.lineTo(
1661
- startX + individualBarWidth + prop['chart.variant.threed.offsetx'] - hmarginGrouped,
1662
- this.data[i][j] < 0 && (startY + height - 5) < (this.gutterTop + this.halfgrapharea) ? (this.gutterTop + this.halfgrapharea) : (startY + height - prop['chart.variant.threed.offsety'])
1663
- );
1664
-
1665
- // TL corner
1666
- co.lineTo(startX + individualBarWidth - hmarginGrouped, startY + height);
1667
- co.closePath();
1668
-
1669
- co.fill();
1670
- co.stroke();
1671
-
1672
- co.strokeStyle = prevStrokeStyle;
1673
- co.fillStyle = prevFillStyle;
1674
- }
1675
-
1676
- if (height < 0) {
1677
- height = Math.abs(height);
1678
- startY = startY - height;
1679
- }
1680
-
1681
- this.coords.push([startX + groupedMargin, startY, individualBarWidth - (2 * groupedMargin), height]);
1682
- if (typeof this.coords2[i] == 'undefined') {
1683
- this.coords2[i] = [];
1684
- }
1685
-
1686
- this.coords2[i].push([startX + groupedMargin, startY, individualBarWidth - (2 * groupedMargin), height]);
1687
-
1688
- // Facilitate shadows going to the left
1689
- if (prop['chart.shadow']) {
1690
- redrawCoords.push([startX + groupedMargin, startY, individualBarWidth - (2 * groupedMargin), height, co.fillStyle]);
1691
- }
1692
- }
1693
-
1694
-
1695
-
1696
-
1697
-
1698
-
1699
-
1700
- /**
1701
- * Redraw the bar if shadows are going to the left
1702
- */
1703
- if (redrawCoords.length) {
1704
-
1705
- RGraph.NoShadow(this);
1706
-
1707
- co.lineWidth = prop['chart.linewidth'];
1708
-
1709
- co.beginPath();
1710
- for (var j=0; j<redrawCoords.length; ++j) {
1711
-
1712
- co.fillStyle = redrawCoords[j][4];
1713
- co.strokeStyle = prop['chart.strokecolor'];
1714
-
1715
- co.fillRect(redrawCoords[j][0], redrawCoords[j][1], redrawCoords[j][2], redrawCoords[j][3]);
1716
- co.strokeRect(redrawCoords[j][0], redrawCoords[j][1], redrawCoords[j][2], redrawCoords[j][3]);
1717
- }
1718
- co.fill();
1719
- co.stroke();
1720
-
1721
- redrawCoords = [];
1722
- }
1723
- } else {
1724
- this.coords.push([]);
1725
- }
1726
-
1727
- co.closePath();
1728
- }
1729
-
1730
- // If 3D, redraw the right hand Y axis
1731
- if (prop['chart.variant'] === '3d' && prop['chart.yaxispos'] === 'right') {
1732
- RG.draw3DYAxis(this);
1733
- }
1734
-
1735
-
1736
-
1737
-
1738
-
1739
- /**
1740
- * Turn off any shadow
1741
- */
1742
- RGraph.noShadow(this);
1743
- };
1744
-
1745
-
1746
-
1747
- /**
1748
- * Draws the labels for the graph
1749
- */
1750
- this.drawLabels =
1751
- this.DrawLabels = function ()
1752
- {
1753
- var context = co;
1754
-
1755
- var text_angle = prop['chart.text.angle'],
1756
- text_size = prop['chart.text.size'],
1757
- labels = prop['chart.labels']
1758
-
1759
-
1760
-
1761
- // Draw the Y axis labels:
1762
- if (prop['chart.ylabels']) {
1763
- if (prop['chart.xaxispos'] == 'top') this.Drawlabels_top();
1764
- if (prop['chart.xaxispos'] == 'center') this.Drawlabels_center();
1765
- if (prop['chart.xaxispos'] == 'bottom') this.Drawlabels_bottom();
1766
- }
1767
-
1768
- /**
1769
- * The X axis labels
1770
- */
1771
- if (typeof(labels) == 'object' && labels) {
1772
-
1773
- var yOffset = Number(prop['chart.labels.offsety']),
1774
- xOffset = Number(prop['chart.labels.offsetx']),
1775
- bold = prop['chart.labels.bold']
1776
-
1777
- /**
1778
- * Text angle
1779
- */
1780
- if (prop['chart.text.angle'] != 0) {
1781
- var valign = 'center';
1782
- var halign = 'right';
1783
- var angle = 0 - prop['chart.text.angle'];
1784
- } else {
1785
- var valign = 'top';
1786
- var halign = 'center';
1787
- var angle = 0;
1788
- }
1789
-
1790
- // Draw the X axis labels
1791
- co.fillStyle = prop['chart.labels.color'] || prop['chart.text.color'];
1792
-
1793
- // How wide is each bar
1794
- var barWidth = (ca.width - this.gutterRight - this.gutterLeft) / labels.length;
1795
-
1796
- // Reset the xTickGap
1797
- xTickGap = (ca.width - this.gutterRight - this.gutterLeft) / labels.length
1798
-
1799
- // Draw the X tickmarks
1800
- var i=0;
1801
- var font = prop['chart.text.font'];
1802
-
1803
- for (x=this.gutterLeft + (xTickGap / 2); x<=ca.width - this.gutterRight; x+=xTickGap) {
1804
-
1805
- RG.text2(this, {
1806
- 'font': font,
1807
- 'size': text_size,
1808
- 'x': x + xOffset,
1809
- 'y': prop['chart.xaxispos'] == 'top' ? this.gutterTop + yOffset - 5: (ca.height - this.gutterBottom) + yOffset + 3,
1810
- 'bold': bold,
1811
- 'text': String(labels[i++]),
1812
- 'valign': prop['chart.xaxispos'] == 'top' ? 'bottom' : valign,
1813
- 'halign': halign,
1814
- 'tag':'label',
1815
- 'marker':false,
1816
- 'angle':angle,
1817
- 'tag': 'labels'
1818
- });
1819
- }
1820
- }
1821
-
1822
- /**
1823
- * Draw above labels
1824
- */
1825
- this.drawAboveLabels();
1826
- };
1827
-
1828
-
1829
-
1830
- /**
1831
- * Draws the X axis at the top
1832
- */
1833
- this.drawlabels_top =
1834
- this.Drawlabels_top = function ()
1835
- {
1836
- var ca = this.canvas;
1837
- var co = this.context;
1838
- var prop = this.properties;
1839
-
1840
- co.beginPath();
1841
- co.fillStyle = prop['chart.text.color'];
1842
- co.strokeStyle = 'black';
1843
-
1844
- if (prop['chart.xaxispos'] == 'top') {
1845
-
1846
- var context = co;
1847
- var text_size = prop['chart.text.size'];
1848
- var units_pre = prop['chart.units.pre'];
1849
- var units_post = prop['chart.units.post'];
1850
- var align = prop['chart.yaxispos'] == 'left' ? 'right' : 'left';
1851
- var font = prop['chart.text.font'];
1852
- var numYLabels = prop['chart.ylabels.count'];
1853
- var ymin = prop['chart.ymin'];
1854
- var offsetx = prop['chart.ylabels.offsetx'];
1855
- var offsety = prop['chart.ylabels.offsety'];
1856
-
1857
- if (prop['chart.ylabels.inside'] == true) {
1858
- var xpos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft + 5 : ca.width - this.gutterRight - 5;
1859
- var align = prop['chart.yaxispos'] == 'left' ? 'left' : 'right';
1860
- var boxed = true;
1861
- } else {
1862
- var xpos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft - 5 : ca.width - this.gutterRight + 5;
1863
- var boxed = false;
1864
- }
1865
-
1866
- /**
1867
- * Draw specific Y labels here so that the local variables can be reused
1868
- */
1869
- if (typeof(prop['chart.ylabels.specific']) == 'object' && prop['chart.ylabels.specific']) {
1870
-
1871
- var labels = RGraph.array_reverse(prop['chart.ylabels.specific']);
1872
- var grapharea = ca.height - this.gutterTop - this.gutterBottom;
1873
-
1874
- for (var i=0; i<labels.length; ++i) {
1875
-
1876
- var y = this.gutterTop + (grapharea * (i / labels.length)) + (grapharea / labels.length);
1877
-
1878
- RG.text2(this, {
1879
- 'font': font,
1880
- 'size': text_size,
1881
- 'x': xpos + offsetx,
1882
- 'y': y + offsety,
1883
- 'text': String(labels[i]),
1884
- 'valign': 'center',
1885
- 'halign': align,
1886
- 'bordered':boxed,
1887
- 'tag': 'scale'
1888
- });
1889
- }
1890
-
1891
- return;
1892
- }
1893
-
1894
-
1895
-
1896
-
1897
-
1898
-
1899
-
1900
- /**
1901
- * Draw the scale
1902
- */
1903
- var labels = this.scale2.labels;
1904
- for (var i=0; i<labels.length; ++i) {
1905
- RGraph.Text2(this, {
1906
- 'font': font,
1907
- 'size':text_size,
1908
- 'x':xpos + offsetx,
1909
- 'y':this.gutterTop + ((this.grapharea / labels.length) * (i + 1)) + offsety,
1910
- 'text': '-' + labels[i],
1911
- 'valign': 'center',
1912
- 'halign': align,
1913
- 'bordered': boxed,
1914
- 'tag':'scale'
1915
- });
1916
- }
1917
-
1918
-
1919
-
1920
-
1921
-
1922
-
1923
-
1924
-
1925
- /**
1926
- * Show the minimum value if its not zero
1927
- */
1928
- if (prop['chart.ymin'] != 0 || prop['chart.noxaxis'] || prop['chart.scale.zerostart']) {
1929
-
1930
- RGraph.Text2(this, {
1931
- 'font': font,
1932
- 'size': text_size,
1933
- 'x': xpos + offsetx,
1934
- 'y': this.gutterTop + offsety,
1935
- 'text': (this.scale2.min != 0 ? '-' : '') + RGraph.number_format(this,(this.scale2.min.toFixed((prop['chart.scale.decimals']))), units_pre, units_post),
1936
- 'valign': 'center',
1937
- 'halign': align,
1938
- 'bordered': boxed,
1939
- 'tag': 'scale'
1940
- });
1941
- }
1942
-
1943
- }
1944
-
1945
- co.fill();
1946
- };
1947
-
1948
-
1949
-
1950
- /**
1951
- * Draws the X axis in the middle
1952
- */
1953
- this.drawlabels_center =
1954
- this.Drawlabels_center = function ()
1955
- {
1956
- var ca = this.canvas;
1957
- var co = this.context;
1958
- var prop = this.properties;
1959
-
1960
- var font = prop['chart.text.font'];
1961
- var numYLabels = prop['chart.ylabels.count'];
1962
-
1963
- co.fillStyle = prop['chart.text.color'];
1964
-
1965
- if (prop['chart.xaxispos'] == 'center') {
1966
-
1967
- /**
1968
- * Draw the top labels
1969
- */
1970
- var text_size = prop['chart.text.size'];
1971
- var units_pre = prop['chart.units.pre'];
1972
- var units_post = prop['chart.units.post'];
1973
- var context = co;
1974
- var align = '';
1975
- var xpos = 0;
1976
- var boxed = false;
1977
- var ymin = prop['chart.ymin'];
1978
- var offsetx = prop['chart.ylabels.offsetx'];
1979
- var offsety = prop['chart.ylabels.offsety'];
1980
-
1981
- co.fillStyle = prop['chart.text.color'];
1982
- co.strokeStyle = 'black';
1983
-
1984
- if (prop['chart.ylabels.inside'] == true) {
1985
- var xpos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft + 5 : ca.width - this.gutterRight - 5;
1986
- var align = prop['chart.yaxispos'] == 'left' ? 'left' : 'right';
1987
- var boxed = true;
1988
- } else {
1989
- var xpos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft - 5 : ca.width - this.gutterRight + 5;
1990
- var align = prop['chart.yaxispos'] == 'left' ? 'right' : 'left';
1991
- var boxed = false;
1992
- }
1993
-
1994
-
1995
-
1996
-
1997
-
1998
-
1999
-
2000
-
2001
-
2002
-
2003
-
2004
-
2005
- /**
2006
- * Draw specific Y labels here so that the local variables can be reused
2007
- */
2008
- if (typeof(prop['chart.ylabels.specific']) == 'object' && prop['chart.ylabels.specific']) {
2009
-
2010
- var labels = prop['chart.ylabels.specific'];
2011
- var grapharea = ca.height - this.gutterTop - this.gutterBottom;
2012
-
2013
- // Draw the top halves labels
2014
- for (var i=0; i<labels.length; ++i) {
2015
-
2016
- var y = this.gutterTop + ((grapharea / 2) / (labels.length - 1)) * i;
2017
-
2018
- RGraph.Text2(this, {
2019
- 'font':font,
2020
- 'size':text_size,
2021
- 'x':xpos + offsetx,
2022
- 'y':y + offsety,
2023
- 'text':String(labels[i]),
2024
- 'valign':'center',
2025
- 'halign':align,
2026
- 'bordered':boxed,
2027
- 'tag': 'scale'
2028
- });
2029
- }
2030
-
2031
- // Draw the bottom halves labels
2032
- for (var i=labels.length-1; i>=1; --i) {
2033
-
2034
- var y = this.gutterTop + (grapharea * (i / ((labels.length - 1) * 2) )) + (grapharea / 2);
2035
-
2036
- RG.Text2(this, {
2037
- 'font':font,
2038
- 'size':text_size,
2039
- 'x':xpos + offsetx,
2040
- 'y':y + offsety,
2041
- 'text':String(labels[labels.length - i - 1]),
2042
- 'valign':'center',
2043
- 'halign':align,
2044
- 'bordered':boxed,
2045
- 'tag': 'scale'
2046
- });
2047
- }
2048
-
2049
- return;
2050
- }
2051
-
2052
-
2053
-
2054
-
2055
-
2056
-
2057
-
2058
-
2059
-
2060
-
2061
- /**
2062
- * Draw the top halfs labels
2063
- */
2064
- for (var i=0; i<this.scale2.labels.length; ++i) {
2065
- var y = this.gutterTop + this.halfgrapharea - ((this.halfgrapharea / numYLabels) * (i + 1));
2066
- var text = this.scale2.labels[i];
2067
- RG.Text2(this, {
2068
- 'font':font,
2069
- 'size':text_size,
2070
- 'x':xpos + offsetx,
2071
- 'y':y + offsety,
2072
- 'text':
2073
- text,
2074
- 'valign':
2075
- 'center',
2076
- 'halign': align,
2077
- 'bordered': boxed,
2078
- 'tag':'scale'
2079
- });
2080
- }
2081
-
2082
- /**
2083
- * Draw the bottom halfs labels
2084
- */
2085
- for (var i=(this.scale2.labels.length - 1); i>=0; --i) {
2086
- var y = this.gutterTop + ((this.halfgrapharea / numYLabels) * (i + 1)) + this.halfgrapharea;
2087
- var text = this.scale2.labels[i];
2088
- RG.Text2(this, {
2089
- 'font':font,
2090
- 'size':text_size,
2091
- 'x':xpos + offsetx,
2092
- 'y':y + offsety,
2093
- 'text': '-' + text,
2094
- 'valign':'center',
2095
- 'halign': align,
2096
- 'bordered': boxed,
2097
- 'tag':'scale'
2098
- });
2099
- }
2100
-
2101
-
2102
-
2103
-
2104
-
2105
- /**
2106
- * Show the minimum value if its not zero
2107
- */
2108
- if (this.scale2.min != 0 || prop['chart.scale.zerostart']) {
2109
- RG.Text2(this, {
2110
- 'font':font,
2111
- 'size':text_size,
2112
- 'x':xpos + offsetx,
2113
- 'y':this.gutterTop + this.halfgrapharea + offsety,
2114
- 'text': RG.number_format(this,(this.scale2.min.toFixed((prop['chart.scale.decimals']))), units_pre, units_post),
2115
- 'valign':'center',
2116
- 'valign':'center',
2117
- 'halign': align,
2118
- 'bordered': boxed,
2119
- 'tag':'scale'
2120
- });
2121
- }
2122
- }
2123
- };
2124
-
2125
-
2126
-
2127
-
2128
- /**
2129
- * Draws the X axdis at the bottom (the default)
2130
- */
2131
- this.drawlabels_bottom =
2132
- this.Drawlabels_bottom = function ()
2133
- {
2134
- var text_size = prop['chart.text.size'],
2135
- units_pre = prop['chart.units.pre'],
2136
- units_post = prop['chart.units.post'],
2137
- context = this.context,
2138
- align = prop['chart.yaxispos'] == 'left' ? 'right' : 'left',
2139
- font = prop['chart.text.font'],
2140
- numYLabels = prop['chart.ylabels.count'],
2141
- ymin = prop['chart.ymin'],
2142
- offsetx = prop['chart.ylabels.offsetx'],
2143
- offsety = prop['chart.ylabels.offsety']
2144
-
2145
- co.beginPath();
2146
-
2147
- co.fillStyle = prop['chart.text.color'];
2148
- co.strokeStyle = 'black';
2149
-
2150
- if (prop['chart.ylabels.inside'] == true) {
2151
- var xpos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft + 5 : ca.width - this.gutterRight - 5;
2152
- var align = prop['chart.yaxispos'] == 'left' ? 'left' : 'right';
2153
- var boxed = true;
2154
- } else {
2155
- var xpos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft - 5 : ca.width - this.gutterRight + 5;
2156
- var boxed = false;
2157
- }
2158
-
2159
- /**
2160
- * Draw specific Y labels here so that the local variables can be reused
2161
- */
2162
- if (prop['chart.ylabels.specific'] && typeof(prop['chart.ylabels.specific']) == 'object') {
2163
-
2164
- var labels = prop['chart.ylabels.specific'];
2165
- var grapharea = ca.height - this.gutterTop - this.gutterBottom;
2166
-
2167
- for (var i=0; i<labels.length; ++i) {
2168
- var y = this.gutterTop + (grapharea * (i / (labels.length - 1)));
2169
-
2170
- RGraph.Text2(this, {
2171
- 'font':font,
2172
- 'size':text_size,
2173
- 'x':xpos + offsetx,
2174
- 'y':y + offsety,
2175
- 'text': labels[i],
2176
- 'valign':'center',
2177
- 'halign': align,
2178
- 'bordered': boxed,
2179
- 'tag':'scale'
2180
- });
2181
- }
2182
-
2183
- return;
2184
- }
2185
-
2186
- var gutterTop = this.gutterTop;
2187
- var halfTextHeight = this.halfTextHeight;
2188
- var scale = this.scale;
2189
-
2190
-
2191
- for (var i=0; i<numYLabels; ++i) {
2192
- var text = this.scale2.labels[i];
2193
- RGraph.Text2(this, {
2194
- 'font':font,
2195
- 'size':text_size,
2196
- 'x':xpos + offsetx,
2197
- 'y':this.gutterTop + this.grapharea - ((this.grapharea / numYLabels) * (i+1)) + offsety,
2198
- 'text': text,
2199
- 'valign':'center',
2200
- 'halign': align,
2201
- 'bordered': boxed,
2202
- 'tag':'scale'
2203
- });
2204
- }
2205
-
2206
-
2207
- /**
2208
- * Show the minimum value if its not zero
2209
- */
2210
- if (prop['chart.ymin'] != 0 || prop['chart.noxaxis'] || prop['chart.scale.zerostart']) {
2211
- RG.Text2(this, {
2212
- 'font':font,
2213
- 'size':text_size,
2214
- 'x':xpos + offsetx,
2215
- 'y':ca.height - this.gutterBottom + offsety,
2216
- 'text': RG.number_format(this,(this.scale2.min.toFixed((prop['chart.scale.decimals']))), units_pre, units_post),
2217
- 'valign':'center',
2218
- 'halign': align,
2219
- 'bordered': boxed,
2220
- 'tag':'scale'
2221
- });
2222
- }
2223
-
2224
- co.fill();
2225
- };
2226
-
2227
-
2228
- /**
2229
- * This function is used by MSIE only to manually draw the shadow
2230
- *
2231
- * @param array coords The coords for the bar
2232
- */
2233
- this.drawIEShadow =
2234
- this.DrawIEShadow = function (coords)
2235
- {
2236
- var co = this.context;
2237
- var ca = this.canvas;
2238
- var prop = this.properties;
2239
-
2240
- var prevFillStyle = co.fillStyle;
2241
- var offsetx = prop['chart.shadow.offsetx'];
2242
- var offsety = prop['chart.shadow.offsety'];
2243
-
2244
- co.lineWidth = prop['chart.linewidth'];
2245
- co.fillStyle = prop['chart.shadow.color'];
2246
- co.beginPath();
2247
-
2248
- // Draw shadow here
2249
- co.fillRect(coords[0] + offsetx, coords[1] + offsety, coords[2], coords[3]);
2250
-
2251
- co.fill();
2252
-
2253
- // Change the fillstyle back to what it was
2254
- co.fillStyle = prevFillStyle;
2255
- };
2256
-
2257
-
2258
-
2259
-
2260
- /**
2261
- * Not used by the class during creating the graph, but is used by event handlers
2262
- * to get the coordinates (if any) of the selected bar
2263
- *
2264
- * @param object e The event object
2265
- * @param object OPTIONAL You can pass in the bar object instead of the
2266
- * function using "this"
2267
- */
2268
- this.getShape =
2269
- this.getBar = function (e)
2270
- {
2271
- // This facilitates you being able to pass in the bar object as a parameter instead of
2272
- // the function getting it from itself
2273
- var obj = arguments[1] ? arguments[1] : this;
2274
-
2275
- var mouseXY = RG.getMouseXY(e),
2276
- mouseX = mouseXY[0],
2277
- mouseY = mouseXY[1],
2278
- canvas = obj.canvas,
2279
- context = obj.context,
2280
- coords = obj.coords
2281
-
2282
- for (var i=0,len=coords.length; i<len; i+=1) {
2283
-
2284
- if (obj.coords[i].length == 0) {
2285
- continue;
2286
- }
2287
-
2288
- var left = coords[i][0],
2289
- top = coords[i][1],
2290
- width = coords[i][2],
2291
- height = coords[i][3],
2292
- prop = obj.properties
2293
-
2294
- // Old way of testing
2295
- //if (mouseX >= left && mouseX <= (left + width) && mouseY >= top && mouseY <= (top + height)) {
2296
-
2297
- // Recreate the path/rectangle so that it can be tested
2298
- // ** DO NOT STROKE OR FILL IT **
2299
- if (prop['chart.tooltips.hotspot.xonly']) {
2300
- pa2(co,
2301
- 'b r % % % %',
2302
- left,
2303
- this.gutterTop,
2304
- width,
2305
- ca.height - this.gutterBottom
2306
- );
2307
- } else {
2308
- pa2(co,
2309
- 'b r % % % %',
2310
- left,
2311
- top,
2312
- width,
2313
- height
2314
- );
2315
- }
2316
-
2317
- if (co.isPointInPath(mouseX, mouseY)) {
2318
-
2319
-
2320
- if (prop['chart.tooltips']) {
2321
- var tooltip = RG.parseTooltipText ? RG.parseTooltipText(prop['chart.tooltips'], i) : prop['chart.tooltips'][i];
2322
- }
2323
-
2324
- // Work out the dataset
2325
- var dataset = 0,
2326
- idx = i
2327
-
2328
- while (idx >= (typeof obj.data[dataset] === 'object' && obj.data[dataset] ? obj.data[dataset].length : 1)) {
2329
-
2330
- if (typeof obj.data[dataset] === 'number') {
2331
- idx -= 1;
2332
- } else if (obj.data[dataset]) { // Accounts for null being an object
2333
- idx -= obj.data[dataset].length;
2334
- } else {
2335
- idx -= 1;
2336
- }
2337
-
2338
- dataset++;
2339
- }
2340
-
2341
- if (typeof(obj.data[dataset]) == 'number') {
2342
- idx = null;
2343
- }
2344
-
2345
-
2346
- return {
2347
- 0: obj, 1: left, 2: top, 3: width, 4: height, 5: i,
2348
- 'object': obj, 'x': left, 'y': top, 'width': width, 'height': height, 'index': i, 'tooltip': tooltip, 'index_adjusted': idx, 'dataset': dataset
2349
- };
2350
- }
2351
- }
2352
-
2353
- return null;
2354
- };
2355
-
2356
-
2357
-
2358
-
2359
- /**
2360
- * This retrives the bar based on the X coordinate only.
2361
- *
2362
- * @param object e The event object
2363
- * @param object OPTIONAL You can pass in the bar object instead of the
2364
- * function using "this"
2365
- */
2366
- this.getShapeByX = function (e)
2367
- {
2368
- var canvas = e.target;
2369
- var mouseCoords = RGraph.getMouseXY(e);
2370
-
2371
-
2372
- // This facilitates you being able to pass in the bar object as a parameter instead of
2373
- // the function getting it from itself
2374
- var obj = arguments[1] ? arguments[1] : this;
2375
-
2376
-
2377
- /**
2378
- * Loop through the bars determining if the mouse is over a bar
2379
- */
2380
- for (var i=0,len=obj.coords.length; i<len; i++) {
2381
-
2382
- if (obj.coords[i].length == 0) {
2383
- continue;
2384
- }
2385
-
2386
- var mouseX = mouseCoords[0];
2387
- var mouseY = mouseCoords[1];
2388
- var left = obj.coords[i][0];
2389
- var top = obj.coords[i][1];
2390
- var width = obj.coords[i][2];
2391
- var height = obj.coords[i][3];
2392
- var prop = obj.properties;
2393
-
2394
- if (mouseX >= left && mouseX <= (left + width)) {
2395
-
2396
- if (prop['chart.tooltips']) {
2397
- var tooltip = RGraph.parseTooltipText ? RGraph.parseTooltipText(prop['chart.tooltips'], i) : prop['chart.tooltips'][i];
2398
- }
2399
-
2400
-
2401
-
2402
- return {
2403
- 0: obj, 1: left, 2: top, 3: width, 4: height, 5: i,
2404
- 'object': obj, 'x': left, 'y': top, 'width': width, 'height': height, 'index': i, 'tooltip': tooltip
2405
- };
2406
- }
2407
- }
2408
-
2409
- return null;
2410
- };
2411
-
2412
-
2413
- /**
2414
- * When you click on the chart, this method can return the Y value at that point. It works for any point on the
2415
- * chart (that is inside the gutters) - not just points within the Bars.
2416
- *
2417
- * EITHER:
2418
- *
2419
- * @param object arg The event object
2420
- *
2421
- * OR:
2422
- *
2423
- * @param object arg A two element array containing the X and Y coordinates
2424
- */
2425
- this.getValue = function (arg)
2426
- {
2427
- var co = this.context;
2428
- var ca = this.canvas;
2429
- var prop = this.properties;
2430
-
2431
- if (arg.length == 2) {
2432
- var mouseX = arg[0];
2433
- var mouseY = arg[1];
2434
- } else {
2435
- var mouseCoords = RGraph.getMouseXY(arg);
2436
- var mouseX = mouseCoords[0];
2437
- var mouseY = mouseCoords[1];
2438
- }
2439
-
2440
- if ( mouseY < prop['chart.gutter.top']
2441
- || mouseY > (ca.height - prop['chart.gutter.bottom'])
2442
- || mouseX < prop['chart.gutter.left']
2443
- || mouseX > (ca.width - prop['chart.gutter.right'])
2444
- ) {
2445
- return null;
2446
- }
2447
-
2448
- if (prop['chart.xaxispos'] == 'center') {
2449
- var value = (((this.grapharea / 2) - (mouseY - prop['chart.gutter.top'])) / this.grapharea) * (this.scale2.max - this.scale2.min)
2450
- value *= 2;
2451
-
2452
- if (value >= 0) {
2453
- value += this.scale2.min;
2454
- } else {
2455
- value -= this.scale2.min;
2456
- }
2457
-
2458
- } else if (prop['chart.xaxispos'] == 'top') {
2459
- var value = ((this.grapharea - (mouseY - prop['chart.gutter.top'])) / this.grapharea) * (this.scale2.max - this.scale2.min)
2460
- value = this.scale2.max - value;
2461
- value = Math.abs(value) * -1;
2462
- } else {
2463
- var value = ((this.grapharea - (mouseY - prop['chart.gutter.top'])) / this.grapharea) * (this.scale2.max - this.scale2.min)
2464
- value += this.scale2.min;
2465
- }
2466
-
2467
- return value;
2468
- };
2469
-
2470
-
2471
- /**
2472
- * This function can be used when the canvas is clicked on (or similar - depending on the event)
2473
- * to retrieve the relevant Y coordinate for a particular value.
2474
- *
2475
- * @param int value The value to get the Y coordinate for
2476
- */
2477
- this.getYCoord = function (value)
2478
- {
2479
-
2480
- if (value > this.scale2.max) {
2481
- return null;
2482
- }
2483
-
2484
- var co = this.context,
2485
- ca = this.canvas,
2486
- prop = this.properties;
2487
-
2488
- var y, xaxispos = prop['chart.xaxispos'];
2489
-
2490
- if (xaxispos == 'top') {
2491
-
2492
- // Account for negative numbers
2493
- if (value < 0) {
2494
- value = ma.abs(value);
2495
- }
2496
-
2497
- y = ((value - this.scale2.min) / (this.scale2.max - this.scale2.min)) * this.grapharea;
2498
- y = y + this.gutterTop
2499
-
2500
- } else if (xaxispos == 'center') {
2501
-
2502
- y = ((value - this.scale2.min) / (this.scale2.max - this.scale2.min)) * (this.grapharea / 2);
2503
- y = (this.grapharea / 2) - y;
2504
- y += this.gutterTop;
2505
-
2506
- } else {
2507
-
2508
- if (value < this.scale2.min) {
2509
- value = this.scale2.min;
2510
- }
2511
-
2512
- y = ((value - this.scale2.min) / (this.scale2.max - this.scale2.min));
2513
- y *= (ca.height - this.gutterTop - this.gutterBottom);
2514
-
2515
- y = ca.height - this.gutterBottom - y;
2516
- }
2517
-
2518
- return y;
2519
- };
2520
-
2521
-
2522
-
2523
- /**
2524
- * Each object type has its own Highlight() function which highlights the appropriate shape
2525
- *
2526
- * @param object shape The shape to highlight
2527
- */
2528
- this.highlight =
2529
- this.Highlight = function (shape)
2530
- {
2531
- if (typeof prop['chart.highlight.style'] === 'function') {
2532
- (prop['chart.highlight.style'])(shape);
2533
- } else {
2534
- // Add the new highlight
2535
- RG.Highlight.Rect(this, shape);
2536
- }
2537
- };
2538
-
2539
-
2540
-
2541
- /**
2542
- * The getObjectByXY() worker method
2543
- */
2544
- this.getObjectByXY = function (e)
2545
- {
2546
- var mouseXY = RG.getMouseXY(e);
2547
-
2548
- // Adjust the mouse Y coordinate for when the bar chart is
2549
- // a 3D variant
2550
- if (prop['chart.variant'] === '3d') {
2551
- var adjustment = prop['chart.variant.threed.angle'] * mouseXY[0];
2552
- mouseXY[1] -= adjustment;
2553
- }
2554
-
2555
-
2556
-
2557
- if (
2558
- mouseXY[0] >= prop['chart.gutter.left']
2559
- && mouseXY[0] <= (ca.width - prop['chart.gutter.right'])
2560
- && mouseXY[1] >= prop['chart.gutter.top']
2561
- && mouseXY[1] <= (ca.height - prop['chart.gutter.bottom'])
2562
- ) {
2563
-
2564
- return this;
2565
- }
2566
- };
2567
-
2568
-
2569
-
2570
-
2571
- /**
2572
- * This method handles the adjusting calculation for when the mouse is moved
2573
- *
2574
- * @param object e The event object
2575
- */
2576
- this.adjusting_mousemove =
2577
- this.Adjusting_mousemove = function (e)
2578
- {
2579
- /**
2580
- * Handle adjusting for the Bar
2581
- */
2582
- if (prop['chart.adjustable'] && RG.Registry.Get('chart.adjusting') && RG.Registry.Get('chart.adjusting').uid == this.uid) {
2583
-
2584
- // Rounding the value to the given number of decimals make the chart step
2585
- var value = Number(this.getValue(e));
2586
- var shape = this.getShapeByX(e);
2587
-
2588
- if (shape) {
2589
-
2590
- RG.Registry.Set('chart.adjusting.shape', shape);
2591
-
2592
- if (this.stackedOrGrouped && prop['chart.grouping'] == 'grouped') {
2593
-
2594
- var indexes = RG.sequentialIndexToGrouped(shape['index'], this.data);
2595
-
2596
- if (typeof this.data[indexes[0]] == 'number') {
2597
- this.data[indexes[0]] = Number(value);
2598
- } else if (!RG.is_null(this.data[indexes[0]])) {
2599
- this.data[indexes[0]][indexes[1]] = Number(value);
2600
- }
2601
- } else if (typeof this.data[shape['index']] == 'number') {
2602
-
2603
- this.data[shape['index']] = Number(value);
2604
- }
2605
-
2606
- RG.redrawCanvas(e.target);
2607
- RG.fireCustomEvent(this, 'onadjust');
2608
- }
2609
- }
2610
- };
2611
-
2612
-
2613
-
2614
-
2615
- /**
2616
- * This function positions a tooltip when it is displayed
2617
- *
2618
- * @param obj object The chart object
2619
- * @param int x The X coordinate specified for the tooltip
2620
- * @param int y The Y coordinate specified for the tooltip
2621
- * @param objec tooltip The tooltips DIV element
2622
- */
2623
- this.positionTooltip = function (obj, x, y, tooltip, idx)
2624
- {
2625
- var prop = obj.properties,
2626
- coordX = obj.coords[tooltip.__index__][0],
2627
- coordY = obj.coords[tooltip.__index__][1],
2628
- coordW = obj.coords[tooltip.__index__][2],
2629
- coordH = obj.coords[tooltip.__index__][3],
2630
- mouseXY = RG.getMouseXY(window.event),
2631
- canvasXY = RG.getCanvasXY(obj.canvas),
2632
- gutterLeft = prop['chart.gutter.left'],
2633
- gutterTop = prop['chart.gutter.top'],
2634
- width = tooltip.offsetWidth,
2635
- height = tooltip.offsetHeight,
2636
- value = obj.data_arr[tooltip.__index__]
2637
-
2638
-
2639
-
2640
- // Set the top position
2641
- tooltip.style.left = 0;
2642
- tooltip.style.top = window.event.pageY - height - 5 + 'px';
2643
-
2644
- /**
2645
- * If the tooltip is for a negative value - position it underneath the bar
2646
- */
2647
- //if (value < 0) {
2648
- //tooltip.style.top = canvasXY[1] + coordY + coordH + 'px';
2649
- //}
2650
-
2651
-
2652
- // By default any overflow is hidden
2653
- tooltip.style.overflow = '';
2654
-
2655
- // Inverted arrow
2656
- // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAFCAMAAACkeOZkAAAAK3RFWHRDcmVhdGlvbiBUaW1lAFNhdCA2IE9jdCAyMDEyIDEyOjQ5OjMyIC0wMDAw2S1RlgAAAAd0SU1FB9wKBgszM4Ed2k4AAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAEZ0FNQQAAsY8L/GEFAAAACVBMVEX/AAC9vb3//+92Pom0AAAAAXRSTlMAQObYZgAAAB1JREFUeNpjYAABRgY4YGRiRDCZYBwQE8qBMEEcAANCACqByy1sAAAAAElFTkSuQmCC
2657
-
2658
- // The arrow
2659
- //var img = new Image();
2660
- // img.style.position = 'absolute';
2661
- // img.id = '__rgraph_tooltip_pointer__';
2662
- // if (value >= 0) {
2663
- // //img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAICAYAAAAm06XyAAAARUlEQVQYV2P8///TfwYyASNIHzkGMDLyMYI1k2oASCNID1wzsQbANGJoJmQAskasmnEZgK4Rp2Z0A7BpxKsZZgAujSB5AB8hH/j9emSYAAAAAElFTkSuQmCC';
2664
- // img.src = '/images/tooltips-pointer-large.png?jkl';
2665
- // img.style.top = tooltip.offsetHeight + 'px';
2666
- // } else {
2667
- // img.src = '/images/tooltips-pointer-large.png?jkl';
2668
- // //img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAICAYAAAAm06XyAAAARUlEQVQYV2P8///TfwYyASNIHzkGMDLyMYI1k2oASCNID1wzsQbANGJoJmQAskasmnEZgK4Rp2Z0A7BpxKsZZgAujSB5AB8hH/j9emSYAAAAAElFTkSuQmCC';
2669
- // img.style.top = '-5px';
2670
- // }
2671
- //
2672
- //tooltip.appendChild(img);
2673
-
2674
- // Reposition the tooltip if at the edges:
2675
-
2676
- // LEFT edge
2677
- if ((canvasXY[0] + coordX + (coordW / 2) - (width / 2)) < 10) {
2678
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
2679
- //img.style.left = ((width * 0.1) - 8.5) + 'px';
2680
-
2681
- // RIGHT edge
2682
- } else if ((canvasXY[0] + coordX + (width / 2)) > doc.body.offsetWidth) {
2683
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
2684
- //img.style.left = ((width * 0.9) - 8.5) + 'px';
2685
-
2686
- // Default positioning - CENTERED
2687
- } else {
2688
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
2689
- //img.style.left = ((width * 0.5) - 8.5) + 'px';
2690
- }
2691
- };
2692
-
2693
-
2694
-
2695
-
2696
- /**
2697
- * This allows for easy specification of gradients
2698
- */
2699
- this.parseColors = function ()
2700
- {
2701
- // Save the original colors so that they can be restored when the canvas is reset
2702
- if (this.original_colors.length === 0) {
2703
- this.original_colors['chart.colors'] = RGraph.array_clone(prop['chart.colors']);
2704
- this.original_colors['chart.key.colors'] = RGraph.array_clone(prop['chart.key.colors']);
2705
- this.original_colors['chart.crosshairs.color'] = prop['chart.crosshairs.color'];
2706
- this.original_colors['chart.highlight.stroke'] = prop['chart.highlight.stroke'];
2707
- this.original_colors['chart.highlight.fill'] = prop['chart.highlight.fill'];
2708
- this.original_colors['chart.text.color'] = prop['chart.text.color'];
2709
- this.original_colors['chart.background.barcolor1'] = prop['chart.background.barcolor1'];
2710
- this.original_colors['chart.background.barcolor2'] = prop['chart.background.barcolor2'];
2711
- this.original_colors['chart.background.grid.color'] = prop['chart.background.grid.color'];
2712
- this.original_colors['chart.background.color'] = prop['chart.background.color'];
2713
- this.original_colors['chart.strokecolor'] = prop['chart.strokecolor'];
2714
- this.original_colors['chart.axis.color'] = prop['chart.axis.color'];
2715
- }
2716
-
2717
-
2718
- // chart.colors
2719
- var colors = prop['chart.colors'];
2720
- if (colors) {
2721
- for (var i=0; i<colors.length; ++i) {
2722
- colors[i] = this.parseSingleColorForGradient(colors[i]);
2723
- }
2724
- }
2725
-
2726
- // chart.key.colors
2727
- var colors = prop['chart.key.colors'];
2728
- if (colors) {
2729
- for (var i=0; i<colors.length; ++i) {
2730
- colors[i] = this.parseSingleColorForGradient(colors[i]);
2731
- }
2732
- }
2733
-
2734
- prop['chart.crosshairs.color'] = this.parseSingleColorForGradient(prop['chart.crosshairs.color']);
2735
- prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
2736
- prop['chart.highlight.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.fill']);
2737
- prop['chart.text.color'] = this.parseSingleColorForGradient(prop['chart.text.color']);
2738
- prop['chart.background.barcolor1'] = this.parseSingleColorForGradient(prop['chart.background.barcolor1']);
2739
- prop['chart.background.barcolor2'] = this.parseSingleColorForGradient(prop['chart.background.barcolor2']);
2740
- prop['chart.background.grid.color'] = this.parseSingleColorForGradient(prop['chart.background.grid.color']);
2741
- prop['chart.background.color'] = this.parseSingleColorForGradient(prop['chart.background.color']);
2742
- prop['chart.strokecolor'] = this.parseSingleColorForGradient(prop['chart.strokecolor']);
2743
- prop['chart.axis.color'] = this.parseSingleColorForGradient(prop['chart.axis.color']);
2744
- };
2745
-
2746
-
2747
-
2748
-
2749
- /**
2750
- * Use this function to reset the object to the post-constructor state. Eg reset colors if
2751
- * need be etc
2752
- */
2753
- this.reset = function ()
2754
- {
2755
- };
2756
-
2757
-
2758
-
2759
- /**
2760
- * This parses a single color value
2761
- */
2762
- this.parseSingleColorForGradient = function (color)
2763
- {
2764
- if (!color || typeof(color) != 'string') {
2765
- return color;
2766
- }
2767
-
2768
- if (color.match(/^gradient\((.*)\)$/i)) {
2769
-
2770
- var parts = RegExp.$1.split(':');
2771
-
2772
- // Create the gradient
2773
- var grad = co.createLinearGradient(0,ca.height - prop['chart.gutter.bottom'], 0, prop['chart.gutter.top']);
2774
-
2775
- var diff = 1 / (parts.length - 1);
2776
-
2777
- grad.addColorStop(0, RG.trim(parts[0]));
2778
-
2779
- for (var j=1,len=parts.length; j<len; ++j) {
2780
- grad.addColorStop(j * diff, RGraph.trim(parts[j]));
2781
- }
2782
- }
2783
-
2784
- return grad ? grad : color;
2785
- };
2786
-
2787
-
2788
-
2789
- this.drawBevel =
2790
- this.DrawBevel = function ()
2791
- {
2792
- var coords = this.coords;
2793
- var coords2 = this.coords2;
2794
-
2795
- var prop = this.properties;
2796
- var co = this.context;
2797
- var ca = this.canvas;
2798
-
2799
- if (prop['chart.grouping'] == 'stacked') {
2800
- for (var i=0; i<coords2.length; ++i) {
2801
- if (coords2[i] && coords2[i][0] && coords2[i][0][0]) {
2802
-
2803
- var x = coords2[i][0][0];
2804
- var y = coords2[i][0][1];
2805
- var w = coords2[i][0][2];
2806
-
2807
- var arr = [];
2808
- for (var j=0; j<coords2[i].length; ++j) {
2809
- arr.push(coords2[i][j][3]);
2810
- }
2811
- var h = RGraph.array_sum(arr);
2812
-
2813
-
2814
- co.save();
2815
-
2816
- co.strokeStyle = 'black';
2817
-
2818
- // Clip to the rect
2819
- co.beginPath();
2820
- co.rect(x, y, w, h);
2821
- co.clip();
2822
-
2823
- // Add the shadow
2824
- co.shadowColor = 'black';
2825
- co.shadowOffsetX = 0;
2826
- co.shadowOffsetY = 0;
2827
- co.shadowBlur = 20;
2828
-
2829
- co.beginPath();
2830
- co.rect(x - 3, y - 3, w + 6, h + 100);
2831
- co.lineWidth = 5;
2832
- co.stroke();
2833
- co.restore();
2834
- }
2835
- }
2836
- } else {
2837
-
2838
- for (var i=0; i<coords.length; ++i) {
2839
- if (coords[i]) {
2840
-
2841
- var x = coords[i][0];
2842
- var y = coords[i][1];
2843
- var w = coords[i][2];
2844
- var h = coords[i][3];
2845
-
2846
- var xaxispos = prop['chart.xaxispos'];
2847
- var xaxis_ycoord = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop;
2848
-
2849
-
2850
- co.save();
2851
-
2852
- co.strokeStyle = 'black';
2853
-
2854
- // Clip to the rect
2855
- co.beginPath();
2856
- co.rect(x, y, w, h);
2857
-
2858
- co.clip();
2859
-
2860
- // Add the shadow
2861
- co.shadowColor = 'black';
2862
- co.shadowOffsetX = 0;
2863
- co.shadowOffsetY = 0;
2864
- co.shadowBlur = 20;
2865
-
2866
- if (xaxispos == 'top' || (xaxispos == 'center' && (y + h) > xaxis_ycoord)) {
2867
- y = y - 100;
2868
- h = h + 100;
2869
- } else {
2870
- y = y;
2871
- h = h + 100;
2872
- }
2873
-
2874
- co.beginPath();
2875
- co.rect(x - 3, y - 3, w + 6, h + 6);
2876
- co.lineWidth = 5;
2877
- co.stroke();
2878
- co.restore();
2879
- }
2880
- }
2881
- }
2882
- };
2883
-
2884
-
2885
-
2886
-
2887
- /**
2888
- * This function handles highlighting an entire data-series for the interactive
2889
- * key
2890
- *
2891
- * @param int index The index of the data series to be highlighted
2892
- */
2893
- this.interactiveKeyHighlight = function (index)
2894
- {
2895
- this.coords2.forEach(function (value, idx, arr)
2896
- {
2897
- if (typeof value[index] == 'object' && value[index]) {
2898
-
2899
- var x = value[index][0]
2900
- var y = value[index][1]
2901
- var w = value[index][2]
2902
- var h = value[index][3]
2903
-
2904
- co.fillStyle = prop['chart.key.interactive.highlight.chart.fill'];
2905
- co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
2906
- co.lineWidth = 2;
2907
- co.strokeRect(x, y, w, h);
2908
- co.fillRect(x, y, w, h);
2909
- }
2910
- });
2911
- };
2912
-
2913
-
2914
-
2915
-
2916
- /**
2917
- * Using a function to add events makes it easier to facilitate method chaining
2918
- *
2919
- * @param string type The type of even to add
2920
- * @param function func
2921
- */
2922
- this.on = function (type, func)
2923
- {
2924
- if (type.substr(0,2) !== 'on') {
2925
- type = 'on' + type;
2926
- }
2927
-
2928
- this[type] = func;
2929
-
2930
- return this;
2931
- };
2932
-
2933
-
2934
-
2935
-
2936
- /**
2937
- * Draws the above labels
2938
- */
2939
- this.drawAboveLabels = function ()
2940
- {
2941
- var labels = prop['chart.labels.above'],
2942
- specific = prop['chart.labels.above.specific'],
2943
- color = prop['chart.labels.above.color'],
2944
- background= prop['chart.labels.above.background'],
2945
- decimals = prop['chart.labels.above.decimals'],
2946
- size = prop['chart.labels.above.size'],
2947
- angle = -1 * prop['chart.labels.above.angle'],
2948
- unitsPre = prop['chart.labels.above.units.pre'],
2949
- unitsPost = prop['chart.labels.above.units.post'],
2950
- coords = this.coords,
2951
- coords2 = this.coords2,
2952
- data = this.data,
2953
- ldata = RG.arrayLinearize(this.data),
2954
- offset = prop['chart.labels.above.offset'],
2955
- text_font = prop['chart.text.font'],
2956
- text_size = prop['chart.text.size'],
2957
- grouping = prop['chart.grouping']
2958
-
2959
-
2960
- // Turn off any shadow
2961
- RG.noShadow(this);
2962
-
2963
- // Color
2964
- co.fillStyle = typeof color === 'string' ? color : prop['chart.text.color'];
2965
-
2966
-
2967
- // This bit draws the text labels that appear above the bars if requested
2968
- if (labels && grouping === 'grouped') {
2969
- for (var i=0,len=data.length,sequentialIndex=0; i<len; i+=1) {
2970
-
2971
- // Alignment for regular, positive bars
2972
- if (typeof data[i] === 'number' && data[i] >= 0) {
2973
-
2974
- var angle = angle;
2975
- var halign = (angle ? 'left' : 'center');
2976
- var valign = angle !== 0 ? 'center' : 'bottom';
2977
-
2978
- RG.text2(this, {
2979
- 'font': text_font,
2980
- 'size': typeof size === 'number' ? size : text_size - 3,
2981
- 'x': coords2[i][0][0] + (coords2[i][0][2] / 2),
2982
- 'y': coords2[i][0][1] - offset,
2983
- 'text': specific ? (specific[sequentialIndex] || '') : RG.numberFormat(this, Number(typeof data[i] === 'object' ? data[i][0] : data[i]).toFixed(decimals), unitsPre, unitsPost),
2984
- 'halign': halign,
2985
- 'valign': valign,
2986
- 'angle': angle,
2987
- 'marker': false,
2988
- 'bounding': true,
2989
- 'bounding.fill': background,
2990
- 'bounding.stroke': 'rgba(0,0,0,0)',
2991
- 'tag': 'labels.above'
2992
- });
2993
-
2994
- sequentialIndex++;
2995
-
2996
-
2997
-
2998
-
2999
-
3000
-
3001
- // Alignment for regular, negative bars
3002
- } else if (typeof data[i] === 'number' && data[i] < 0) {
3003
-
3004
- var angle = angle;
3005
- var halign = angle ? 'right' : 'center';
3006
- var valign = angle !== 0 ? 'center' : 'top';
3007
-
3008
-
3009
- RG.text2(this, {
3010
- 'font': text_font,
3011
- 'size': typeof size === 'number' ? size : text_size - 3,
3012
- 'x': coords2[i][0][0] + (coords2[i][0][2] / 2),
3013
- 'y': coords2[i][0][1] + coords2[i][0][3] + offset,
3014
- 'text': specific ? (specific[sequentialIndex] || '') : RG.numberFormat(this, Number(typeof data[i] === 'object' ? data[i][0] : data[i]).toFixed(decimals), unitsPre, unitsPost),
3015
- 'halign': halign,
3016
- 'valign': valign,
3017
- 'angle': angle,
3018
- 'bounding': true,
3019
- 'bounding.fill': background,
3020
- 'bounding.stroke': 'rgba(0,0,0,0)',
3021
- 'marker': false,
3022
- 'tag': 'labels.above'
3023
- });
3024
-
3025
- sequentialIndex++;
3026
-
3027
-
3028
-
3029
-
3030
-
3031
-
3032
- // Alignment for grouped bars
3033
- } else if (typeof data[i] === 'object') {
3034
-
3035
- for (var j=0,len2=data[i].length; j<len2; j+=1) {
3036
-
3037
- var angle = angle;
3038
- var halign = data[i][j] < 0 ? 'right' : 'left';
3039
- halign = angle === 0 ? 'center' : halign;
3040
- var valign = data[i][j] < 0 ? 'top' : 'bottom';
3041
- valign = angle != 0 ? 'center' : valign;
3042
-
3043
- RG.text2(this, {
3044
- 'font': text_font,
3045
- 'size': typeof size === 'number' ? size : text_size - 3,
3046
- 'x': coords2[i][j][0] + (coords2[i][j][2] / 2),
3047
- 'y': coords2[i][j][1] + (data[i][j] < 0 ? coords2[i][j][3] + offset: -offset),
3048
- 'text': specific ? (specific[sequentialIndex] || '') : RG.numberFormat(this, Number(data[i][j]).toFixed(decimals), unitsPre, unitsPost),
3049
- 'halign': halign,
3050
- 'valign': valign,
3051
- 'angle': angle,
3052
- 'bounding': true,
3053
- 'bounding.fill': background,
3054
- 'bounding.stroke': 'rgba(0,0,0,0)',
3055
- 'marker': false,
3056
- 'tag': 'labels.above'
3057
- });
3058
- sequentialIndex++;
3059
- }
3060
- }
3061
- }
3062
-
3063
-
3064
-
3065
-
3066
-
3067
- /**
3068
- * STACKED bars
3069
- */
3070
- } else if (labels && grouping === 'stacked') {
3071
- for (var i=0,len=data.length,sequentialIndex=0; i<len; i+=1) {
3072
- if (typeof data[i] === 'object') {
3073
-
3074
- var angle = angle;
3075
- var halign = angle != 0 ? 'left' : 'center';
3076
- var valign = angle != 0 ? 'center' : 'bottom';
3077
-
3078
- RG.text2(this, {
3079
- 'font': text_font,
3080
- 'size': typeof size === 'number' ? size : text_size - 3,
3081
- 'x': coords2[i][0][0] + (coords2[i][0][2] / 2),
3082
- 'y': coords2[i][0][1] + (data[i][0] < 0 ? coords2[i][0][3] : 0) - offset,
3083
- 'text': specific ? (specific[sequentialIndex] || '') : RG.numberFormat(this, Number(RG.arraySum(data[i])).toFixed(decimals), unitsPre, unitsPost),
3084
- 'halign': halign,
3085
- 'valign': valign,
3086
- 'angle': angle,
3087
- 'bounding': true,
3088
- 'bounding.fill': background,
3089
- 'bounding.stroke': 'rgba(0,0,0,0)',
3090
- 'marker': false,
3091
- 'tag': 'labels.above'
3092
- });
3093
-
3094
- sequentialIndex += data[i].length;
3095
-
3096
- /**
3097
- * Regular numbers but in a stacked grouping
3098
- */
3099
- } else {
3100
-
3101
- var angle = angle;
3102
- var halign = angle != 0 ? 'left' : 'center';
3103
- var valign = angle != 0 ? 'center' : 'bottom';
3104
-
3105
- RG.text2(this, {
3106
- 'font': text_font,
3107
- 'size': typeof size === 'number' ? size : text_size - 3,
3108
- 'x': coords2[i][0][0] + (coords2[i][0][2] / 2),
3109
- 'y': coords2[i][0][1] + (data[i][0] < 0 ? coords2[i][0][3] : 0) - offset,
3110
- 'text': specific ? (specific[sequentialIndex] || '') : RG.numberFormat(this, Number(data[i]).toFixed(decimals), unitsPre, unitsPost),
3111
- 'halign': halign,
3112
- 'valign': valign,
3113
- 'angle': angle,
3114
- 'bounding': true,
3115
- 'bounding.fill': background,
3116
- 'bounding.stroke': 'rgba(0,0,0,0)',
3117
- 'marker': false,
3118
- 'tag': 'labels.above'
3119
- });
3120
-
3121
- sequentialIndex++;
3122
- }
3123
- }
3124
- }
3125
- };
3126
-
3127
-
3128
-
3129
-
3130
- /**
3131
- * This function runs once only
3132
- */
3133
- this.firstDrawFunc = function ()
3134
- {
3135
- };
3136
-
3137
-
3138
-
3139
-
3140
- /**
3141
- * Bar chart Wave effect This effect defaults to 30 frames - which is
3142
- * approximately half a second. This the prior, older implementation
3143
- * of the Wave effect. It can be slower due to the many timers set
3144
- *
3145
- * @param object obj The chart object
3146
- */
3147
- this.waveOld = function ()
3148
- {
3149
- var obj = this;
3150
- var opt = arguments[0] ? arguments[0] : {};
3151
- opt.frames = opt.frames ? opt.frames : 15;
3152
- opt.delay = opt.delay || 50;
3153
- var callback = arguments[1] ? arguments[1] : function () {};
3154
- var original_data = [];
3155
- var frame = [];
3156
- var length = obj.data.length;
3157
-
3158
- obj.draw();
3159
- //var scale = RGraph.getScale2(obj, {'max':obj.max});
3160
- obj.Set('chart.ymax', obj.scale2.max);
3161
- RG.clear(obj.canvas);
3162
-
3163
- for (var i=0,len=length; i<len; ++i) {
3164
- (function (idx)
3165
- {
3166
- original_data[idx] = obj.data[idx];
3167
- obj.data[idx] = typeof obj.data[idx] === 'object' ? [] : 0;
3168
- frame[idx] = typeof obj.data[idx] === 'object' ? [] : 0;
3169
- setTimeout(function () {iterator(idx, opt.frames);}, opt.delay * idx)
3170
- })(i);
3171
- }
3172
-
3173
- return this;
3174
-
3175
-
3176
- function iterator (idx, frames)
3177
- {
3178
- if (frame[idx] <= frames) {
3179
-
3180
- // Update the data point
3181
- if (typeof obj.data[idx] === 'number') {
3182
- obj.data[idx] = (frame[idx] / frames) * original_data[idx]
3183
-
3184
- } else if (typeof obj.data[idx] === 'object') {
3185
- for (var k=0,len=original_data[idx].length; k<len; ++k) {
3186
- obj.data[idx][k] = (frame[idx] / frames) * original_data[idx][k];
3187
- }
3188
- }
3189
-
3190
- RG.clear(obj.canvas);
3191
- RG.redrawCanvas(obj.canvas);
3192
-
3193
- ++frame[idx];
3194
- RG.Effects.updateCanvas(function () {iterator(idx, frames);});
3195
-
3196
- } else if (idx === (length - 1) ) {
3197
- callback(obj);
3198
- }
3199
- }
3200
- };
3201
-
3202
-
3203
-
3204
-
3205
- /**
3206
- * (new) Bar chart Wave effect. This is a rewrite that should be smoother
3207
- * because it just uses a single loop and not setTimeout
3208
- *
3209
- * @param object OPTIONAL An object map of options. You specify 'frames' here to give the number of frames in the effect
3210
- * @param function OPTIONAL A function that will be called when the effect is complete
3211
- */
3212
- this.wave = function ()
3213
- {
3214
- var obj = this,
3215
- opt = arguments[0] || {},
3216
- labelsAbove = this.get('labelsAbove');
3217
-
3218
- opt.frames = opt.frames || 60;
3219
- opt.startFrames = [];
3220
- opt.counters = [];
3221
-
3222
- var framesperbar = opt.frames / 3,
3223
- frame = -1,
3224
- callback = arguments[1] || function () {},
3225
- original = RG.arrayClone(obj.data);
3226
-
3227
- //
3228
- // turn off the labelsAbove option whilst animating
3229
- //
3230
- this.set('labelsAbove', false);
3231
-
3232
- for (var i=0,len=obj.data.length; i<len; i+=1) {
3233
- opt.startFrames[i] = ((opt.frames / 2) / (obj.data.length - 1)) * i;
3234
-
3235
- if (typeof obj.data[i] === 'object' && obj.data[i]) {
3236
- opt.counters[i] = [];
3237
- for (var j=0; j<obj.data[i].length; j++) {
3238
- opt.counters[i][j] = 0;
3239
- }
3240
- } else {
3241
- opt.counters[i] = 0;
3242
- }
3243
- }
3244
-
3245
- /**
3246
- * This stops the chart from jumping
3247
- */
3248
- obj.draw();
3249
- obj.Set('ymax', obj.scale2.max);
3250
- RG.clear(obj.canvas);
3251
-
3252
- function iterator ()
3253
- {
3254
- ++frame;
3255
-
3256
- for (var i=0,len=obj.data.length; i<len; i+=1) {
3257
- if (frame > opt.startFrames[i]) {
3258
- if (typeof obj.data[i] === 'number') {
3259
-
3260
- obj.data[i] = ma.min(
3261
- ma.abs(original[i]),
3262
- ma.abs(original[i] * ( (opt.counters[i]++) / framesperbar))
3263
- );
3264
-
3265
- // Make the number negative if the original was
3266
- if (original[i] < 0) {
3267
- obj.data[i] *= -1;
3268
- }
3269
- } else if (!RG.isNull(obj.data[i])) {
3270
- for (var j=0,len2=obj.data[i].length; j<len2; j+=1) {
3271
-
3272
- obj.data[i][j] = ma.min(
3273
- ma.abs(original[i][j]),
3274
- ma.abs(original[i][j] * ( (opt.counters[i][j]++) / framesperbar))
3275
- );
3276
-
3277
- // Make the number negative if the original was
3278
- if (original[i][j] < 0) {
3279
- obj.data[i][j] *= -1;
3280
- }
3281
- }
3282
- }
3283
- } else {
3284
- 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);
3285
- }
3286
- }
3287
-
3288
-
3289
- if (frame >= opt.frames) {
3290
-
3291
- if (labelsAbove) {
3292
- obj.set('labelsAbove', true);
3293
- RG.redraw();
3294
- }
3295
-
3296
- callback(obj);
3297
- } else {
3298
- RG.redrawCanvas(obj.canvas);
3299
- RG.Effects.updateCanvas(iterator);
3300
- }
3301
- }
3302
-
3303
- iterator();
3304
-
3305
- return this;
3306
- };
3307
-
3308
-
3309
-
3310
-
3311
- /**
3312
- * Color Wave effect. This fades in color sequentially like the wave effect
3313
- * makes the bars grow.
3314
- *
3315
- * @param object OPTIONAL An object map of options. You specify 'frames'
3316
- * here to give the number of frames in the effect
3317
- * @param function OPTIONAL A function that will be called when the effect
3318
- * is complete
3319
- */
3320
- this.colorWave = function ()
3321
- {
3322
- var obj = this,
3323
- opt = arguments[0] || {};
3324
- opt.frames = opt.frames || 60;
3325
- opt.startFrames = [];
3326
- opt.counters = [],
3327
- colors = obj.properties['chart.colors'];
3328
-
3329
- // If just one color is specified and colorsSequential is not, then
3330
- // pad the colors array out
3331
- if (colors.length <= obj.data.length) {
3332
- obj.set('chart.colors.sequential', true);
3333
- colors = RG.arrayPad(colors, obj.data.length, colors[colors.length - 1]);
3334
- }
3335
-
3336
- var framesperbar = opt.frames / 2,
3337
- frame = -1,
3338
- callback = arguments[1] || function () {},
3339
- originalColors = RG.arrayClone(obj.properties['chart.colors']);
3340
-
3341
-
3342
-
3343
- for (var i=0,len=originalColors.length; i<len; i+=1) {
3344
- opt.startFrames[i] = ((opt.frames / 2) / (originalColors.length - 1)) * i;
3345
- opt.counters[i] = 0;
3346
- }
3347
-
3348
-
3349
- function iterator ()
3350
- {
3351
- ++frame;
3352
-
3353
- for (var i=0,len=colors.length; i<len; i+=1) {
3354
- if (frame > opt.startFrames[i] && colors[i].match(/^rgba?\(([0-9 ]+),([0-9 ]+),([0-9 ]+)(,([ 0-9.]+)?)\)/)) {
3355
-
3356
- // DO NOT USE SPACES!
3357
- colors[i] = 'rgba({1},{2},{3},{4})'.format(
3358
- RegExp.$1,
3359
- RegExp.$2,
3360
- RegExp.$3,
3361
- (frame - opt.startFrames[i]) / framesperbar
3362
- );
3363
- } else {
3364
- colors[i] = colors[i].replace(/,[0-9. ]+\)/, ',0)');
3365
- }
3366
- }
3367
-
3368
-
3369
- if (frame >= opt.frames) {
3370
- callback(obj);
3371
- } else {
3372
- RG.redrawCanvas(obj.canvas);
3373
- RG.Effects.updateCanvas(iterator);
3374
- }
3375
- }
3376
-
3377
- iterator();
3378
-
3379
- return this;
3380
- };
3381
-
3382
-
3383
-
3384
-
3385
- /**
3386
- * Grow
3387
- *
3388
- * The Bar chart Grow effect gradually increases the values of the bars
3389
- *
3390
- * @param object An object of options - eg: {frames: 30}
3391
- * @param function A function to call when the effect is complete
3392
- */
3393
- this.grow = function ()
3394
- {
3395
- // Callback
3396
- var opt = arguments[0] || {},
3397
- frames = opt.frames || 30,
3398
- frame = 0,
3399
- callback = arguments[1] || function () {},
3400
- obj = this,
3401
- labelsAbove = this.get('labelsAbove')
3402
-
3403
- //
3404
- // turn off the labelsAbove option whilst animating
3405
- //
3406
- this.set('labelsAbove', false);
3407
-
3408
- // Save the data
3409
- this.original_data = RG.arrayClone(this.data);
3410
-
3411
-
3412
- // Stop the scale from changing by setting chart.ymax (if it's not already set)
3413
- if (prop['chart.ymax'] == null) {
3414
-
3415
- var ymax = 0;
3416
-
3417
- for (var i=0; i<obj.data.length; ++i) {
3418
- if (RG.isArray(this.data[i]) && prop['chart.grouping'] === 'stacked') {
3419
- ymax = ma.max(ymax, ma.abs(RG.arraySum(this.data[i])));
3420
-
3421
- } else if (RG.isArray(this.data[i]) && prop['chart.grouping'] === 'grouped') {
3422
-
3423
- for (var j=0,group=[]; j<this.data[i].length; j++) {
3424
- group.push(ma.abs(this.data[i][j]));
3425
- }
3426
-
3427
- ymax = ma.max(ymax, ma.abs(RG.arrayMax(group)));
3428
-
3429
- } else {
3430
- ymax = ma.max(ymax, ma.abs(this.data[i]));
3431
- }
3432
- }
3433
-
3434
- var scale = RG.getScale2(this, {'max':ymax});
3435
- this.Set('chart.ymax', scale.max);
3436
- }
3437
-
3438
-
3439
-
3440
- var iterator = function ()
3441
- {
3442
- var easingMultiplier = RG.Effects.getEasingMultiplier(frames, frame);
3443
-
3444
- // Alter the Bar chart data depending on the frame
3445
- for (var j=0,len=obj.original_data.length; j<len; ++j) {
3446
- if (typeof obj.data[j] === 'object') {
3447
- for (var k=0,len2=obj.data[j].length; k<len2; ++k) {
3448
- obj.data[j][k] = easingMultiplier * obj.original_data[j][k];
3449
- }
3450
- } else {
3451
- obj.data[j] = easingMultiplier * obj.original_data[j];
3452
- }
3453
- }
3454
-
3455
-
3456
-
3457
-
3458
- //RGraph.clear(obj.canvas);
3459
- RGraph.redrawCanvas(obj.canvas);
3460
-
3461
-
3462
-
3463
-
3464
- if (frame < frames) {
3465
- frame += 1;
3466
-
3467
- RG.Effects.updateCanvas(iterator);
3468
-
3469
- // Call the callback function
3470
- } else {
3471
- if (labelsAbove) {
3472
- obj.set('labelsAbove', true);
3473
- RG.redraw();
3474
- }
3475
- callback(obj);
3476
- }
3477
- };
3478
-
3479
- iterator();
3480
-
3481
- return this;
3482
- };
3483
-
3484
-
3485
-
3486
-
3487
- //
3488
- // Draws error-bars for the Bar and Line charts
3489
- //
3490
- this.drawErrorbars = function ()
3491
- {
3492
- var coords = this.coords,
3493
- color = prop['chart.errorbars.color'] || 'black',
3494
- default_halfwidth = ma.min(prop['chart.errorbars.capped.width'], coords[0][2]) / 2,
3495
- x = 0,
3496
- errorbars = prop['chart.errorbars'],
3497
- length = 0;
3498
-
3499
-
3500
- // If not capped set the width of the cqap to zero
3501
- if (!prop['chart.errorbars.capped']) {
3502
- prop['chart.errorbars.capped.width'] = 0;
3503
- halfwidth = 0;
3504
- }
3505
-
3506
- // Set the linewidth
3507
- co.lineWidth = prop['chart.errorbars.linewidth'];
3508
-
3509
-
3510
-
3511
-
3512
- for (var i=0; i<coords.length; ++i) {
3513
-
3514
-
3515
- // Default to black
3516
- color = prop['chart.errorbars.color'] || 'black';
3517
-
3518
- // Set the perbar linewidth if the fourth option in the array
3519
- // is specified
3520
- if (errorbars[i] && typeof errorbars[i][3] === 'number') {
3521
- co.lineWidth = errorbars[i][3];
3522
- }
3523
-
3524
- // Set the halfwidth
3525
- var halfwidth = (errorbars[i]&& typeof errorbars[i][4] === 'number') ? errorbars[i][4] / 2 : default_halfwidth;
3526
-
3527
- if (!prop['chart.errorbars.capped']) {
3528
- halfwidth = 0;
3529
- }
3530
-
3531
-
3532
-
3533
- // Calulate the pixel size
3534
- if (typeof errorbars[i] === 'number') {
3535
-
3536
- length = ma.abs(this.getYCoord(errorbars[i]) - this.getYCoord(0));
3537
-
3538
- if (length) {
3539
- pa2(
3540
- co,
3541
- 'b m % % l % % l % % l % % s %',
3542
- coords[i][0] + (coords[i][2] / 2),
3543
- coords[i][1],
3544
- coords[i][0] + (coords[i][2] / 2),
3545
- coords[i][1] - length,
3546
- coords[i][0] + (coords[i][2] / 2) - halfwidth,
3547
- ma.round(coords[i][1] - length),
3548
- coords[i][0] + (coords[i][2] / 2) + halfwidth,
3549
- ma.round(coords[i][1] - length),
3550
- color
3551
- );
3552
- }
3553
- } else if (typeof errorbars[i] === 'object' && !RG.isNull(errorbars[i])) {
3554
-
3555
- var positiveLength = ma.abs(this.getYCoord(errorbars[i][0]) - this.getYCoord(0));
3556
-
3557
- // Color
3558
- if (typeof errorbars[i][1] === 'string') {
3559
- color = errorbars[i][1];
3560
-
3561
- } else if (typeof errorbars[i][2] === 'string') {
3562
- color = errorbars[i][2];
3563
- }
3564
-
3565
- // Cap width
3566
- halfwidth = typeof errorbars[i][4] === 'number' ? errorbars[i][4] / 2 : default_halfwidth;
3567
-
3568
- if (!prop['chart.errorbars.capped']) {
3569
- halfwidth = 0;
3570
- }
3571
-
3572
- if (!RG.isNull(errorbars[i][0])) {
3573
- pa2(
3574
- co,
3575
- 'b m % % l % % l % % l % % s %',
3576
- coords[i][0] + (coords[i][2] / 2),
3577
- coords[i][1],
3578
- coords[i][0] + (coords[i][2] / 2),
3579
- coords[i][1] - positiveLength,
3580
- coords[i][0] + (coords[i][2] / 2) - halfwidth,
3581
- ma.round(coords[i][1] - positiveLength),
3582
- coords[i][0] + (coords[i][2] / 2) + halfwidth,
3583
- ma.round(coords[i][1] - positiveLength),
3584
- color
3585
- );
3586
- }
3587
-
3588
- if (typeof errorbars[i][1] === 'number') {
3589
-
3590
- var negativeLength = ma.abs(this.getYCoord(errorbars[i][1]) - this.getYCoord(0));
3591
-
3592
- pa2(
3593
- co,
3594
- 'b m % % l % % l % % l % % s %',
3595
- coords[i][0] + (coords[i][2] / 2),
3596
- coords[i][1],
3597
- coords[i][0] + (coords[i][2] / 2),
3598
- coords[i][1] + negativeLength,
3599
- coords[i][0] + (coords[i][2] / 2) - halfwidth,
3600
- ma.round(coords[i][1] + negativeLength),
3601
- coords[i][0] + (coords[i][2] / 2) + halfwidth,
3602
- ma.round(coords[i][1] + negativeLength),
3603
- color
3604
- );
3605
- }
3606
- }
3607
-
3608
-
3609
- // Reset the perbar linewidth to the default if the fourth option
3610
- // in the array was specified specified
3611
- if (errorbars[i] && typeof errorbars[i][3] === 'number') {
3612
- co.lineWidth = prop['chart.errorbars.linewidth'];
3613
- }
3614
- }
3615
- };
3616
-
3617
-
3618
-
3619
-
3620
- /**
3621
- * Register the object
3622
- */
3623
- RG.register(this);
3624
-
3625
-
3626
-
3627
-
3628
- /**
3629
- * This is the 'end' of the constructor so if the first argument
3630
- * contains configuration dsta - handle that.
3631
- */
3632
- if (parseConfObjectForOptions) {
3633
- RG.parseObjectStyleConfig(this, conf.options);
3634
- }
3635
- };
3636
-
3637
-
3638
-
3639
-
3640
-
3641
- /*********************************************************************************************************
3642
- * This is the combined bar and Line class which makes creating bar/line combo charts a little bit easier *
3643
- /*********************************************************************************************************/
3644
-
3645
-
3646
-
3647
-
3648
-
3649
-
3650
-
3651
- RGraph.CombinedChart = function ()
3652
- {
3653
- /**
3654
- * Create a default empty array for the objects
3655
- */
3656
- this.objects = [];
3657
- var objects = [];
3658
-
3659
- if (RGraph.isArray(arguments[0])) {
3660
- objects = arguments[0];
3661
- } else {
3662
-
3663
- for (var i=0; i<arguments.length; i+=1) {
3664
-
3665
- objects[i] = arguments[i];
3666
- }
3667
- }
3668
-
3669
- for (var i=0; i<objects.length; ++i) {
3670
-
3671
- this.objects[i] = objects[i];
3672
-
3673
- /**
3674
- * Set the Line chart gutters to match the Bar chart gutters
3675
- */
3676
- this.objects[i].set({
3677
- gutterLeft: this.objects[0].get('gutter.left'), // Needs to use the dot form to skirt an IE9 bug
3678
- gutterRight: this.objects[0].get('gutter.right'), // Needs to use the dot form to skirt an IE9 bug
3679
- gutterTop: this.objects[0].get('gutter.top'), // Needs to use the dot form to skirt an IE9 bug
3680
- gutterBottom: this.objects[0].get('gutter.bottom') // Needs to use the dot form to skirt an IE9 bug
3681
- });
3682
-
3683
- if (this.objects[i].type == 'line') {
3684
-
3685
- var obj = this.objects[i];
3686
-
3687
- /**
3688
- * Set the line chart hmargin
3689
- */
3690
- obj.set('hmargin', ((this.objects[0].canvas.width - this.objects[0].Get('chart.gutter.right') - this.objects[0].Get('chart.gutter.left')) / this.objects[0].data.length) / 2 );
3691
-
3692
-
3693
- /**
3694
- * No labels, axes or grid on the Line chart
3695
- */
3696
- obj.set('noaxes', true);
3697
- obj.set('backgroundGrid', false);
3698
- obj.set('ylabels', false);
3699
- }
3700
-
3701
- /**
3702
- * Resizing
3703
- */
3704
- if (this.objects[i].get('chart.resizable')) {
3705
- var resizable_object = obj;
3706
- }
3707
- }
3708
-
3709
- /**
3710
- * Resizing
3711
- */
3712
- if (resizable_object) {
3713
- /**
3714
- * This recalculates the Line chart hmargin when the chart is resized
3715
- */
3716
- function myOnresizebeforedraw (obj)
3717
- {
3718
- var gutterLeft = obj.get('gutterLeft');
3719
- var gutterRight = obj.get('gutterRight');
3720
-
3721
- obj.set('hmargin', (obj.canvas.width - gutterLeft - gutterRight) / (obj.original_data[0].length * 2));
3722
- }
3723
-
3724
- RGraph.AddCustomEventListener(
3725
- resizable_object,
3726
- 'onresizebeforedraw',
3727
- myOnresizebeforedraw
3728
- );
3729
- }
3730
- };
3731
-
3732
-
3733
-
3734
-
3735
- /**
3736
- * The Add method can be used to add methods to the CombinedChart object.
3737
- */
3738
- RGraph.CombinedChart.prototype.add =
3739
- RGraph.CombinedChart.prototype.Add = function (obj)
3740
- {
3741
- this.objects.push(obj);
3742
- };
3743
-
3744
-
3745
- /**
3746
- * The Draw method goes through all of the objects drawing them (sequentially)
3747
- */
3748
- RGraph.CombinedChart.prototype.draw =
3749
- RGraph.CombinedChart.prototype.Draw = function ()
3750
- {
3751
- for (var i=0; i<this.objects.length; ++i) {
3752
- if (this.objects[i].properties['chart.combinedchart.effect']) {
3753
-
3754
- var options = this.objects[i].properties['chart.combinedchart.effect.options'] ? eval('(' + this.objects[i].properties['chart.combinedchart.effect.options'] + ')') : null;
3755
-
3756
- (this.objects[i][this.objects[i].properties['chart.combinedchart.effect']])
3757
- (
3758
- options,
3759
- this.objects[i].properties['chart.combinedchart.effect.callback']
3760
- )
3761
- } else {
3762
- this.objects[i].draw();
3763
- }
3764
- }
3765
- };
2
+ RGraph=window.RGraph||{isRGraph:true};RGraph.Bar=function(conf)
3
+ {if(typeof conf==='object'&&typeof conf.data==='object'&&typeof conf.id==='string'){var id=conf.id,canvas=document.getElementById(id),data=conf.data,parseConfObjectForOptions=true}else{var id=conf,canvas=document.getElementById(id),data=arguments[1]}
4
+ this.id=id;this.canvas=canvas;this.context=this.canvas.getContext('2d');this.canvas.__object__=this;this.type='bar';this.max=0;this.stackedOrGrouped=false;this.isRGraph=true;this.uid=RGraph.CreateUID();this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID();this.colorsParsed=false;this.original_colors=[];this.cachedBackgroundCanvas=null;this.firstDraw=true;this.properties={'chart.background.barcolor1':'rgba(0,0,0,0)','chart.background.barcolor2':'rgba(0,0,0,0)','chart.background.grid':true,'chart.background.grid.color':'#ddd','chart.background.grid.width':1,'chart.background.grid.hsize':20,'chart.background.grid.vsize':20,'chart.background.grid.vlines':true,'chart.background.grid.hlines':true,'chart.background.grid.border':true,'chart.background.grid.autofit':true,'chart.background.grid.autofit.align':true,'chart.background.grid.autofit.numhlines':5,'chart.background.grid.autofit.numvlines':20,'chart.background.grid.dashed':false,'chart.background.grid.dotted':false,'chart.background.image.stretch':true,'chart.background.image.x':null,'chart.background.image.y':null,'chart.background.image.w':null,'chart.background.image.h':null,'chart.background.image.align':null,'chart.background.color':null,'chart.background.hbars':null,'chart.numyticks':10,'chart.hmargin':5,'chart.hmargin.grouped':1,'chart.strokecolor':'rgba(0,0,0,0)','chart.axis.color':'black','chart.axis.linewidth':1,'chart.gutter.top':25,'chart.gutter.bottom':30,'chart.gutter.left':25,'chart.gutter.right':25,'chart.labels':null,'chart.labels.bold':false,'chart.labels.color':null,'chart.labels.ingraph':null,'chart.labels.above':false,'chart.labels.above.decimals':0,'chart.labels.above.size':null,'chart.labels.above.color':null,'chart.labels.above.background':'rgba(0,0,0,0)','chart.labels.above.angle':null,'chart.labels.above.offset':4,'chart.labels.above.units.pre':'','chart.labels.above.units.post':'','chart.ylabels':true,'chart.ylabels.count':5,'chart.ylabels.inside':false,'chart.ylabels.offsetx':0,'chart.ylabels.offsety':0,'chart.labels.offsetx':0,'chart.labels.offsety':0,'chart.xaxispos':'bottom','chart.yaxispos':'left','chart.text.angle':0,'chart.text.color':'black','chart.text.size':12,'chart.text.font':'Segoe UI, Arial, Verdana, sans-serif','chart.text.accessible':true,'chart.text.accessible.overflow':'visible','chart.text.accessible.pointerevents':true,'chart.ymin':0,'chart.ymax':null,'chart.title':'','chart.title.font':null,'chart.title.background':null,'chart.title.hpos':null,'chart.title.vpos':null,'chart.title.bold':true,'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':null,'chart.title.yaxis.x':null,'chart.title.yaxis.y':null,'chart.title.xaxis.x':null,'chart.title.xaxis.y':null,'chart.title.x':null,'chart.title.y':null,'chart.title.halign':null,'chart.title.valign':null,'chart.colors':['red','#0f0','blue','pink','orange','cyan','black','white','green','magenta'],'chart.colors.sequential':false,'chart.colors.reverse':false,'chart.grouping':'grouped','chart.variant':'bar','chart.variant.sketch.verticals':true,'chart.variant.threed.xaxis':true,'chart.variant.threed.yaxis':true,'chart.variant.threed.angle':0.1,'chart.variant.threed.offsetx':10,'chart.variant.threed.offsety':5,'chart.shadow':false,'chart.shadow.color':'#aaa','chart.shadow.offsetx':0,'chart.shadow.offsety':0,'chart.shadow.blur':15,'chart.tooltips':null,'chart.tooltips.effect':'fade','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.event':'onclick','chart.tooltips.highlight':true,'chart.tooltips.hotspot.xonly':false,'chart.highlight.stroke':'rgba(0,0,0,0)','chart.highlight.fill':'rgba(255,255,255,0.7)','chart.key':null,'chart.key.background':'white','chart.key.position':'graph','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.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.halign':'right','chart.key.color.shape':'square','chart.key.rounded':true,'chart.key.text.size':10,'chart.key.linewidth':1,'chart.key.colors':null,'chart.key.text.color':'black','chart.contextmenu':null,'chart.units.pre':'','chart.units.post':'','chart.scale.decimals':0,'chart.scale.point':'.','chart.scale.thousand':',','chart.scale.round':false,'chart.scale.zerostart':true,'chart.crosshairs':false,'chart.crosshairs.color':'#333','chart.crosshairs.hline':true,'chart.crosshairs.vline':true,'chart.linewidth':1,'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.resizable':false,'chart.resize.handle.background':null,'chart.adjustable':false,'chart.noaxes':false,'chart.noxaxis':false,'chart.noyaxis':false,'chart.events.click':null,'chart.events.mousemove':null,'chart.numxticks':null,'chart.bevel':false,'chart.errorbars':false,'chart.errorbars.color':'black','chart.errorbars.capped':true,'chart.errorbars.capped.width':14,'chart.errorbars.linewidth':1,'chart.combinedchart.effect':null,'chart.combinedchart.effect.options':null,'chart.combinedchart.effect.callback':null,'chart.clearto':'rgba(0,0,0,0)'}
5
+ if(!this.canvas){alert('[BAR] No canvas support');return;}
6
+ for(var i=0;i<data.length;++i){if(typeof data[i]==='string'){data[i]=parseFloat(data[i]);}else if(typeof data[i]==='object'&&data[i]){for(var j=0;j<data[i].length;++j){if(typeof data[i][j]==='string'){data[i][j]=parseFloat(data[i][j]);}}}else if(typeof data[i]==='undefined'){data[i]=null;}}
7
+ for(var i=0;i<data.length;++i){if(typeof data[i]==='object'&&!RGraph.is_null(data[i])){this.stackedOrGrouped=true;}}
8
+ var linear_data=RGraph.arrayLinearize(data);for(var i=0;i<linear_data.length;++i){this['$'+i]={};}
9
+ this.data=data;this.original_data=RGraph.arrayClone(data);this.coords=[];this.coords2=[];this.coordsText=[];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 arguments[0]==='object'){RG.parseObjectStyleConfig(this,arguments[0]);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.xlabels.offset'){name='chart.labels.offsety';}
17
+ if(name=='chart.labels.abovebar'){name='chart.labels.above';}
18
+ if(name=='chart.strokestyle'){name='chart.strokecolor';}
19
+ if(name=='chart.xaxispos'){if(value!='bottom'&&value!='center'&&value!='top'){alert('[BAR] ('+this.id+') chart.xaxispos should be top, center or bottom. Tried to set it to: '+value+' Changing it to center');value='center';}
20
+ if(value=='top'){for(var i=0;i<this.data.length;++i){if(typeof(this.data[i])=='number'&&this.data[i]>0){alert('[BAR] The data element with index '+i+' should be negative');}}}}
21
+ if(name.toLowerCase()=='chart.linewidth'&&value==0){value=0.0001;}
22
+ prop[name]=value;return this;};this.get=this.Get=function(name)
23
+ {if(name.substr(0,6)!='chart.'){name='chart.'+name;}
24
+ while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
25
+ return prop[name];};this.draw=this.Draw=function()
26
+ {if(typeof(prop['chart.background.image'])=='string'){RG.DrawBackgroundImage(this);}
27
+ RG.FireCustomEvent(this,'onbeforedraw');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);}}
28
+ if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
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'];if((prop['chart.variant']=='pyramid'||prop['chart.variant']=='dot')&&typeof(prop['chart.tooltips'])=='object'&&prop['chart.tooltips']&&prop['chart.tooltips'].length>0){alert('[BAR] ('+this.id+') Sorry, tooltips are not supported with dot or pyramid charts');}
30
+ this.coords=[];this.coords2=[];this.coordsText=[];this.max=0;this.grapharea=ca.height-this.gutterTop-this.gutterBottom;this.halfgrapharea=this.grapharea/2;this.halfTextHeight=prop['chart.text.size']/2;RG.background.Draw(this);this.drawbars();this.drawAxes();this.DrawLabels();if(prop['chart.bevel']||prop['chart.bevelled']){this.DrawBevel();}
31
+ 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
+ if(prop['chart.errorbars']){this.drawErrorbars();}
34
+ if(prop['chart.labels.ingraph']){RG.DrawInGraphLabels(this);}
35
+ if(prop['chart.resizable']){RG.AllowResizing(this);}
36
+ RG.InstallEventListeners(this);if(this.firstDraw){RG.fireCustomEvent(this,'onfirstdraw');this.firstDraw=false;this.firstDrawFunc();}
37
+ RG.fireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
38
+ {func(this);return this;};this.drawAxes=this.DrawAxes=function()
39
+ {if(prop['chart.noaxes']){return;}
40
+ var xaxispos=prop['chart.xaxispos'];var yaxispos=prop['chart.yaxispos'];var isSketch=prop['chart.variant']=='sketch';co.beginPath();co.strokeStyle=prop['chart.axis.color'];co.lineWidth=prop['chart.axis.linewidth']+0.001;if(RG.ISSAFARI==-1){co.lineCap='square';}
41
+ if(prop['chart.noyaxis']==false){if(yaxispos=='right'){co.moveTo(ca.width-this.gutterRight+(isSketch?3:0),this.gutterTop-(isSketch?3:0));co.lineTo(ca.width-this.gutterRight-(isSketch?2:0),ca.height-this.gutterBottom+(isSketch?5:0));}else{co.moveTo(this.gutterLeft-(isSketch?2:0),this.gutterTop-(isSketch?5:0));co.lineTo(this.gutterLeft-(isSketch?1:0),ca.height-this.gutterBottom+(isSketch?5:0));}}
42
+ if(prop['chart.noxaxis']==false){if(xaxispos=='center'){co.moveTo(this.gutterLeft-(isSketch?5:0),Math.round(((ca.height-this.gutterTop-this.gutterBottom)/2)+this.gutterTop+(isSketch?2:0)));co.lineTo(ca.width-this.gutterRight+(isSketch?5:0),Math.round(((ca.height-this.gutterTop-this.gutterBottom)/2)+this.gutterTop-(isSketch?2:0)));}else if(xaxispos=='top'){co.moveTo(this.gutterLeft-(isSketch?3:0),this.gutterTop-(isSketch?3:0));co.lineTo(ca.width-this.gutterRight+(isSketch?5:0),this.gutterTop+(isSketch?2:0));}else{co.moveTo(this.gutterLeft-(isSketch?5:0),ma.round(this.getYCoord(0)-(isSketch?2:0)));co.lineTo(ca.width-this.gutterRight+(isSketch?8:0),ma.round(this.getYCoord(0)+(isSketch?2:0)));}}
43
+ var numYTicks=prop['chart.numyticks'];if(prop['chart.noyaxis']==false&&!isSketch){var yTickGap=(ca.height-this.gutterTop-this.gutterBottom)/numYTicks;var xpos=yaxispos=='left'?this.gutterLeft:ca.width-this.gutterRight;if(this.properties['chart.numyticks']>0){for(y=this.gutterTop;xaxispos=='center'?y<=(ca.height-this.gutterBottom):y<(ca.height-this.gutterBottom+(xaxispos=='top'?1:0));y+=yTickGap){if(xaxispos=='center'&&y==(this.gutterTop+(this.grapharea/2))){continue;}
44
+ if(xaxispos=='top'&&y==this.gutterTop){continue;}
45
+ co.moveTo(xpos+(yaxispos=='left'?0:0),ma.round(y));co.lineTo(xpos+(yaxispos=='left'?-3:3),ma.round(y));}
46
+ if(xaxispos==='bottom'&&prop['chart.ymin']!==0){co.moveTo(xpos+(yaxispos=='left'?0:0),ma.round(ca.height-prop['chart.gutter.bottom']));co.lineTo(xpos+(yaxispos=='left'?-3:3),ma.round(ca.height-prop['chart.gutter.bottom']));}}
47
+ if(prop['chart.noxaxis']){if(xaxispos=='center'){co.moveTo(xpos+(yaxispos=='left'?-3:3),Math.round(ca.height/2));co.lineTo(xpos,Math.round(ca.height/2));}else if(xaxispos=='top'){co.moveTo(xpos+(yaxispos=='left'?-3:3),Math.round(this.gutterTop));co.lineTo(xpos,Math.round(this.gutterTop));}else{co.moveTo(xpos+(yaxispos=='left'?-3:3),Math.round(ca.height-this.gutterBottom));co.lineTo(xpos,Math.round(ca.height-this.gutterBottom));}}}
48
+ if(prop['chart.noxaxis']==false&&!isSketch){if(typeof(prop['chart.numxticks'])=='number'){var xTickGap=(ca.width-this.gutterLeft-this.gutterRight)/prop['chart.numxticks'];}else{var xTickGap=(ca.width-this.gutterLeft-this.gutterRight)/this.data.length;}
49
+ if(xaxispos=='bottom'){yStart=prop['chart.ymin']<0?this.getYCoord(0)-3:this.getYCoord(0);yEnd=this.getYCoord(0)+3;}else if(xaxispos=='top'){yStart=this.gutterTop-3;yEnd=this.gutterTop;}else if(xaxispos=='center'){yStart=((ca.height-this.gutterTop-this.gutterBottom)/2)+this.gutterTop+3;yEnd=((ca.height-this.gutterTop-this.gutterBottom)/2)+this.gutterTop-3;}
50
+ var noEndXTick=prop['chart.noendxtick'];for(x=this.gutterLeft+(yaxispos=='left'?xTickGap:0),len=(ca.width-this.gutterRight+(yaxispos=='left'?5:0));x<len;x+=xTickGap){if(yaxispos=='left'&&!noEndXTick&&x>this.gutterLeft){co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}else if(yaxispos=='left'&&noEndXTick&&x>this.gutterLeft&&x<(ca.width-this.gutterRight)){co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}else if(yaxispos=='right'&&x<(ca.width-this.gutterRight)&&!noEndXTick){co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}else if(yaxispos=='right'&&x<(ca.width-this.gutterRight)&&x>(this.gutterLeft)&&noEndXTick){co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}}
51
+ if(prop['chart.noyaxis']||prop['chart.numxticks']==null){if(typeof(prop['chart.numxticks'])=='number'&&prop['chart.numxticks']>0){co.moveTo(Math.round(this.gutterLeft),yStart);co.lineTo(Math.round(this.gutterLeft),yEnd);}}}
52
+ if(prop['chart.noyaxis']&&prop['chart.noxaxis']==false&&prop['chart.numxticks']==null){if(xaxispos=='center'){co.moveTo(ma.round(this.gutterLeft),(ca.height/2)-3);co.lineTo(ma.round(this.gutterLeft),(ca.height/2)+3);}else{co.moveTo(ma.round(this.gutterLeft),ca.height-this.gutterBottom);co.lineTo(ma.round(this.gutterLeft),ca.height-this.gutterBottom+3);}}
53
+ co.stroke();};this.drawbars=this.Drawbars=function()
54
+ {co.lineWidth=prop['chart.linewidth'];co.strokeStyle=prop['chart.strokecolor'];co.fillStyle=prop['chart.colors'][0];var prevX=0,prevY=0,decimals=prop['chart.scale.decimals'];if(prop['chart.ymax']){this.scale2=RG.getScale2(this,{'max':prop['chart.ymax'],'strict':prop['chart.scale.round']?false:true,'min':prop['chart.ymin'],'scale.thousand':prop['chart.scale.thousand'],'scale.point':prop['chart.scale.point'],'scale.decimals':prop['chart.scale.decimals'],'ylabels.count':prop['chart.ylabels.count'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post']});}else{var errorbars=prop['chart.errorbars'];if(typeof errorbars==='number'){var value=errorbars;prop['chart.errorbars']=[];for(var i=0;i<this.data.length;++i){if(typeof this.data[i]==='number'){prop['chart.errorbars'].push([value,null]);}else if(typeof this.data[i]==='object'&&!RG.isNull(this.data[i])){for(var j=0;j<this.data[i].length;++j){prop['chart.errorbars'].push([value,null]);}}}
55
+ errorbars=prop['chart.errorbars'];}
56
+ for(i=0;i<this.data.length;++i){if(typeof(this.data[i])=='object'){var value=prop['chart.grouping']==='grouped'?Number(RG.arrayMax(this.data[i],true)):Number(RG.array_sum(this.data[i]));}else{var value=Number(this.data[i]);}
57
+ this.max=ma.max(ma.abs(this.max),ma.abs(value)+
58
+ Number((typeof prop['chart.errorbars']==='object'&&typeof prop['chart.errorbars'][i]==='object'&&!RG.isNull(prop['chart.errorbars'][i])&&typeof prop['chart.errorbars'][i][0]==='number')?prop['chart.errorbars'][i][0]:0));}
59
+ this.scale2=RGraph.getScale2(this,{'max':this.max,'min':prop['chart.ymin'],'scale.thousand':prop['chart.scale.thousand'],'scale.point':prop['chart.scale.point'],'scale.decimals':prop['chart.scale.decimals'],'ylabels.count':prop['chart.ylabels.count'],'scale.round':prop['chart.scale.round'],'units.pre':prop['chart.units.pre'],'units.post':prop['chart.units.post']});this.max=this.scale2.max;}
60
+ if(prop['chart.adjustable']&&!prop['chart.ymax']){this.Set('chart.ymax',this.scale2.max);}
61
+ if(prop['chart.background.hbars']&&prop['chart.background.hbars'].length>0){RGraph.DrawBars(this);}
62
+ var variant=prop['chart.variant'];if(variant==='3d'){RG.draw3DAxes(this);}
63
+ var xaxispos=prop['chart.xaxispos'],width=(ca.width-this.gutterLeft-this.gutterRight)/this.data.length,orig_height=height,hmargin=prop['chart.hmargin'],shadow=prop['chart.shadow'],shadowColor=prop['chart.shadow.color'],shadowBlur=prop['chart.shadow.blur'],shadowOffsetX=prop['chart.shadow.offsetx'],shadowOffsetY=prop['chart.shadow.offsety'],strokeStyle=prop['chart.strokecolor'],colors=prop['chart.colors'],sequentialColorIndex=0
64
+ var height;for(i=0,len=this.data.length;i<len;i+=1){if(RG.arraySum(this.data[i])<0){var height=(RG.arraySum(this.data[i])+this.scale2.min)/(this.scale2.max-this.scale2.min);}else{var height=(RG.arraySum(this.data[i])-this.scale2.min)/(this.scale2.max-this.scale2.min);}
65
+ height*=ma.abs(this.getYCoord(this.scale2.max)-this.getYCoord(this.scale2.min));var x=(i*width)+this.gutterLeft;var y=xaxispos=='center'?((ca.height-this.gutterTop-this.gutterBottom)/2)+this.gutterTop-height:ca.height-height-this.gutterBottom;if(xaxispos=='top'){y=this.gutterTop+ma.abs(height);}
66
+ if(height<0){y+=height;height=ma.abs(height);}
67
+ if(shadow){co.shadowColor=shadowColor;co.shadowBlur=shadowBlur;co.shadowOffsetX=shadowOffsetX;co.shadowOffsetY=shadowOffsetY;}
68
+ co.beginPath();if(typeof this.data[i]=='number'){if(xaxispos==='bottom'&&prop['chart.ymin']<0){if(this.data[i]>=0){height=ma.abs(this.getYCoord(0)-this.getYCoord(this.data[i]));}else{y=this.getYCoord(0);height=ma.abs(this.getYCoord(0)-this.getYCoord(this.data[i]));}}
69
+ var barWidth=width-(2*hmargin);if(barWidth<0){alert('[RGRAPH] Warning: you have a negative bar width. This may be caused by the chart.hmargin being too high or the width of the canvas not being sufficient.');}
70
+ co.strokeStyle=strokeStyle;co.fillStyle=colors[0];if(prop['chart.colors.sequential']){co.fillStyle=colors[i];}
71
+ if(variant=='sketch'){co.lineCap='round';var sketchOffset=3;co.beginPath();co.strokeStyle=colors[0];if(prop['chart.colors.sequential']){co.strokeStyle=colors[i];}
72
+ co.moveTo(x+hmargin+2,y+height-2);co.lineTo(x+hmargin-1,y-4);co.moveTo(x+hmargin-3,y+ -2+(this.data[i]<0?height:0));co.bezierCurveTo(x+((hmargin+width)*0.33),y+15+(this.data[i]<0?height-10:0),x+((hmargin+width)*0.66),y+5+(this.data[i]<0?height-10:0),x+hmargin+width+ -1,y+0+(this.data[i]<0?height:0));co.moveTo(x+hmargin+width-5,y-5);co.lineTo(x+hmargin+width-3,y+height-3);if(prop['chart.variant.sketch.verticals']){for(var r=0.2;r<=0.8;r+=0.2){co.moveTo(x+hmargin+width+(r>0.4?-1:3)-(r*width),y-1);co.lineTo(x+hmargin+width-(r>0.4?1:-1)-(r*width),y+height+(r==0.2?1:-2));}}
73
+ co.stroke();}else if(variant=='bar'||variant=='3d'||variant=='glass'||variant=='bevel'){if(RGraph.ISOLD&&shadow){this.DrawIEShadow([x+hmargin,y,barWidth,height]);}
74
+ if(variant=='glass'){RGraph.filledCurvyRect(co,x+hmargin,y,barWidth,height,3,this.data[i]>0,this.data[i]>0,this.data[i]<0,this.data[i]<0);RGraph.strokedCurvyRect(co,x+hmargin,y,barWidth,height,3,this.data[i]>0,this.data[i]>0,this.data[i]<0,this.data[i]<0);}else{co.beginPath();co.rect(x+hmargin,y,barWidth,height);co.fill();RG.NoShadow(this);co.beginPath();co.rect(x+hmargin,y,barWidth,height);co.stroke();}
75
+ if(variant=='3d'){var prevStrokeStyle=co.strokeStyle;var prevFillStyle=co.fillStyle;if(this.data[i]>=0){co.beginPath();co.moveTo(x+hmargin,y);co.lineTo(x+hmargin+prop['chart.variant.threed.offsetx'],y-prop['chart.variant.threed.offsety']);co.lineTo(x+hmargin+prop['chart.variant.threed.offsetx']+barWidth,y-prop['chart.variant.threed.offsety']);co.lineTo(x+hmargin+barWidth,y);co.closePath();co.stroke();co.fill();}
76
+ co.beginPath();co.moveTo(x+hmargin+barWidth,y);co.lineTo(x+hmargin+barWidth+prop['chart.variant.threed.offsetx'],this.data[i]<0&&xaxispos==='bottom'?this.getYCoord(0):(this.data[i]<0&&(y-prop['chart.variant.threed.offsety'])<(this.gutterTop+this.halfgrapharea)?(this.gutterTop+this.halfgrapharea):(y-prop['chart.variant.threed.offsety'])));co.lineTo(x+hmargin+barWidth+prop['chart.variant.threed.offsetx'],this.data[i]<0&&(y-prop['chart.variant.threed.offsety']+height)<(this.gutterTop+this.getYCoord(0))?this.getYCoord(this.data[i])-prop['chart.variant.threed.offsety']:(this.data[i]>0?y-prop['chart.variant.threed.offsety']+height:ma.min(y-prop['chart.variant.threed.offsety']+height,ca.height-this.gutterBottom)));co.lineTo(x+hmargin+barWidth,y+height);co.closePath();co.stroke();co.fill();if(this.data[i]>0){co.beginPath();co.fillStyle='rgba(255,255,255,0.5)';co.moveTo(x+hmargin,y);co.lineTo(x+hmargin+prop['chart.variant.threed.offsetx'],y-prop['chart.variant.threed.offsety']);co.lineTo(x+hmargin+prop['chart.variant.threed.offsetx']+barWidth,y-prop['chart.variant.threed.offsety']);co.lineTo(x+hmargin+barWidth,y);co.lineTo(x+hmargin,y);co.closePath();co.stroke();co.fill();}
77
+ co.beginPath();co.fillStyle='rgba(0,0,0,0.4)';co.moveTo(x+hmargin+barWidth,y);co.lineTo(x+hmargin+barWidth+prop['chart.variant.threed.offsetx'],this.data[i]<0&&xaxispos==='bottom'?this.getYCoord(0):(this.data[i]<0&&(y-prop['chart.variant.threed.offsety'])<(this.gutterTop+this.halfgrapharea)?(this.gutterTop+this.halfgrapharea):y-prop['chart.variant.threed.offsety']));co.lineTo(x+hmargin+barWidth+prop['chart.variant.threed.offsetx'],this.data[i]<0&&(y-prop['chart.variant.threed.offsety']+height)<this.getYCoord(0)?this.getYCoord(0):this.data[i]>0?y-prop['chart.variant.threed.offsety']+height:ma.min(y-prop['chart.variant.threed.offsety']+height,ca.height-this.gutterBottom));co.lineTo(x+hmargin+barWidth,y+height);co.lineTo(x+hmargin+barWidth,y);co.closePath();co.stroke();co.fill();co.strokeStyle=prevStrokeStyle;co.fillStyle=prevFillStyle;}else if(variant=='glass'){var grad=co.createLinearGradient(x+hmargin,y,x+hmargin+(barWidth/2),y);grad.addColorStop(0,'rgba(255,255,255,0.9)');grad.addColorStop(1,'rgba(255,255,255,0.5)');co.beginPath();co.fillStyle=grad;co.fillRect(x+hmargin+2,y+(this.data[i]>0?2:0),(barWidth/2)-2,height-2);co.fill();}}else if(variant=='dot'){co.beginPath();co.moveTo(x+(width/2),y);co.lineTo(x+(width/2),y+height);co.stroke();co.beginPath();co.fillStyle=this.properties['chart.colors'][i];co.arc(x+(width/2),y+(this.data[i]>0?0:height),2,0,6.28,0);co.fillStyle=prop['chart.colors'][0];if(prop['chart.colors.sequential']){co.fillStyle=colors[i];}
78
+ co.stroke();co.fill();}else{alert('[BAR] Warning! Unknown chart.variant: '+variant);}
79
+ this.coords.push([x+hmargin,y,width-(2*hmargin),height]);if(typeof this.coords2[i]=='undefined'){this.coords2[i]=[];}
80
+ this.coords2[i].push([x+hmargin,y,width-(2*hmargin),height]);}else if(this.data[i]&&typeof(this.data[i])=='object'&&prop['chart.grouping']=='stacked'){if(this.scale2.min){alert("[ERROR] Stacked Bar charts with a Y min are not supported");}
81
+ var barWidth=width-(2*hmargin);var redrawCoords=[];var startY=0;var dataset=this.data[i];if(barWidth<0){alert('[RGRAPH] Warning: you have a negative bar width. This may be caused by the chart.hmargin being too high or the width of the canvas not being sufficient.');}
82
+ for(j=0;j<dataset.length;++j){if(xaxispos=='center'){alert("[BAR] It's pointless having the X axis position at the center on a stacked bar chart.");return;}
83
+ if(this.data[i][j]<0){alert('[BAR] Negative values are not permitted with a stacked bar chart. Try a grouped one instead.');return;}
84
+ co.strokeStyle=strokeStyle
85
+ co.fillStyle=colors[j];if(prop['chart.colors.reverse']){co.fillStyle=colors[this.data[i].length-j-1];}
86
+ if(prop['chart.colors.sequential']&&colors[sequentialColorIndex]){co.fillStyle=colors[sequentialColorIndex++];}else if(prop['chart.colors.sequential']){co.fillStyle=colors[sequentialColorIndex-1];}
87
+ var height=(dataset[j]/this.scale2.max)*(ca.height-this.gutterTop-this.gutterBottom);if(xaxispos=='center'){height/=2;}
88
+ var totalHeight=(RGraph.array_sum(dataset)/this.scale2.max)*(ca.height-hmargin-this.gutterTop-this.gutterBottom);this.coords.push([x+hmargin,y,width-(2*hmargin),height]);if(typeof this.coords2[i]=='undefined'){this.coords2[i]=[];}
89
+ this.coords2[i].push([x+hmargin,y,width-(2*hmargin),height]);if(RGraph.ISOLD&&shadow){this.DrawIEShadow([x+hmargin,y,width-(2*hmargin),height+1]);}
90
+ if(height>0){co.strokeRect(x+hmargin,y,width-(2*hmargin),height);co.fillRect(x+hmargin,y,width-(2*hmargin),height);}
91
+ if(j==0){var startY=y;var startX=x;}
92
+ if(shadow){redrawCoords.push([x+hmargin,y,width-(2*hmargin),height,co.fillStyle]);}
93
+ if(variant=='3d'){var prevFillStyle=co.fillStyle;var prevStrokeStyle=co.strokeStyle;if(j==0){co.beginPath();co.moveTo(startX+hmargin,y);co.lineTo(startX+prop['chart.variant.threed.offsetx']+hmargin,y-prop['chart.variant.threed.offsety']);co.lineTo(startX+prop['chart.variant.threed.offsetx']+barWidth+hmargin,y-prop['chart.variant.threed.offsety']);co.lineTo(startX+barWidth+hmargin,y);co.closePath();co.fill();co.stroke();}
94
+ co.beginPath();co.moveTo(startX+barWidth+hmargin,y);co.lineTo(startX+barWidth+hmargin+prop['chart.variant.threed.offsetx'],y-prop['chart.variant.threed.offsety']);co.lineTo(startX+barWidth+hmargin+prop['chart.variant.threed.offsetx'],y-prop['chart.variant.threed.offsety']+height);co.lineTo(startX+barWidth+hmargin,y+height);co.closePath();co.fill();co.stroke();if(j==0){co.fillStyle='rgba(255,255,255,0.5)';co.beginPath();co.moveTo(startX+hmargin,y);co.lineTo(startX+prop['chart.variant.threed.offsetx']+hmargin,y-prop['chart.variant.threed.offsety']);co.lineTo(startX+prop['chart.variant.threed.offsetx']+barWidth+hmargin,y-prop['chart.variant.threed.offsety']);co.lineTo(startX+barWidth+hmargin,y);co.closePath();co.fill();co.stroke();}
95
+ co.fillStyle='rgba(0,0,0,0.4)';co.beginPath();co.moveTo(startX+barWidth+hmargin,y);co.lineTo(startX+barWidth+hmargin+prop['chart.variant.threed.offsetx'],y-prop['chart.variant.threed.offsety']);co.lineTo(startX+barWidth+hmargin+prop['chart.variant.threed.offsetx'],y-prop['chart.variant.threed.offsety']+height);co.lineTo(startX+barWidth+hmargin,y+height);co.closePath();co.fill();co.stroke();co.strokeStyle=prevStrokeStyle;co.fillStyle=prevFillStyle;}
96
+ y+=height;}
97
+ if(shadow){RGraph.NoShadow(this);for(k=0;k<redrawCoords.length;++k){co.strokeStyle=strokeStyle;co.fillStyle=redrawCoords[k][4];co.strokeRect(redrawCoords[k][0],redrawCoords[k][1],redrawCoords[k][2],redrawCoords[k][3]);co.fillRect(redrawCoords[k][0],redrawCoords[k][1],redrawCoords[k][2],redrawCoords[k][3]);co.stroke();co.fill();}
98
+ redrawCoords=[];}}else if(this.data[i]&&typeof(this.data[i])=='object'&&prop['chart.grouping']=='grouped'){var redrawCoords=[];co.lineWidth=prop['chart.linewidth'];for(j=0;j<this.data[i].length;++j){co.strokeStyle=strokeStyle;co.fillStyle=colors[j];if(prop['chart.colors.sequential']&&colors[sequentialColorIndex]){co.fillStyle=colors[sequentialColorIndex++];}else if(prop['chart.colors.sequential']){co.fillStyle=colors[sequentialColorIndex-1];}
99
+ var individualBarWidth=(width-(2*hmargin))/this.data[i].length;var height=((this.data[i][j]+(this.data[i][j]<0?this.scale2.min:(-1*this.scale2.min)))/(this.scale2.max-this.scale2.min))*(ca.height-this.gutterTop-this.gutterBottom);var groupedMargin=prop['chart.hmargin.grouped'];var startX=x+hmargin+(j*individualBarWidth);if(individualBarWidth<0){alert('[RGRAPH] Warning: you have a negative bar width. This may be caused by the chart.hmargin being too high or the width of the canvas not being sufficient.');}
100
+ if(xaxispos=='center'){height/=2;}
101
+ if(xaxispos=='top'){var startY=this.gutterTop;var height=Math.abs(height);}else if(xaxispos=='center'){var startY=this.gutterTop+(this.grapharea/2)-height;}else{var startY=this.getYCoord(0);var height=ma.abs(ma.abs(this.getYCoord(this.data[i][j]))-this.getYCoord(0));if(this.data[i][j]>=0){startY-=height;}}
102
+ co.strokeRect(startX+groupedMargin,startY,individualBarWidth-(2*groupedMargin),height);co.fillRect(startX+groupedMargin,startY,individualBarWidth-(2*groupedMargin),height);y+=height;if(variant=='3d'){var prevFillStyle=co.fillStyle;var prevStrokeStyle=co.strokeStyle;var hmarginGrouped=prop['chart.hmargin.grouped'];if(this.data[i][j]>=0){co.beginPath();co.moveTo(startX+hmarginGrouped,startY);co.lineTo(startX+hmarginGrouped+prop['chart.variant.threed.offsetx'],startY-prop['chart.variant.threed.offsety']);co.lineTo(startX+prop['chart.variant.threed.offsetx']+individualBarWidth-hmarginGrouped,startY-prop['chart.variant.threed.offsety']);co.lineTo(startX+individualBarWidth-hmarginGrouped,startY);co.closePath();co.fill();co.stroke();}
103
+ co.beginPath();co.moveTo(startX+individualBarWidth-hmarginGrouped-1,startY);co.lineTo(startX+individualBarWidth-hmarginGrouped+prop['chart.variant.threed.offsetx'],this.data[i][j]<0?(this.getYCoord(0)+ma.abs(height)-prop['chart.variant.threed.offsety']):this.getYCoord(0)-height-prop['chart.variant.threed.offsety']);co.lineTo(startX+individualBarWidth-hmarginGrouped+prop['chart.variant.threed.offsetx'],this.data[i][j]<0&&(startY+height-prop['chart.variant.threed.offsety'])<(this.gutterTop+this.halfgrapharea)?(this.gutterTop+this.halfgrapharea):(startY+height-prop['chart.variant.threed.offsety']));co.lineTo(startX+individualBarWidth-hmarginGrouped-1,startY+height);co.closePath();co.fill();co.stroke();if(this.data[i][j]>=0){co.fillStyle='rgba(255,255,255,0.5)';co.beginPath();co.moveTo(startX+hmarginGrouped,startY);co.lineTo(startX+hmarginGrouped+prop['chart.variant.threed.offsetx'],startY-prop['chart.variant.threed.offsety']);co.lineTo(startX+prop['chart.variant.threed.offsetx']+individualBarWidth-hmarginGrouped,startY-prop['chart.variant.threed.offsety']);co.lineTo(startX+individualBarWidth-hmarginGrouped,startY);co.closePath();co.fill();co.stroke();}
104
+ co.fillStyle='rgba(0,0,0,0.4)';co.beginPath();co.moveTo(startX+individualBarWidth-hmarginGrouped,startY);co.lineTo(startX+individualBarWidth+prop['chart.variant.threed.offsetx']-hmarginGrouped,this.data[i][j]<0?(this.getYCoord(0)+ma.abs(height)-prop['chart.variant.threed.offsety']):this.getYCoord(0)-height-prop['chart.variant.threed.offsety']);co.lineTo(startX+individualBarWidth+prop['chart.variant.threed.offsetx']-hmarginGrouped,this.data[i][j]<0&&(startY+height-5)<(this.gutterTop+this.halfgrapharea)?(this.gutterTop+this.halfgrapharea):(startY+height-prop['chart.variant.threed.offsety']));co.lineTo(startX+individualBarWidth-hmarginGrouped,startY+height);co.closePath();co.fill();co.stroke();co.strokeStyle=prevStrokeStyle;co.fillStyle=prevFillStyle;}
105
+ if(height<0){height=Math.abs(height);startY=startY-height;}
106
+ this.coords.push([startX+groupedMargin,startY,individualBarWidth-(2*groupedMargin),height]);if(typeof this.coords2[i]=='undefined'){this.coords2[i]=[];}
107
+ this.coords2[i].push([startX+groupedMargin,startY,individualBarWidth-(2*groupedMargin),height]);if(prop['chart.shadow']){redrawCoords.push([startX+groupedMargin,startY,individualBarWidth-(2*groupedMargin),height,co.fillStyle]);}}
108
+ if(redrawCoords.length){RGraph.NoShadow(this);co.lineWidth=prop['chart.linewidth'];co.beginPath();for(var j=0;j<redrawCoords.length;++j){co.fillStyle=redrawCoords[j][4];co.strokeStyle=prop['chart.strokecolor'];co.fillRect(redrawCoords[j][0],redrawCoords[j][1],redrawCoords[j][2],redrawCoords[j][3]);co.strokeRect(redrawCoords[j][0],redrawCoords[j][1],redrawCoords[j][2],redrawCoords[j][3]);}
109
+ co.fill();co.stroke();redrawCoords=[];}}else{this.coords.push([]);}
110
+ co.closePath();}
111
+ if(prop['chart.variant']==='3d'&&prop['chart.yaxispos']==='right'){RG.draw3DYAxis(this);}
112
+ RGraph.noShadow(this);};this.drawLabels=this.DrawLabels=function()
113
+ {var context=co;var text_angle=prop['chart.text.angle'],text_size=prop['chart.text.size'],labels=prop['chart.labels']
114
+ if(prop['chart.ylabels']){if(prop['chart.xaxispos']=='top')this.Drawlabels_top();if(prop['chart.xaxispos']=='center')this.Drawlabels_center();if(prop['chart.xaxispos']=='bottom')this.Drawlabels_bottom();}
115
+ if(typeof(labels)=='object'&&labels){var yOffset=Number(prop['chart.labels.offsety']),xOffset=Number(prop['chart.labels.offsetx']),bold=prop['chart.labels.bold']
116
+ if(prop['chart.text.angle']!=0){var valign='center';var halign='right';var angle=0-prop['chart.text.angle'];}else{var valign='top';var halign='center';var angle=0;}
117
+ co.fillStyle=prop['chart.labels.color']||prop['chart.text.color'];var barWidth=(ca.width-this.gutterRight-this.gutterLeft)/labels.length;xTickGap=(ca.width-this.gutterRight-this.gutterLeft)/labels.length
118
+ var i=0;var font=prop['chart.text.font'];for(x=this.gutterLeft+(xTickGap/2);x<=ca.width-this.gutterRight;x+=xTickGap){RG.text2(this,{'font':font,'size':text_size,'x':x+xOffset,'y':prop['chart.xaxispos']=='top'?this.gutterTop+yOffset-5:(ca.height-this.gutterBottom)+yOffset+3,'bold':bold,'text':String(labels[i++]),'valign':prop['chart.xaxispos']=='top'?'bottom':valign,'halign':halign,'tag':'label','marker':false,'angle':angle,'tag':'labels'});}}
119
+ this.drawAboveLabels();};this.drawlabels_top=this.Drawlabels_top=function()
120
+ {var ca=this.canvas;var co=this.context;var prop=this.properties;co.beginPath();co.fillStyle=prop['chart.text.color'];co.strokeStyle='black';if(prop['chart.xaxispos']=='top'){var context=co;var text_size=prop['chart.text.size'];var units_pre=prop['chart.units.pre'];var units_post=prop['chart.units.post'];var align=prop['chart.yaxispos']=='left'?'right':'left';var font=prop['chart.text.font'];var numYLabels=prop['chart.ylabels.count'];var ymin=prop['chart.ymin'];var offsetx=prop['chart.ylabels.offsetx'];var offsety=prop['chart.ylabels.offsety'];if(prop['chart.ylabels.inside']==true){var xpos=prop['chart.yaxispos']=='left'?this.gutterLeft+5:ca.width-this.gutterRight-5;var align=prop['chart.yaxispos']=='left'?'left':'right';var boxed=true;}else{var xpos=prop['chart.yaxispos']=='left'?this.gutterLeft-5:ca.width-this.gutterRight+5;var boxed=false;}
121
+ if(typeof(prop['chart.ylabels.specific'])=='object'&&prop['chart.ylabels.specific']){var labels=RGraph.array_reverse(prop['chart.ylabels.specific']);var grapharea=ca.height-this.gutterTop-this.gutterBottom;for(var i=0;i<labels.length;++i){var y=this.gutterTop+(grapharea*(i/labels.length))+(grapharea/labels.length);RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':y+offsety,'text':String(labels[i]),'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
122
+ return;}
123
+ var labels=this.scale2.labels;for(var i=0;i<labels.length;++i){RGraph.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+((this.grapharea/labels.length)*(i+1))+offsety,'text':'-'+labels[i],'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
124
+ if(prop['chart.ymin']!=0||prop['chart.noxaxis']||prop['chart.scale.zerostart']){RGraph.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+offsety,'text':(this.scale2.min!=0?'-':'')+RGraph.numberFormat(this,(this.scale2.min.toFixed((this.scale2.min===0?0:prop['chart.scale.decimals']))),units_pre,units_post),'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}}
125
+ co.fill();};this.drawlabels_center=this.Drawlabels_center=function()
126
+ {var ca=this.canvas;var co=this.context;var prop=this.properties;var font=prop['chart.text.font'];var numYLabels=prop['chart.ylabels.count'];co.fillStyle=prop['chart.text.color'];if(prop['chart.xaxispos']=='center'){var text_size=prop['chart.text.size'];var units_pre=prop['chart.units.pre'];var units_post=prop['chart.units.post'];var context=co;var align='';var xpos=0;var boxed=false;var ymin=prop['chart.ymin'];var offsetx=prop['chart.ylabels.offsetx'];var offsety=prop['chart.ylabels.offsety'];co.fillStyle=prop['chart.text.color'];co.strokeStyle='black';if(prop['chart.ylabels.inside']==true){var xpos=prop['chart.yaxispos']=='left'?this.gutterLeft+5:ca.width-this.gutterRight-5;var align=prop['chart.yaxispos']=='left'?'left':'right';var boxed=true;}else{var xpos=prop['chart.yaxispos']=='left'?this.gutterLeft-5:ca.width-this.gutterRight+5;var align=prop['chart.yaxispos']=='left'?'right':'left';var boxed=false;}
127
+ if(typeof(prop['chart.ylabels.specific'])=='object'&&prop['chart.ylabels.specific']){var labels=prop['chart.ylabels.specific'];var grapharea=ca.height-this.gutterTop-this.gutterBottom;for(var i=0;i<labels.length;++i){var y=this.gutterTop+((grapharea/2)/(labels.length-1))*i;RGraph.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':y+offsety,'text':String(labels[i]),'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
128
+ for(var i=labels.length-1;i>=1;--i){var y=this.gutterTop+(grapharea*(i/((labels.length-1)*2)))+(grapharea/2);RG.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':y+offsety,'text':String(labels[labels.length-i-1]),'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
129
+ return;}
130
+ for(var i=0;i<this.scale2.labels.length;++i){var y=this.gutterTop+this.halfgrapharea-((this.halfgrapharea/numYLabels)*(i+1));var text=this.scale2.labels[i];RG.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':y+offsety,'text':text,'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
131
+ for(var i=(this.scale2.labels.length-1);i>=0;--i){var y=this.gutterTop+((this.halfgrapharea/numYLabels)*(i+1))+this.halfgrapharea;var text=this.scale2.labels[i];RG.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':y+offsety,'text':'-'+text,'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
132
+ if(this.scale2.min!=0||prop['chart.scale.zerostart']){RG.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+this.halfgrapharea+offsety,'text':RG.number_format(this,(this.scale2.min.toFixed((this.scale2.min===0?0:prop['chart.scale.decimals']))),units_pre,units_post),'valign':'center','valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}}};this.drawlabels_bottom=this.Drawlabels_bottom=function()
133
+ {var text_size=prop['chart.text.size'],units_pre=prop['chart.units.pre'],units_post=prop['chart.units.post'],context=this.context,align=prop['chart.yaxispos']=='left'?'right':'left',font=prop['chart.text.font'],numYLabels=prop['chart.ylabels.count'],ymin=prop['chart.ymin'],offsetx=prop['chart.ylabels.offsetx'],offsety=prop['chart.ylabels.offsety']
134
+ co.beginPath();co.fillStyle=prop['chart.text.color'];co.strokeStyle='black';if(prop['chart.ylabels.inside']==true){var xpos=prop['chart.yaxispos']=='left'?this.gutterLeft+5:ca.width-this.gutterRight-5;var align=prop['chart.yaxispos']=='left'?'left':'right';var boxed=true;}else{var xpos=prop['chart.yaxispos']=='left'?this.gutterLeft-5:ca.width-this.gutterRight+5;var boxed=false;}
135
+ if(prop['chart.ylabels.specific']&&typeof(prop['chart.ylabels.specific'])=='object'){var labels=prop['chart.ylabels.specific'];var grapharea=ca.height-this.gutterTop-this.gutterBottom;for(var i=0;i<labels.length;++i){var y=this.gutterTop+(grapharea*(i/(labels.length-1)));RGraph.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':y+offsety,'text':labels[i],'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
136
+ return;}
137
+ var gutterTop=this.gutterTop;var halfTextHeight=this.halfTextHeight;var scale=this.scale;for(var i=0;i<numYLabels;++i){var text=this.scale2.labels[i];RGraph.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+this.grapharea-((this.grapharea/numYLabels)*(i+1))+offsety,'text':text,'valign':'center','halign':align,'bordered':boxed,'tag':'scale'});}
138
+ if(prop['chart.ymin']!=0||prop['chart.noxaxis']||prop['chart.scale.zerostart']){RG.text2(this,{font:font,size:text_size,x:xpos+offsetx,y:ca.height-this.gutterBottom+offsety,text:RG.numberFormat(this,(this.scale2.min.toFixed((this.scale2.min===0?0:prop['chart.scale.decimals']))),units_pre,units_post),valign:'center',halign:align,bordered:boxed,tag:'scale'});}
139
+ co.fill();};this.drawIEShadow=this.DrawIEShadow=function(coords)
140
+ {var co=this.context;var ca=this.canvas;var prop=this.properties;var prevFillStyle=co.fillStyle;var offsetx=prop['chart.shadow.offsetx'];var offsety=prop['chart.shadow.offsety'];co.lineWidth=prop['chart.linewidth'];co.fillStyle=prop['chart.shadow.color'];co.beginPath();co.fillRect(coords[0]+offsetx,coords[1]+offsety,coords[2],coords[3]);co.fill();co.fillStyle=prevFillStyle;};this.getShape=this.getBar=function(e)
141
+ {var obj=arguments[1]?arguments[1]:this;var mouseXY=RG.getMouseXY(e),mouseX=mouseXY[0],mouseY=mouseXY[1],canvas=obj.canvas,context=obj.context,coords=obj.coords
142
+ for(var i=0,len=coords.length;i<len;i+=1){if(obj.coords[i].length==0){continue;}
143
+ var left=coords[i][0],top=coords[i][1],width=coords[i][2],height=coords[i][3],prop=obj.properties
144
+ if(prop['chart.tooltips.hotspot.xonly']){pa2(co,'b r % % % %',left,this.gutterTop,width,ca.height-this.gutterBottom);}else{pa2(co,'b r % % % %',left,top,width,height);}
145
+ if(co.isPointInPath(mouseX,mouseY)){if(prop['chart.tooltips']){var tooltip=RG.parseTooltipText?RG.parseTooltipText(prop['chart.tooltips'],i):prop['chart.tooltips'][i];}
146
+ var dataset=0,idx=i
147
+ while(idx>=(typeof obj.data[dataset]==='object'&&obj.data[dataset]?obj.data[dataset].length:1)){if(typeof obj.data[dataset]==='number'){idx-=1;}else if(obj.data[dataset]){idx-=obj.data[dataset].length;}else{idx-=1;}
148
+ dataset++;}
149
+ if(typeof(obj.data[dataset])=='number'){idx=null;}
150
+ return{0:obj,1:left,2:top,3:width,4:height,5:i,'object':obj,'x':left,'y':top,'width':width,'height':height,'index':i,'tooltip':tooltip,'index_adjusted':idx,'dataset':dataset};}}
151
+ return null;};this.getShapeByX=function(e)
152
+ {var canvas=e.target;var mouseCoords=RGraph.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;}
153
+ var mouseX=mouseCoords[0];var mouseY=mouseCoords[1];var left=obj.coords[i][0];var top=obj.coords[i][1];var width=obj.coords[i][2];var height=obj.coords[i][3];var prop=obj.properties;if(mouseX>=left&&mouseX<=(left+width)){if(prop['chart.tooltips']){var tooltip=RGraph.parseTooltipText?RGraph.parseTooltipText(prop['chart.tooltips'],i):prop['chart.tooltips'][i];}
154
+ return{0:obj,1:left,2:top,3:width,4:height,5:i,'object':obj,'x':left,'y':top,'width':width,'height':height,'index':i,'tooltip':tooltip};}}
155
+ return null;};this.getValue=function(arg)
156
+ {var co=this.context;var ca=this.canvas;var prop=this.properties;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];}
157
+ if(mouseY<prop['chart.gutter.top']||mouseY>(ca.height-prop['chart.gutter.bottom'])||mouseX<prop['chart.gutter.left']||mouseX>(ca.width-prop['chart.gutter.right'])){return null;}
158
+ if(prop['chart.xaxispos']=='center'){var value=(((this.grapharea/2)-(mouseY-prop['chart.gutter.top']))/this.grapharea)*(this.scale2.max-this.scale2.min)
159
+ value*=2;if(value>=0){value+=this.scale2.min;}else{value-=this.scale2.min;}}else if(prop['chart.xaxispos']=='top'){var value=((this.grapharea-(mouseY-prop['chart.gutter.top']))/this.grapharea)*(this.scale2.max-this.scale2.min)
160
+ value=this.scale2.max-value;value=ma.abs(value)* -1;}else{var value=((this.grapharea-(mouseY-prop['chart.gutter.top']))/this.grapharea)*(this.scale2.max-this.scale2.min)
161
+ value+=this.scale2.min;}
162
+ return value;};this.getYCoord=function(value)
163
+ {if(value>this.scale2.max){return null;}
164
+ var co=this.context,ca=this.canvas,prop=this.properties;var y,xaxispos=prop['chart.xaxispos'];if(xaxispos=='top'){if(value<0){value=ma.abs(value);}
165
+ y=((value-this.scale2.min)/(this.scale2.max-this.scale2.min))*this.grapharea;y=y+this.gutterTop}else if(xaxispos=='center'){y=((value-this.scale2.min)/(this.scale2.max-this.scale2.min))*(this.grapharea/2);y=(this.grapharea/2)-y;y+=this.gutterTop;}else{if(value<this.scale2.min){value=this.scale2.min;}
166
+ y=((value-this.scale2.min)/(this.scale2.max-this.scale2.min));y*=(ca.height-this.gutterTop-this.gutterBottom);y=ca.height-this.gutterBottom-y;}
167
+ return y;};this.highlight=this.Highlight=function(shape)
168
+ {if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else{RG.Highlight.Rect(this,shape);}};this.getObjectByXY=function(e)
169
+ {var mouseXY=RG.getMouseXY(e);if(prop['chart.variant']==='3d'){var adjustment=prop['chart.variant.threed.angle']*mouseXY[0];mouseXY[1]-=adjustment;}
170
+ if(mouseXY[0]>=prop['chart.gutter.left']&&mouseXY[0]<=(ca.width-prop['chart.gutter.right'])&&mouseXY[1]>=prop['chart.gutter.top']&&mouseXY[1]<=(ca.height-prop['chart.gutter.bottom'])){return this;}};this.adjusting_mousemove=this.Adjusting_mousemove=function(e)
171
+ {if(prop['chart.adjustable']&&RG.Registry.Get('chart.adjusting')&&RG.Registry.Get('chart.adjusting').uid==this.uid){var value=Number(this.getValue(e));var shape=RG.Registry.Get('chart.adjusting.shape')
172
+ 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.isNull(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);}
173
+ RG.redrawCanvas(e.target);RG.fireCustomEvent(this,'onadjust');}}};this.parseColors=function()
174
+ {if(this.original_colors.length===0){this.original_colors['chart.colors']=RGraph.array_clone(prop['chart.colors']);this.original_colors['chart.key.colors']=RGraph.array_clone(prop['chart.key.colors']);this.original_colors['chart.crosshairs.color']=prop['chart.crosshairs.color'];this.original_colors['chart.highlight.stroke']=prop['chart.highlight.stroke'];this.original_colors['chart.highlight.fill']=prop['chart.highlight.fill'];this.original_colors['chart.text.color']=prop['chart.text.color'];this.original_colors['chart.background.barcolor1']=prop['chart.background.barcolor1'];this.original_colors['chart.background.barcolor2']=prop['chart.background.barcolor2'];this.original_colors['chart.background.grid.color']=prop['chart.background.grid.color'];this.original_colors['chart.background.color']=prop['chart.background.color'];this.original_colors['chart.strokecolor']=prop['chart.strokecolor'];this.original_colors['chart.axis.color']=prop['chart.axis.color'];}
175
+ var colors=prop['chart.colors'];if(colors){for(var i=0;i<colors.length;++i){colors[i]=this.parseSingleColorForGradient(colors[i]);}}
176
+ var colors=prop['chart.key.colors'];if(colors){for(var i=0;i<colors.length;++i){colors[i]=this.parseSingleColorForGradient(colors[i]);}}
177
+ prop['chart.crosshairs.color']=this.parseSingleColorForGradient(prop['chart.crosshairs.color']);prop['chart.highlight.stroke']=this.parseSingleColorForGradient(prop['chart.highlight.stroke']);prop['chart.highlight.fill']=this.parseSingleColorForGradient(prop['chart.highlight.fill']);prop['chart.text.color']=this.parseSingleColorForGradient(prop['chart.text.color']);prop['chart.background.barcolor1']=this.parseSingleColorForGradient(prop['chart.background.barcolor1']);prop['chart.background.barcolor2']=this.parseSingleColorForGradient(prop['chart.background.barcolor2']);prop['chart.background.grid.color']=this.parseSingleColorForGradient(prop['chart.background.grid.color']);prop['chart.background.color']=this.parseSingleColorForGradient(prop['chart.background.color']);prop['chart.strokecolor']=this.parseSingleColorForGradient(prop['chart.strokecolor']);prop['chart.axis.color']=this.parseSingleColorForGradient(prop['chart.axis.color']);};this.reset=function()
178
+ {};this.parseSingleColorForGradient=function(color)
179
+ {if(!color||typeof(color)!='string'){return color;}
180
+ if(color.match(/^gradient\((.*)\)$/i)){var parts=RegExp.$1.split(':');var grad=co.createLinearGradient(0,ca.height-prop['chart.gutter.bottom'],0,prop['chart.gutter.top']);var diff=1/(parts.length-1);grad.addColorStop(0,RG.trim(parts[0]));for(var j=1,len=parts.length;j<len;++j){grad.addColorStop(j*diff,RGraph.trim(parts[j]));}}
181
+ return grad?grad:color;};this.drawBevel=this.DrawBevel=function()
182
+ {var coords=this.coords;var coords2=this.coords2;var prop=this.properties;var co=this.context;var ca=this.canvas;if(prop['chart.grouping']=='stacked'){for(var i=0;i<coords2.length;++i){if(coords2[i]&&coords2[i][0]&&coords2[i][0][0]){var x=coords2[i][0][0];var y=coords2[i][0][1];var w=coords2[i][0][2];var arr=[];for(var j=0;j<coords2[i].length;++j){arr.push(coords2[i][j][3]);}
183
+ var h=RGraph.array_sum(arr);co.save();co.strokeStyle='black';co.beginPath();co.rect(x,y,w,h);co.clip();co.shadowColor='black';co.shadowOffsetX=0;co.shadowOffsetY=0;co.shadowBlur=20;co.beginPath();co.rect(x-3,y-3,w+6,h+100);co.lineWidth=5;co.stroke();co.restore();}}}else{for(var i=0;i<coords.length;++i){if(coords[i]){var x=coords[i][0];var y=coords[i][1];var w=coords[i][2];var h=coords[i][3];var xaxispos=prop['chart.xaxispos'];var xaxis_ycoord=((ca.height-this.gutterTop-this.gutterBottom)/2)+this.gutterTop;co.save();co.strokeStyle='black';co.beginPath();co.rect(x,y,w,h);co.clip();co.shadowColor='black';co.shadowOffsetX=0;co.shadowOffsetY=0;co.shadowBlur=20;if(xaxispos=='top'||(xaxispos=='center'&&(y+h)>xaxis_ycoord)){y=y-100;h=h+100;}else{y=y;h=h+100;}
184
+ co.beginPath();co.rect(x-3,y-3,w+6,h+6);co.lineWidth=5;co.stroke();co.restore();}}}};this.interactiveKeyHighlight=function(index)
185
+ {this.coords2.forEach(function(value,idx,arr)
186
+ {if(typeof value[index]=='object'&&value[index]){var x=value[index][0]
187
+ var y=value[index][1]
188
+ var w=value[index][2]
189
+ var h=value[index][3]
190
+ co.fillStyle=prop['chart.key.interactive.highlight.chart.fill'];co.strokeStyle=prop['chart.key.interactive.highlight.chart.stroke'];co.lineWidth=2;co.strokeRect(x,y,w,h);co.fillRect(x,y,w,h);}});};this.on=function(type,func)
191
+ {if(type.substr(0,2)!=='on'){type='on'+type;}
192
+ if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
193
+ return this;};this.drawAboveLabels=function()
194
+ {var labels=prop['chart.labels.above'],specific=prop['chart.labels.above.specific'],color=prop['chart.labels.above.color'],background=prop['chart.labels.above.background'],decimals=prop['chart.labels.above.decimals'],size=prop['chart.labels.above.size'],angle=-1*prop['chart.labels.above.angle'],unitsPre=prop['chart.labels.above.units.pre'],unitsPost=prop['chart.labels.above.units.post'],coords=this.coords,coords2=this.coords2,data=this.data,ldata=RG.arrayLinearize(this.data),offset=prop['chart.labels.above.offset'],text_font=prop['chart.text.font'],text_size=prop['chart.text.size'],grouping=prop['chart.grouping']
195
+ RG.noShadow(this);co.fillStyle=typeof color==='string'?color:prop['chart.text.color'];if(labels&&grouping==='grouped'){for(var i=0,len=data.length,sequentialIndex=0;i<len;i+=1){if(typeof data[i]==='number'&&data[i]>=0){var angle=angle;var halign=(angle?'left':'center');var valign=angle!==0?'center':'bottom';RG.text2(this,{'font':text_font,'size':typeof size==='number'?size:text_size-3,'x':coords2[i][0][0]+(coords2[i][0][2]/2),'y':coords2[i][0][1]-offset,'text':specific?(specific[sequentialIndex]||''):RG.numberFormat(this,Number(typeof data[i]==='object'?data[i][0]:data[i]).toFixed(decimals),unitsPre,unitsPost),'halign':halign,'valign':valign,'angle':angle,'marker':false,'bounding':true,'bounding.fill':background,'bounding.stroke':'rgba(0,0,0,0)','tag':'labels.above'});sequentialIndex++;}else if(typeof data[i]==='number'&&data[i]<0){var angle=angle;var halign=angle?'right':'center';var valign=angle!==0?'center':'top';RG.text2(this,{'font':text_font,'size':typeof size==='number'?size:text_size-3,'x':coords2[i][0][0]+(coords2[i][0][2]/2),'y':coords2[i][0][1]+coords2[i][0][3]+offset,'text':specific?(specific[sequentialIndex]||''):RG.numberFormat(this,Number(typeof data[i]==='object'?data[i][0]:data[i]).toFixed(decimals),unitsPre,unitsPost),'halign':halign,'valign':valign,'angle':angle,'bounding':true,'bounding.fill':background,'bounding.stroke':'rgba(0,0,0,0)','marker':false,'tag':'labels.above'});sequentialIndex++;}else if(typeof data[i]==='object'){for(var j=0,len2=data[i].length;j<len2;j+=1){var angle=angle;var halign=data[i][j]<0?'right':'left';halign=angle===0?'center':halign;var valign=data[i][j]<0?'top':'bottom';valign=angle!=0?'center':valign;RG.text2(this,{'font':text_font,'size':typeof size==='number'?size:text_size-3,'x':coords2[i][j][0]+(coords2[i][j][2]/2),'y':coords2[i][j][1]+(data[i][j]<0?coords2[i][j][3]+offset:-offset),'text':specific?(specific[sequentialIndex]||''):RG.numberFormat(this,Number(data[i][j]).toFixed(decimals),unitsPre,unitsPost),'halign':halign,'valign':valign,'angle':angle,'bounding':true,'bounding.fill':background,'bounding.stroke':'rgba(0,0,0,0)','marker':false,'tag':'labels.above'});sequentialIndex++;}}}}else if(labels&&grouping==='stacked'){for(var i=0,len=data.length,sequentialIndex=0;i<len;i+=1){if(typeof data[i]==='object'){var angle=angle;var halign=angle!=0?'left':'center';var valign=angle!=0?'center':'bottom';RG.text2(this,{'font':text_font,'size':typeof size==='number'?size:text_size-3,'x':coords2[i][0][0]+(coords2[i][0][2]/2),'y':coords2[i][0][1]+(data[i][0]<0?coords2[i][0][3]:0)-offset,'text':specific?(specific[sequentialIndex]||''):RG.numberFormat(this,Number(RG.arraySum(data[i])).toFixed(decimals),unitsPre,unitsPost),'halign':halign,'valign':valign,'angle':angle,'bounding':true,'bounding.fill':background,'bounding.stroke':'rgba(0,0,0,0)','marker':false,'tag':'labels.above'});sequentialIndex+=data[i].length;}else{var angle=angle;var halign=angle!=0?'left':'center';var valign=angle!=0?'center':'bottom';RG.text2(this,{'font':text_font,'size':typeof size==='number'?size:text_size-3,'x':coords2[i][0][0]+(coords2[i][0][2]/2),'y':coords2[i][0][1]+(data[i][0]<0?coords2[i][0][3]:0)-offset,'text':specific?(specific[sequentialIndex]||''):RG.numberFormat(this,Number(data[i]).toFixed(decimals),unitsPre,unitsPost),'halign':halign,'valign':valign,'angle':angle,'bounding':true,'bounding.fill':background,'bounding.stroke':'rgba(0,0,0,0)','marker':false,'tag':'labels.above'});sequentialIndex++;}}}};this.firstDrawFunc=function()
196
+ {};this.wave=function()
197
+ {var obj=this,opt=arguments[0]||{},labelsAbove=this.get('labelsAbove');opt.frames=opt.frames||60;opt.startFrames=[];opt.counters=[];var framesperbar=opt.frames/3,frame=-1,callback=arguments[1]||function(){},original=RG.arrayClone(this.original_data);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;}}
198
+ obj.draw();obj.Set('ymax',obj.scale2.max);RG.clear(obj.canvas);function iterator()
199
+ {++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);}}
200
+ if(frame>=opt.frames){if(labelsAbove){obj.set('labelsAbove',true);RG.redraw();}
201
+ callback(obj);}else{RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iterator);}}
202
+ iterator();return this;};this.colorWave=function()
203
+ {var obj=this,opt=arguments[0]||{};opt.frames=opt.frames||60;opt.startFrames=[];opt.counters=[],colors=obj.properties['chart.colors'];if(colors.length<=obj.data.length){obj.set('chart.colors.sequential',true);colors=RG.arrayPad(colors,obj.data.length,colors[colors.length-1]);}
204
+ var framesperbar=opt.frames/2,frame=-1,callback=arguments[1]||function(){},originalColors=RG.arrayClone(obj.properties['chart.colors']);for(var i=0,len=originalColors.length;i<len;i+=1){opt.startFrames[i]=((opt.frames/2)/(originalColors.length-1))*i;opt.counters[i]=0;}
205
+ function iterator()
206
+ {++frame;for(var i=0,len=colors.length;i<len;i+=1){if(frame>opt.startFrames[i]&&colors[i].match(/^rgba?\(([0-9 ]+),([0-9 ]+),([0-9 ]+)(,([ 0-9.]+)?)\)/)){colors[i]='rgba({1},{2},{3},{4})'.format(RegExp.$1,RegExp.$2,RegExp.$3,(frame-opt.startFrames[i])/framesperbar);}else{colors[i]=colors[i].replace(/,[0-9. ]+\)/,',0)');}}
207
+ if(frame>=opt.frames){callback(obj);}else{RG.redrawCanvas(obj.canvas);RG.Effects.updateCanvas(iterator);}}
208
+ iterator();return this;};this.grow=function()
209
+ {var opt=arguments[0]||{},frames=opt.frames||30,frame=0,callback=arguments[1]||function(){},obj=this,labelsAbove=this.get('labelsAbove')
210
+ if(RG.isArray(opt.data)){var ymax=0;for(var i=0;i<opt.data.length;++i){if(typeof opt.data[i]==='object'){for(var j=0;j<opt.data[i].length;++j){if(typeof opt.data[i][j]==='string'&&opt.data[i][j].match(/(\+|\-)([0-9]+)/)){if(RegExp.$1==='+'){opt.data[i][j]=this.original_data[i][j]+parseInt(RegExp.$2);}else{opt.data[i][j]=this.original_data[i][j]-parseInt(RegExp.$2);}}
211
+ ymax=ma.max(ymax,opt.data[i][j]);}}else if(typeof opt.data[i]==='string'&&opt.data[i].match(/(\+|\-)([0-9]+)/)){if(RegExp.$1==='+'){opt.data[i]=this.original_data[i]+parseInt(RegExp.$2);}else{opt.data[i]=this.original_data[i]-parseInt(RegExp.$2);}
212
+ ymax=ma.max(ymax,opt.data[i]);}else{ymax=ma.max(ymax,opt.data[i]);}}
213
+ var scale=RG.getScale2(this,{'max':ymax});this.Set('chart.ymax',scale.max);}
214
+ this.set('labelsAbove',false);if(prop['chart.ymax']==null){var ymax=0;for(var i=0;i<obj.data.length;++i){if(RG.isArray(this.data[i])&&prop['chart.grouping']==='stacked'){ymax=ma.max(ymax,ma.abs(RG.arraySum(this.data[i])));}else if(RG.isArray(this.data[i])&&prop['chart.grouping']==='grouped'){for(var j=0,group=[];j<this.data[i].length;j++){group.push(ma.abs(this.data[i][j]));}
215
+ ymax=ma.max(ymax,ma.abs(RG.arrayMax(group)));}else{ymax=ma.max(ymax,ma.abs(this.data[i]));}}
216
+ var scale=RG.getScale2(this,{'max':ymax});this.Set('chart.ymax',scale.max);}
217
+ if(typeof opt.ymax==='number'){obj.set('ymax',opt.ymax);}
218
+ var iterator=function()
219
+ {var easingMultiplier=RG.Effects.getEasingMultiplier(frames,frame);for(var j=0,len=obj.original_data.length;j<len;++j){if(typeof obj.data[j]==='object'&&!RG.isNull(obj.data[j])){for(var k=0,len2=obj.data[j].length;k<len2;++k){if(obj.firstDraw||!opt.data){obj.data[j][k]=easingMultiplier*obj.original_data[j][k];}else if(opt.data&&opt.data.length===obj.original_data.length){var diff=opt.data[j][k]-obj.original_data[j][k];obj.data[j][k]=(easingMultiplier*diff)+obj.original_data[j][k];}}}else{if(obj.firstDraw||!opt.data){obj.data[j]=easingMultiplier*obj.original_data[j];}else if(opt.data&&opt.data.length===obj.original_data.length){var diff=opt.data[j]-obj.original_data[j];obj.data[j]=(easingMultiplier*diff)+obj.original_data[j];}}}
220
+ RG.redrawCanvas(obj.canvas);if(frame<frames){frame+=1;RG.Effects.updateCanvas(iterator);}else{if(RG.isArray(opt.data)){var linear_data=RG.arrayLinearize(data);for(var i=0;i<linear_data.length;++i){if(!obj['$'+i]){obj['$'+i]={};}}}
221
+ obj.data=data;obj.original_data=RG.arrayClone(data);if(labelsAbove){obj.set('labelsAbove',true);RG.redraw();}
222
+ callback(obj);}};iterator();return this;};this.drawErrorbars=function()
223
+ {var coords=this.coords,color=prop['chart.errorbars.color']||'black',default_halfwidth=ma.min(prop['chart.errorbars.capped.width'],coords[0][2])/2,x=0,errorbars=prop['chart.errorbars'],length=0;if(!prop['chart.errorbars.capped']){prop['chart.errorbars.capped.width']=0;halfwidth=0;}
224
+ co.lineWidth=prop['chart.errorbars.linewidth'];for(var i=0;i<coords.length;++i){color=prop['chart.errorbars.color']||'black';if(errorbars[i]&&typeof errorbars[i][3]==='number'){co.lineWidth=errorbars[i][3];}
225
+ var halfwidth=(errorbars[i]&&typeof errorbars[i][4]==='number')?errorbars[i][4]/2:default_halfwidth;if(!prop['chart.errorbars.capped']){halfwidth=0;}
226
+ if(typeof errorbars[i]==='number'){length=ma.abs(this.getYCoord(errorbars[i])-this.getYCoord(0));if(length){pa2(co,'b m % % l % % l % % l % % s %',coords[i][0]+(coords[i][2]/2),coords[i][1],coords[i][0]+(coords[i][2]/2),coords[i][1]-length,coords[i][0]+(coords[i][2]/2)-halfwidth,ma.round(coords[i][1]-length),coords[i][0]+(coords[i][2]/2)+halfwidth,ma.round(coords[i][1]-length),color);}}else if(typeof errorbars[i]==='object'&&!RG.isNull(errorbars[i])){var positiveLength=ma.abs(this.getYCoord(errorbars[i][0])-this.getYCoord(0));if(typeof errorbars[i][1]==='string'){color=errorbars[i][1];}else if(typeof errorbars[i][2]==='string'){color=errorbars[i][2];}
227
+ halfwidth=typeof errorbars[i][4]==='number'?errorbars[i][4]/2:default_halfwidth;if(!prop['chart.errorbars.capped']){halfwidth=0;}
228
+ if(!RG.isNull(errorbars[i][0])){pa2(co,'b m % % l % % l % % l % % s %',coords[i][0]+(coords[i][2]/2),coords[i][1],coords[i][0]+(coords[i][2]/2),coords[i][1]-positiveLength,coords[i][0]+(coords[i][2]/2)-halfwidth,ma.round(coords[i][1]-positiveLength),coords[i][0]+(coords[i][2]/2)+halfwidth,ma.round(coords[i][1]-positiveLength),color);}
229
+ if(typeof errorbars[i][1]==='number'){var negativeLength=ma.abs(this.getYCoord(errorbars[i][1])-this.getYCoord(0));pa2(co,'b m % % l % % l % % l % % s %',coords[i][0]+(coords[i][2]/2),coords[i][1],coords[i][0]+(coords[i][2]/2),coords[i][1]+negativeLength,coords[i][0]+(coords[i][2]/2)-halfwidth,ma.round(coords[i][1]+negativeLength),coords[i][0]+(coords[i][2]/2)+halfwidth,ma.round(coords[i][1]+negativeLength),color);}}
230
+ if(errorbars[i]&&typeof errorbars[i][3]==='number'){co.lineWidth=prop['chart.errorbars.linewidth'];}}};RG.register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}
231
+ var thisIsHereToTestMyMinificationScript='this is a test 15th August 2016';};RGraph.CombinedChart=function()
232
+ {this.objects=[];var objects=[];if(RGraph.isArray(arguments[0])){objects=arguments[0];}else{for(var i=0;i<arguments.length;i+=1){objects[i]=arguments[i];}}
233
+ for(var i=0;i<objects.length;++i){this.objects[i]=objects[i];this.objects[i].set({gutterLeft:this.objects[0].get('gutter.left'),gutterRight:this.objects[0].get('gutter.right'),gutterTop:this.objects[0].get('gutter.top'),gutterBottom:this.objects[0].get('gutter.bottom')});if(this.objects[i].type=='line'){var obj=this.objects[i];obj.set('hmargin',((this.objects[0].canvas.width-this.objects[0].Get('chart.gutter.right')-this.objects[0].Get('chart.gutter.left'))/this.objects[0].data.length)/2);obj.set('noaxes',true);obj.set('backgroundGrid',false);obj.set('ylabels',false);}
234
+ if(this.objects[i].get('chart.resizable')){var resizable_object=obj;}}
235
+ if(resizable_object){function myOnresizebeforedraw(obj)
236
+ {var gutterLeft=obj.get('gutterLeft');var gutterRight=obj.get('gutterRight');obj.set('hmargin',(obj.canvas.width-gutterLeft-gutterRight)/(obj.original_data[0].length*2));}
237
+ RGraph.AddCustomEventListener(resizable_object,'onresizebeforedraw',myOnresizebeforedraw);}};RGraph.CombinedChart.prototype.add=RGraph.CombinedChart.prototype.Add=function(obj)
238
+ {this.objects.push(obj);};RGraph.CombinedChart.prototype.draw=RGraph.CombinedChart.prototype.Draw=function()
239
+ {for(var i=0;i<this.objects.length;++i){if(this.objects[i].properties['chart.combinedchart.effect']){var options=this.objects[i].properties['chart.combinedchart.effect.options']?eval('('+this.objects[i].properties['chart.combinedchart.effect.options']+')'):null;(this.objects[i][this.objects[i].properties['chart.combinedchart.effect']])
240
+ (options,this.objects[i].properties['chart.combinedchart.effect.callback'])}else{this.objects[i].draw();}}};