rgraph-rails 4.62 → 4.64
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +3 -4
- data/lib/rgraph-rails/version.rb +1 -1
- data/vendor/assets/javascripts/RGraph.bar.js +240 -3742
- data/vendor/assets/javascripts/RGraph.bipolar.js +165 -2005
- data/vendor/assets/javascripts/RGraph.common.annotate.js +35 -395
- data/vendor/assets/javascripts/RGraph.common.context.js +30 -595
- data/vendor/assets/javascripts/RGraph.common.core.js +418 -5359
- data/vendor/assets/javascripts/RGraph.common.csv.js +20 -276
- data/vendor/assets/javascripts/RGraph.common.deprecated.js +35 -450
- data/vendor/assets/javascripts/RGraph.common.dynamic.js +88 -1395
- data/vendor/assets/javascripts/RGraph.common.effects.js +90 -1545
- data/vendor/assets/javascripts/RGraph.common.key.js +52 -753
- data/vendor/assets/javascripts/RGraph.common.resizing.js +37 -563
- data/vendor/assets/javascripts/RGraph.common.sheets.js +29 -352
- data/vendor/assets/javascripts/RGraph.common.tooltips.js +32 -450
- data/vendor/assets/javascripts/RGraph.common.zoom.js +14 -219
- data/vendor/assets/javascripts/RGraph.cornergauge.js +71 -0
- data/vendor/assets/javascripts/RGraph.drawing.background.js +34 -570
- data/vendor/assets/javascripts/RGraph.drawing.circle.js +33 -544
- data/vendor/assets/javascripts/RGraph.drawing.image.js +51 -755
- data/vendor/assets/javascripts/RGraph.drawing.marker1.js +37 -645
- data/vendor/assets/javascripts/RGraph.drawing.marker2.js +36 -633
- data/vendor/assets/javascripts/RGraph.drawing.marker3.js +35 -514
- data/vendor/assets/javascripts/RGraph.drawing.poly.js +37 -559
- data/vendor/assets/javascripts/RGraph.drawing.rect.js +33 -548
- data/vendor/assets/javascripts/RGraph.drawing.text.js +36 -664
- data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +50 -812
- data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +51 -856
- data/vendor/assets/javascripts/RGraph.fuel.js +58 -964
- data/vendor/assets/javascripts/RGraph.funnel.js +55 -984
- data/vendor/assets/javascripts/RGraph.gantt.js +77 -1354
- data/vendor/assets/javascripts/RGraph.gauge.js +85 -1421
- data/vendor/assets/javascripts/RGraph.hbar.js +162 -2788
- data/vendor/assets/javascripts/RGraph.hprogress.js +80 -1401
- data/vendor/assets/javascripts/RGraph.line.js +249 -4248
- data/vendor/assets/javascripts/RGraph.meter.js +74 -1280
- data/vendor/assets/javascripts/RGraph.modaldialog.js +19 -301
- data/vendor/assets/javascripts/RGraph.odo.js +71 -1264
- data/vendor/assets/javascripts/RGraph.pie.js +137 -2288
- data/vendor/assets/javascripts/RGraph.radar.js +110 -1847
- data/vendor/assets/javascripts/RGraph.rose.js +108 -1977
- data/vendor/assets/javascripts/RGraph.rscatter.js +80 -1432
- data/vendor/assets/javascripts/RGraph.scatter.js +172 -3163
- data/vendor/assets/javascripts/RGraph.semicircularprogress.js +60 -1120
- data/vendor/assets/javascripts/RGraph.svg.bar.js +66 -1735
- data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +21 -246
- data/vendor/assets/javascripts/RGraph.svg.common.core.js +255 -3937
- data/vendor/assets/javascripts/RGraph.svg.common.csv.js +20 -276
- data/vendor/assets/javascripts/RGraph.svg.common.fx.js +68 -1303
- data/vendor/assets/javascripts/RGraph.svg.common.key.js +19 -205
- data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +29 -352
- data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +22 -273
- data/vendor/assets/javascripts/RGraph.svg.funnel.js +32 -0
- data/vendor/assets/javascripts/RGraph.svg.hbar.js +59 -1400
- data/vendor/assets/javascripts/RGraph.svg.line.js +70 -1580
- data/vendor/assets/javascripts/RGraph.svg.pie.js +55 -1131
- data/vendor/assets/javascripts/RGraph.svg.radar.js +57 -1502
- data/vendor/assets/javascripts/RGraph.svg.rose.js +66 -1817
- data/vendor/assets/javascripts/RGraph.svg.scatter.js +58 -1261
- data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +28 -865
- data/vendor/assets/javascripts/RGraph.svg.waterfall.js +45 -1252
- data/vendor/assets/javascripts/RGraph.thermometer.js +63 -1136
- data/vendor/assets/javascripts/RGraph.vprogress.js +83 -1470
- data/vendor/assets/javascripts/RGraph.waterfall.js +83 -1347
- metadata +5 -4
- data/vendor/assets/javascripts/financial-data.js +0 -1067
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 76c1debe9ae26e49ea87cdcb39f1925c102ec3875ccd073142dfdec80e1a74e0
|
4
|
+
data.tar.gz: 143fd83753b0a16f9aa6a5722e4fdb26b7997cc3b419db066a8833d5939a0c85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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).
|
data/lib/rgraph-rails/version.rb
CHANGED
@@ -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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
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();}}};
|