rgraph-rails 4.62 → 4.64

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