rgraph-rails 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +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();}}};