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