rgraph-rails 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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,4163 +1,242 @@
|
|
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 is just 99 GBP and you can |
|
11
|
-
* | read about it here: |
|
12
|
-
* | http://www.rgraph.net/license |
|
13
|
-
* o--------------------------------------------------------------------------------o
|
14
|
-
*/
|
15
1
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
'chart.axis.linewidth': 1,
|
258
|
-
'chart.numxticks': (data && typeof(data[0]) == 'number' ? data.length - 1: 20),
|
259
|
-
'chart.numyticks': 10,
|
260
|
-
'chart.zoom.factor': 1.5,
|
261
|
-
'chart.zoom.fade.in': true,
|
262
|
-
'chart.zoom.fade.out': true,
|
263
|
-
'chart.zoom.hdir': 'right',
|
264
|
-
'chart.zoom.vdir': 'down',
|
265
|
-
'chart.zoom.frames': 25,
|
266
|
-
'chart.zoom.delay': 16.666,
|
267
|
-
'chart.zoom.shadow': true,
|
268
|
-
'chart.zoom.background': true,
|
269
|
-
'chart.zoom.action': 'zoom',
|
270
|
-
'chart.backdrop': false,
|
271
|
-
'chart.backdrop.size': 30,
|
272
|
-
'chart.backdrop.alpha': 0.2,
|
273
|
-
'chart.resizable': false,
|
274
|
-
'chart.resize.handle.adjust': [0,0],
|
275
|
-
'chart.resize.handle.background': null,
|
276
|
-
'chart.adjustable': false,
|
277
|
-
'chart.noredraw': false,
|
278
|
-
'chart.outofbounds': false,
|
279
|
-
'chart.outofbounds.clip': false,
|
280
|
-
'chart.chromefix': true,
|
281
|
-
'chart.animation.factor': 1,
|
282
|
-
'chart.animation.unfold.x': false,
|
283
|
-
'chart.animation.unfold.y': true,
|
284
|
-
'chart.animation.unfold.initial': 2,
|
285
|
-
'chart.animation.trace.clip': 1,
|
286
|
-
'chart.curvy': false,
|
287
|
-
'chart.line.visible': [],
|
288
|
-
'chart.events.click': null,
|
289
|
-
'chart.events.mousemove': null,
|
290
|
-
'chart.errorbars': false,
|
291
|
-
'chart.errorbars.color': 'black',
|
292
|
-
'chart.errorbars.capped': true,
|
293
|
-
'chart.errorbars.capped.width': 12,
|
294
|
-
'chart.errorbars.linewidth': 1,
|
295
|
-
'chart.combinedchart.effect': null,
|
296
|
-
'chart.combinedchart.effect.options': null,
|
297
|
-
'chart.combinedchart.effect.callback': null,
|
298
|
-
'chart.clearto': 'rgba(0,0,0,0)'
|
299
|
-
}
|
300
|
-
|
301
|
-
/**
|
302
|
-
* Change null arguments to empty arrays
|
303
|
-
*/
|
304
|
-
for (var i=1; i<arguments.length; ++i) {
|
305
|
-
if (typeof(arguments[i]) == 'null' || !arguments[i]) {
|
306
|
-
arguments[i] = [];
|
307
|
-
}
|
308
|
-
}
|
309
|
-
|
310
|
-
|
311
|
-
/**
|
312
|
-
* Store the original data. This also allows for giving arguments as one big array.
|
313
|
-
*/
|
314
|
-
this.original_data = [];
|
315
|
-
|
316
|
-
// This allows for the new object based configuration style
|
317
|
-
if (typeof conf === 'object' && conf.data) {
|
318
|
-
if (typeof conf.data[0] === 'number' || RGraph.isNull(conf.data[0])) {
|
319
|
-
|
320
|
-
this.original_data[0] = RGraph.arrayClone(conf.data);
|
321
|
-
|
322
|
-
//} else if (typeof conf.data[0] === 'object' && !RGraph.isNull(conf.data[0])) {
|
323
|
-
} else {
|
324
|
-
|
325
|
-
for (var i=0; i<conf.data.length; ++i) {
|
326
|
-
this.original_data[i] = RGraph.arrayClone(conf.data[i]);
|
327
|
-
}
|
328
|
-
}
|
329
|
-
|
330
|
-
// Allow for the older configuration style
|
331
|
-
} else {
|
332
|
-
for (var i=1; i<arguments.length; ++i) {
|
333
|
-
|
334
|
-
if ( arguments[1]
|
335
|
-
&& typeof(arguments[1]) == 'object'
|
336
|
-
&& arguments[1][0]
|
337
|
-
&& typeof(arguments[1][0]) == 'object'
|
338
|
-
&& arguments[1][0].length) {
|
339
|
-
|
340
|
-
var tmp = [];
|
341
|
-
|
342
|
-
for (var i=0; i<arguments[1].length; ++i) {
|
343
|
-
tmp[i] = RGraph.array_clone(arguments[1][i]);
|
344
|
-
}
|
345
|
-
|
346
|
-
for (var j=0; j<tmp.length; ++j) {
|
347
|
-
this.original_data[j] = RGraph.array_clone(tmp[j]);
|
348
|
-
}
|
349
|
-
|
350
|
-
} else {
|
351
|
-
this.original_data[i - 1] = RGraph.array_clone(arguments[i]);
|
352
|
-
}
|
353
|
-
}
|
354
|
-
}
|
355
|
-
|
356
|
-
|
357
|
-
// Check for support
|
358
|
-
if (!this.canvas) {
|
359
|
-
alert('[LINE] Fatal error: no canvas support');
|
360
|
-
return;
|
361
|
-
}
|
362
|
-
|
363
|
-
// Convert strings to numbers
|
364
|
-
for (var i=0; i<this.original_data.length; ++i) {
|
365
|
-
for (var j=0; j<this.original_data[i].length; ++j) {
|
366
|
-
if (typeof this.original_data[i][j] === 'string') {
|
367
|
-
this.original_data[i][j] = parseFloat(this.original_data[i][j]);
|
368
|
-
}
|
369
|
-
}
|
370
|
-
}
|
371
|
-
|
372
|
-
|
373
|
-
/**
|
374
|
-
* Store the data here as one big array
|
375
|
-
*/
|
376
|
-
this.data_arr = RGraph.arrayLinearize(this.original_data);
|
377
|
-
|
378
|
-
for (var i=0; i<this.data_arr.length; ++i) {
|
379
|
-
this['$' + i] = {};
|
380
|
-
}
|
381
|
-
|
382
|
-
|
383
|
-
/**
|
384
|
-
* Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
|
385
|
-
* done already
|
386
|
-
*/
|
387
|
-
if (!this.canvas.__rgraph_aa_translated__) {
|
388
|
-
this.context.translate(0.5,0.5);
|
389
|
-
|
390
|
-
this.canvas.__rgraph_aa_translated__ = true;
|
391
|
-
}
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
// Short variable names
|
397
|
-
var RG = RGraph,
|
398
|
-
ca = this.canvas,
|
399
|
-
co = ca.getContext('2d'),
|
400
|
-
prop = this.properties,
|
401
|
-
pa2 = RG.path2,
|
402
|
-
win = window,
|
403
|
-
doc = document,
|
404
|
-
ma = Math
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
/**
|
409
|
-
* "Decorate" the object with the generic effects if the effects library has been included
|
410
|
-
*/
|
411
|
-
if (RG.Effects && typeof RG.Effects.decorate === 'function') {
|
412
|
-
RG.Effects.decorate(this);
|
413
|
-
}
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
/**
|
420
|
-
* An all encompassing accessor
|
421
|
-
*
|
422
|
-
* @param string name The name of the property
|
423
|
-
* @param mixed value The value of the property
|
424
|
-
*/
|
425
|
-
this.set =
|
426
|
-
this.Set = function (name)
|
427
|
-
{
|
428
|
-
var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
|
429
|
-
|
430
|
-
/**
|
431
|
-
* the number of arguments is only one and it's an
|
432
|
-
* object - parse it for configuration data and return.
|
433
|
-
*/
|
434
|
-
if (arguments.length === 1 && typeof name === 'object') {
|
435
|
-
RG.parseObjectStyleConfig(this, name);
|
436
|
-
return this;
|
437
|
-
}
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
/**
|
444
|
-
* This should be done first - prepend the propertyy name with "chart." if necessary
|
445
|
-
*/
|
446
|
-
if (name.substr(0,6) != 'chart.') {
|
447
|
-
name = 'chart.' + name;
|
448
|
-
}
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
// Convert uppercase letters to dot+lower case letter
|
454
|
-
while(name.match(/([A-Z])/)) {
|
455
|
-
name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
|
456
|
-
}
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
// Consolidate the tooltips
|
461
|
-
if (name == 'chart.tooltips' && typeof value == 'object' && value) {
|
462
|
-
|
463
|
-
var tooltips = [];
|
464
|
-
|
465
|
-
for (var i=1; i<arguments.length; i++) {
|
466
|
-
if (typeof(arguments[i]) == 'object' && arguments[i][0]) {
|
467
|
-
for (var j=0; j<arguments[i].length; j++) {
|
468
|
-
tooltips.push(arguments[i][j]);
|
469
|
-
}
|
470
|
-
|
471
|
-
} else if (typeof(arguments[i]) == 'function') {
|
472
|
-
tooltips = arguments[i];
|
473
|
-
|
474
|
-
} else {
|
475
|
-
tooltips.push(arguments[i]);
|
476
|
-
}
|
477
|
-
}
|
478
|
-
|
479
|
-
// Because "value" is used further down at the end of this function, set it to the expanded array os tooltips
|
480
|
-
value = tooltips;
|
481
|
-
}
|
482
|
-
|
483
|
-
|
484
|
-
/**
|
485
|
-
* If (buggy) Chrome and the linewidth is 1, change it to 1.01
|
486
|
-
*/
|
487
|
-
if (name == 'chart.linewidth' && navigator.userAgent.match(/Chrome/)) {
|
488
|
-
if (value == 1) {
|
489
|
-
value = 1.01;
|
490
|
-
|
491
|
-
} else if (RGraph.is_array(value)) {
|
492
|
-
for (var i=0; i<value.length; ++i) {
|
493
|
-
if (typeof(value[i]) == 'number' && value[i] == 1) {
|
494
|
-
value[i] = 1.01;
|
495
|
-
}
|
496
|
-
}
|
497
|
-
}
|
498
|
-
}
|
499
|
-
|
500
|
-
|
501
|
-
/**
|
502
|
-
* Check for xaxispos
|
503
|
-
*/
|
504
|
-
if (name == 'chart.xaxispos' ) {
|
505
|
-
if (value != 'bottom' && value != 'center' && value != 'top') {
|
506
|
-
alert('[LINE] (' + this.id + ') chart.xaxispos should be top, center or bottom. Tried to set it to: ' + value + ' Changing it to center');
|
507
|
-
value = 'center';
|
508
|
-
}
|
509
|
-
}
|
510
|
-
|
511
|
-
|
512
|
-
/**
|
513
|
-
* chart.xticks is now called chart.numxticks
|
514
|
-
*/
|
515
|
-
if (name == 'chart.xticks') {
|
516
|
-
name = 'chart.numxticks';
|
517
|
-
}
|
518
|
-
|
519
|
-
|
520
|
-
/**
|
521
|
-
* Change the new chart.spline option to chart.curvy
|
522
|
-
*/
|
523
|
-
if (name == 'chart.spline') {
|
524
|
-
name = 'chart.curvy';
|
525
|
-
}
|
526
|
-
|
527
|
-
|
528
|
-
/**
|
529
|
-
* Chnge chart.ylabels.invert to chart.scale.invert
|
530
|
-
*/
|
531
|
-
if (name == 'chart.ylabels.invert') {
|
532
|
-
name = 'chart.scale.invert';
|
533
|
-
}
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
this.properties[name] = value;
|
542
|
-
|
543
|
-
return this;
|
544
|
-
};
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
/**
|
550
|
-
* An all encompassing accessor
|
551
|
-
*
|
552
|
-
* @param string name The name of the property
|
553
|
-
*/
|
554
|
-
this.get =
|
555
|
-
this.Get = function (name)
|
556
|
-
{
|
557
|
-
/**
|
558
|
-
* This should be done first - prepend the property name with "chart." if necessary
|
559
|
-
*/
|
560
|
-
if (name.substr(0,6) != 'chart.') {
|
561
|
-
name = 'chart.' + name;
|
562
|
-
}
|
563
|
-
|
564
|
-
// Convert uppercase letters to dot+lower case letter
|
565
|
-
name = name.replace(/([A-Z])/g, function (str)
|
566
|
-
{
|
567
|
-
return '.' + String(RegExp.$1).toLowerCase()
|
568
|
-
});
|
569
|
-
|
570
|
-
/**
|
571
|
-
* If requested property is chart.spline - change it to chart.curvy
|
572
|
-
*/
|
573
|
-
if (name == 'chart.spline') {
|
574
|
-
name = 'chart.curvy';
|
575
|
-
}
|
576
|
-
|
577
|
-
return prop[name];
|
578
|
-
};
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
/**
|
584
|
-
* The function you call to draw the line chart
|
585
|
-
*
|
586
|
-
* @param bool An optional bool used internally to ditinguish whether the
|
587
|
-
* line chart is being called by the bar chart
|
588
|
-
*
|
589
|
-
* Draw()
|
590
|
-
* |
|
591
|
-
* +--Draw()
|
592
|
-
* | |
|
593
|
-
* | +-DrawLine()
|
594
|
-
* |
|
595
|
-
* +-RedrawLine()
|
596
|
-
* |
|
597
|
-
* +-DrawCurvyLine()
|
598
|
-
* |
|
599
|
-
* +-DrawSpline()
|
600
|
-
*/
|
601
|
-
this.draw =
|
602
|
-
this.Draw = function ()
|
603
|
-
{
|
604
|
-
// MUST be the first thing done!
|
605
|
-
if (typeof(prop['chart.background.image']) == 'string') {
|
606
|
-
RG.DrawBackgroundImage(this);
|
607
|
-
}
|
608
|
-
|
609
|
-
|
610
|
-
/**
|
611
|
-
* Fire the onbeforedraw event
|
612
|
-
*/
|
613
|
-
RG.FireCustomEvent(this, 'onbeforedraw');
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
/**
|
621
|
-
* Parse the colors. This allows for simple gradient syntax
|
622
|
-
*/
|
623
|
-
if (!this.colorsParsed) {
|
624
|
-
|
625
|
-
this.parseColors();
|
626
|
-
|
627
|
-
// Don't want to do this again
|
628
|
-
this.colorsParsed = true;
|
629
|
-
}
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
/**
|
634
|
-
* This is new in May 2011 and facilitates indiviual gutter settings,
|
635
|
-
* eg chart.gutter.left
|
636
|
-
*/
|
637
|
-
this.gutterLeft = prop['chart.gutter.left'];
|
638
|
-
this.gutterRight = prop['chart.gutter.right'];
|
639
|
-
this.gutterTop = prop['chart.gutter.top'];
|
640
|
-
this.gutterBottom = prop['chart.gutter.bottom'];
|
641
|
-
|
642
|
-
|
643
|
-
/**
|
644
|
-
* Check for Chrome 6 and shadow
|
645
|
-
*
|
646
|
-
* TODO Remove once it's been fixed (for a while)
|
647
|
-
* 07/03/2014 - Removed
|
648
|
-
* 29/10/2011 - Looks like it's been fixed as long the linewidth is at least 1.01
|
649
|
-
* SEARCH TAGS: CHROME FIX SHADOW BUG
|
650
|
-
*/
|
651
|
-
//if ( prop['chart.shadow']
|
652
|
-
// && RG.ISCHROME
|
653
|
-
// && prop['chart.linewidth'] <= 1
|
654
|
-
// && prop['chart.chromefix']
|
655
|
-
// && prop['chart.shadow.blur'] > 0) {
|
656
|
-
// alert('[RGRAPH WARNING] Chrome has a shadow bug, meaning you should increase the linewidth to at least 1.01');
|
657
|
-
//}
|
658
|
-
|
659
|
-
|
660
|
-
// Reset the data back to that which was initially supplied
|
661
|
-
this.data = RG.array_clone(this.original_data);
|
662
|
-
|
663
|
-
|
664
|
-
// Reset the max value
|
665
|
-
this.max = 0;
|
666
|
-
|
667
|
-
/**
|
668
|
-
* Reverse the datasets so that the data and the labels tally
|
669
|
-
* COMMENTED OUT 15TH AUGUST 2011
|
670
|
-
*/
|
671
|
-
//this.data = RG.array_reverse(this.data);
|
672
|
-
|
673
|
-
if (prop['chart.filled'] && !prop['chart.filled.range'] && this.data.length > 1 && prop['chart.filled.accumulative']) {
|
674
|
-
|
675
|
-
var accumulation = [];
|
676
|
-
|
677
|
-
for (var set=0; set<this.data.length; ++set) {
|
678
|
-
for (var point=0; point<this.data[set].length; ++point) {
|
679
|
-
this.data[set][point] = Number(accumulation[point] ? accumulation[point] : 0) + this.data[set][point];
|
680
|
-
accumulation[point] = this.data[set][point];
|
681
|
-
}
|
682
|
-
}
|
683
|
-
}
|
684
|
-
|
685
|
-
/**
|
686
|
-
* Get the maximum Y scale value
|
687
|
-
*/
|
688
|
-
if (prop['chart.ymax']) {
|
689
|
-
|
690
|
-
this.max = prop['chart.ymax'];
|
691
|
-
this.min = prop['chart.ymin'] ? prop['chart.ymin'] : 0;
|
692
|
-
|
693
|
-
this.scale2 = RG.getScale2(this, {
|
694
|
-
'max':this.max,
|
695
|
-
'min':prop['chart.ymin'],
|
696
|
-
'strict':true,
|
697
|
-
'scale.thousand':prop['chart.scale.thousand'],
|
698
|
-
'scale.point':prop['chart.scale.point'],
|
699
|
-
'scale.decimals':prop['chart.scale.decimals'],
|
700
|
-
'ylabels.count':prop['chart.ylabels.count'],
|
701
|
-
'scale.round':prop['chart.scale.round'],
|
702
|
-
'units.pre': prop['chart.units.pre'],
|
703
|
-
'units.post': prop['chart.units.post']
|
704
|
-
});
|
705
|
-
|
706
|
-
this.max = this.scale2.max ? this.scale2.max : 0;
|
707
|
-
|
708
|
-
// Check for negative values
|
709
|
-
if (!prop['chart.outofbounds']) {
|
710
|
-
for (dataset=0; dataset<this.data.length; ++dataset) {
|
711
|
-
if (RGraph.isArray(this.data[dataset])) {
|
712
|
-
for (var datapoint=0; datapoint<this.data[dataset].length; datapoint++) {
|
713
|
-
// Check for negative values
|
714
|
-
this.hasnegativevalues = (this.data[dataset][datapoint] < 0) || this.hasnegativevalues;
|
715
|
-
}
|
716
|
-
}
|
717
|
-
}
|
718
|
-
}
|
719
|
-
|
720
|
-
} else {
|
721
|
-
|
722
|
-
this.min = prop['chart.ymin'] ? prop['chart.ymin'] : 0;
|
723
|
-
|
724
|
-
// Work out the max Y value
|
725
|
-
for (dataset=0; dataset<this.data.length; ++dataset) {
|
726
|
-
for (var datapoint=0; datapoint<this.data[dataset].length; datapoint++) {
|
727
|
-
|
728
|
-
this.max = Math.max(this.max, this.data[dataset][datapoint] ? Math.abs(parseFloat(this.data[dataset][datapoint])) : 0);
|
729
|
-
|
730
|
-
// Check for negative values
|
731
|
-
if (!prop['chart.outofbounds']) {
|
732
|
-
this.hasnegativevalues = (this.data[dataset][datapoint] < 0) || this.hasnegativevalues;
|
733
|
-
}
|
734
|
-
}
|
735
|
-
}
|
736
|
-
|
737
|
-
this.scale2 = RG.getScale2(this, {
|
738
|
-
'max':this.max,
|
739
|
-
'min':prop['chart.ymin'],
|
740
|
-
'scale.thousand':prop['chart.scale.thousand'],
|
741
|
-
'scale.point':prop['chart.scale.point'],
|
742
|
-
'scale.decimals':prop['chart.scale.decimals'],
|
743
|
-
'ylabels.count':prop['chart.ylabels.count'],
|
744
|
-
'scale.round':prop['chart.scale.round'],
|
745
|
-
'units.pre': prop['chart.units.pre'],
|
746
|
-
'units.post': prop['chart.units.post']
|
747
|
-
});
|
748
|
-
|
749
|
-
this.max = this.scale2.max ? this.scale2.max : 0;
|
750
|
-
}
|
751
|
-
|
752
|
-
/**
|
753
|
-
* Setup the context menu if required
|
754
|
-
*/
|
755
|
-
if (prop['chart.contextmenu']) {
|
756
|
-
RG.ShowContext(this);
|
757
|
-
}
|
758
|
-
|
759
|
-
/**
|
760
|
-
* Reset the coords arrays otherwise it will keep growing
|
761
|
-
*/
|
762
|
-
this.coords = [];
|
763
|
-
this.coordsText = [];
|
764
|
-
|
765
|
-
/**
|
766
|
-
* Work out a few things. They need to be here because they depend on things you can change before you
|
767
|
-
* call Draw() but after you instantiate the object
|
768
|
-
*/
|
769
|
-
this.grapharea = ca.height - this.gutterTop - this.gutterBottom;
|
770
|
-
this.halfgrapharea = this.grapharea / 2;
|
771
|
-
this.halfTextHeight = prop['chart.text.size'] / 2;
|
772
|
-
|
773
|
-
// Check the combination of the X axis position and if there any negative values
|
774
|
-
//
|
775
|
-
// 25th Feb 2016 - Removed entirely as this is another way to do
|
776
|
-
// offset axes
|
777
|
-
//if (prop['chart.xaxispos'] == 'bottom' && this.hasnegativevalues && !RG.ISOPERA) {
|
778
|
-
// alert('[LINE] You have negative values and the X axis is at the bottom. This is not good...');
|
779
|
-
//}
|
780
|
-
|
781
|
-
if (prop['chart.variant'] == '3d') {
|
782
|
-
RG.Draw3DAxes(this);
|
783
|
-
}
|
784
|
-
|
785
|
-
// Progressively Draw the chart
|
786
|
-
RG.background.Draw(this);
|
787
|
-
|
788
|
-
|
789
|
-
/**
|
790
|
-
* Draw any horizontal bars that have been defined
|
791
|
-
*/
|
792
|
-
if (prop['chart.background.hbars'] && prop['chart.background.hbars'].length > 0) {
|
793
|
-
RG.DrawBars(this);
|
794
|
-
}
|
795
|
-
|
796
|
-
if (prop['chart.axesontop'] == false) {
|
797
|
-
this.DrawAxes();
|
798
|
-
}
|
799
|
-
|
800
|
-
//if (typeof(shadowColor) == 'object') {
|
801
|
-
// shadowColor = RG.array_reverse(RG.array_clone(prop['chart.shadow.color']]);
|
802
|
-
//}
|
803
|
-
|
804
|
-
/**
|
805
|
-
* This facilitates the new Trace2 effect
|
806
|
-
*/
|
807
|
-
|
808
|
-
co.save()
|
809
|
-
co.beginPath();
|
810
|
-
co.rect(0, 0, ca.width * prop['chart.animation.trace.clip'], ca.height);
|
811
|
-
co.clip();
|
812
|
-
|
813
|
-
for (var i=0, j=0, len=this.data.length; i<len; i++, j++) {
|
814
|
-
|
815
|
-
co.beginPath();
|
816
|
-
|
817
|
-
/**
|
818
|
-
* Turn on the shadow if required
|
819
|
-
*/
|
820
|
-
if (!prop['chart.filled']) {
|
821
|
-
this.SetShadow(i);
|
822
|
-
}
|
823
|
-
|
824
|
-
/**
|
825
|
-
* Draw the line
|
826
|
-
*/
|
827
|
-
|
828
|
-
if (prop['chart.fillstyle']) {
|
829
|
-
if (typeof(prop['chart.fillstyle']) == 'object' && prop['chart.fillstyle'][j]) {
|
830
|
-
var fill = prop['chart.fillstyle'][j];
|
831
|
-
|
832
|
-
} else if (typeof(prop['chart.fillstyle']) == 'object' && prop['chart.fillstyle'].toString().indexOf('Gradient') > 0) {
|
833
|
-
var fill = prop['chart.fillstyle'];
|
834
|
-
|
835
|
-
} else if (typeof(prop['chart.fillstyle']) == 'string') {
|
836
|
-
var fill = prop['chart.fillstyle'];
|
837
|
-
|
838
|
-
}
|
839
|
-
} else if (prop['chart.filled']) {
|
840
|
-
var fill = prop['chart.colors'][j];
|
841
|
-
|
842
|
-
} else {
|
843
|
-
var fill = null;
|
844
|
-
}
|
845
|
-
|
846
|
-
/**
|
847
|
-
* Figure out the tickmark to use
|
848
|
-
*/
|
849
|
-
if (prop['chart.tickmarks'] && typeof(prop['chart.tickmarks']) == 'object') {
|
850
|
-
var tickmarks = prop['chart.tickmarks'][i];
|
851
|
-
} else if (prop['chart.tickmarks'] && typeof(prop['chart.tickmarks']) == 'string') {
|
852
|
-
var tickmarks = prop['chart.tickmarks'];
|
853
|
-
} else if (prop['chart.tickmarks'] && typeof(prop['chart.tickmarks']) == 'function') {
|
854
|
-
var tickmarks = prop['chart.tickmarks'];
|
855
|
-
} else {
|
856
|
-
var tickmarks = null;
|
857
|
-
}
|
858
|
-
|
859
|
-
//
|
860
|
-
// Draw the line, accounting for the outofboundsClip option
|
861
|
-
//
|
862
|
-
if (prop['chart.outofbounds.clip']) {
|
863
|
-
pa2(
|
864
|
-
co,
|
865
|
-
'sa b r % % % % cl b',
|
866
|
-
0,
|
867
|
-
this.gutterTop,
|
868
|
-
ca.width,
|
869
|
-
ca.height - this.gutterTop - this.gutterBottom
|
870
|
-
);
|
871
|
-
}
|
872
|
-
this.drawLine(
|
873
|
-
this.data[i],
|
874
|
-
prop['chart.colors'][j],
|
875
|
-
fill,
|
876
|
-
this.getLineWidth(j),
|
877
|
-
tickmarks,
|
878
|
-
i
|
879
|
-
);
|
880
|
-
if (prop['chart.outofbounds.clip']) {
|
881
|
-
co.restore();
|
882
|
-
}
|
883
|
-
|
884
|
-
co.stroke();
|
885
|
-
|
886
|
-
/**
|
887
|
-
* Draw errorbars
|
888
|
-
*
|
889
|
-
* ** This is now done in the redrawLine function **
|
890
|
-
*/
|
891
|
-
}
|
892
|
-
|
893
|
-
/**
|
894
|
-
* If the line is filled re-stroke the lines
|
895
|
-
*/
|
896
|
-
if (prop['chart.filled'] && prop['chart.filled.accumulative'] && !prop['chart.curvy']) {
|
897
|
-
|
898
|
-
for (var i=0; i<this.coords2.length; ++i) {
|
899
|
-
|
900
|
-
co.beginPath();
|
901
|
-
co.lineWidth = this.GetLineWidth(i);
|
902
|
-
co.strokeStyle = !this.hidden(i) ? prop['chart.colors'][i] : 'rgba(0,0,0,0)';
|
903
|
-
|
904
|
-
for (var j=0,len=this.coords2[i].length; j<len; ++j) {
|
905
|
-
|
906
|
-
if (j == 0 || this.coords2[i][j][1] == null || (this.coords2[i][j - 1] && this.coords2[i][j - 1][1] == null)) {
|
907
|
-
co.moveTo(this.coords2[i][j][0], this.coords2[i][j][1]);
|
908
|
-
} else {
|
909
|
-
if (prop['chart.stepped']) {
|
910
|
-
co.lineTo(this.coords2[i][j][0], this.coords2[i][j - 1][1]);
|
911
|
-
}
|
912
|
-
co.lineTo(this.coords2[i][j][0], this.coords2[i][j][1]);
|
913
|
-
}
|
914
|
-
}
|
915
|
-
|
916
|
-
co.stroke();
|
917
|
-
// No fill!
|
918
|
-
}
|
919
|
-
|
920
|
-
//Redraw the tickmarks
|
921
|
-
if (prop['chart.tickmarks']) {
|
922
|
-
|
923
|
-
co.beginPath();
|
924
|
-
|
925
|
-
co.fillStyle = 'white';
|
926
|
-
|
927
|
-
for (var i=0,len=this.coords2.length; i<len; ++i) {
|
928
|
-
|
929
|
-
co.beginPath();
|
930
|
-
co.strokeStyle = prop['chart.colors'][i];
|
931
|
-
|
932
|
-
for (var j=0; j<this.coords2[i].length; ++j) {
|
933
|
-
if (typeof(this.coords2[i][j]) == 'object' && typeof(this.coords2[i][j][0]) == 'number' && typeof(this.coords2[i][j][1]) == 'number') {
|
934
|
-
|
935
|
-
var tickmarks = typeof(prop['chart.tickmarks']) == 'object' ? prop['chart.tickmarks'][i] : prop['chart.tickmarks'];
|
936
|
-
|
937
|
-
this.DrawTick(
|
938
|
-
this.coords2[i],
|
939
|
-
this.coords2[i][j][0],
|
940
|
-
this.coords2[i][j][1],
|
941
|
-
co.strokeStyle,
|
942
|
-
false,
|
943
|
-
j == 0 ? 0 : this.coords2[i][j - 1][0],
|
944
|
-
j == 0 ? 0 : this.coords2[i][j - 1][1],
|
945
|
-
tickmarks,
|
946
|
-
j,
|
947
|
-
i
|
948
|
-
);
|
949
|
-
}
|
950
|
-
}
|
951
|
-
}
|
952
|
-
|
953
|
-
co.stroke();
|
954
|
-
co.fill();
|
955
|
-
}
|
956
|
-
|
957
|
-
} else if (prop['chart.filled'] && prop['chart.filled.accumulative'] && prop['chart.curvy']) {
|
958
|
-
|
959
|
-
// Restroke the curvy filled accumulative lines
|
960
|
-
|
961
|
-
for (var i=0; i<this.coordsSpline.length; i+=1) {
|
962
|
-
co.beginPath();
|
963
|
-
co.strokeStyle = prop['chart.colors'][i];
|
964
|
-
co.lineWidth = this.GetLineWidth(i);
|
965
|
-
|
966
|
-
for (var j=0,len=this.coordsSpline[i].length; j<len; j+=1) {
|
967
|
-
|
968
|
-
var point = this.coordsSpline[i][j];
|
969
|
-
|
970
|
-
j == 0 ? co.moveTo(point[0], point[1]) : co.lineTo(point[0], point[1]);
|
971
|
-
}
|
972
|
-
|
973
|
-
co.stroke();
|
974
|
-
}
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
for (var i=0,len=this.coords2.length; i<len; i+=1) {
|
983
|
-
for (var j=0,len2=this.coords2[i].length; j<len2; ++j) {
|
984
|
-
if (typeof(this.coords2[i][j]) == 'object' && typeof(this.coords2[i][j][0]) == 'number' && typeof(this.coords2[i][j][1]) == 'number') {
|
985
|
-
|
986
|
-
var tickmarks = typeof prop['chart.tickmarks'] == 'object' && !RGraph.is_null(prop['chart.tickmarks']) ? prop['chart.tickmarks'][i] : prop['chart.tickmarks'];
|
987
|
-
co.strokeStyle = prop['chart.colors'][i];
|
988
|
-
this.DrawTick(
|
989
|
-
this.coords2[i],
|
990
|
-
this.coords2[i][j][0],
|
991
|
-
this.coords2[i][j][1],
|
992
|
-
prop['chart.colors'][i],
|
993
|
-
false,
|
994
|
-
j == 0 ? 0 : this.coords2[i][j - 1][0],
|
995
|
-
j == 0 ? 0 : this.coords2[i][j - 1][1],
|
996
|
-
tickmarks,
|
997
|
-
j,
|
998
|
-
i
|
999
|
-
);
|
1000
|
-
}
|
1001
|
-
}
|
1002
|
-
}
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
}
|
1007
|
-
co.restore();
|
1008
|
-
|
1009
|
-
// ???
|
1010
|
-
co.beginPath();
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
/**
|
1016
|
-
* If the axes have been requested to be on top, do that
|
1017
|
-
*/
|
1018
|
-
if (prop['chart.axesontop']) {
|
1019
|
-
this.DrawAxes();
|
1020
|
-
}
|
1021
|
-
|
1022
|
-
/**
|
1023
|
-
* Draw the labels
|
1024
|
-
*/
|
1025
|
-
this.DrawLabels();
|
1026
|
-
|
1027
|
-
/**
|
1028
|
-
* Draw the range if necessary
|
1029
|
-
*/
|
1030
|
-
this.DrawRange();
|
1031
|
-
|
1032
|
-
// Draw a key if necessary
|
1033
|
-
if (prop['chart.key'] && prop['chart.key'].length && RG.DrawKey) {
|
1034
|
-
RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
|
1035
|
-
}
|
1036
|
-
|
1037
|
-
/**
|
1038
|
-
* Draw " above" labels if enabled
|
1039
|
-
*/
|
1040
|
-
if (prop['chart.labels.above']) {
|
1041
|
-
this.drawAboveLabels();
|
1042
|
-
}
|
1043
|
-
|
1044
|
-
/**
|
1045
|
-
* Draw the "in graph" labels
|
1046
|
-
*/
|
1047
|
-
RG.DrawInGraphLabels(this);
|
1048
|
-
|
1049
|
-
/**
|
1050
|
-
* Redraw the lines if a filled range is on the cards
|
1051
|
-
*/
|
1052
|
-
if (prop['chart.filled'] && prop['chart.filled.range'] && this.data.length == 2) {
|
1053
|
-
|
1054
|
-
co.beginPath();
|
1055
|
-
var len = this.coords.length / 2;
|
1056
|
-
co.lineWidth = prop['chart.linewidth'];
|
1057
|
-
co.strokeStyle = this.hidden(0) ? 'rgba(0,0,0,0)' : prop['chart.colors'][0];
|
1058
|
-
|
1059
|
-
for (var i=0; i<len; ++i) {
|
1060
|
-
|
1061
|
-
if (!RG.isNull(this.coords[i][1])) {
|
1062
|
-
if (i == 0) {
|
1063
|
-
co.moveTo(this.coords[i][0], this.coords[i][1]);
|
1064
|
-
} else {
|
1065
|
-
co.lineTo(this.coords[i][0], this.coords[i][1]);
|
1066
|
-
}
|
1067
|
-
}
|
1068
|
-
}
|
1069
|
-
|
1070
|
-
co.stroke();
|
1071
|
-
|
1072
|
-
|
1073
|
-
co.beginPath();
|
1074
|
-
|
1075
|
-
if (prop['chart.colors'][1]) {
|
1076
|
-
co.strokeStyle = this.hidden(1) ? 'rgba(0,0,0,0)' : prop['chart.colors'][1];
|
1077
|
-
}
|
1078
|
-
|
1079
|
-
for (var i=this.coords.length - 1; i>=len; --i) {
|
1080
|
-
if (!RG.is_null(this.coords[i][1])) {
|
1081
|
-
if (i == (this.coords.length - 1)) {
|
1082
|
-
co.moveTo(this.coords[i][0], this.coords[i][1]);
|
1083
|
-
} else {
|
1084
|
-
co.lineTo(this.coords[i][0], this.coords[i][1]);
|
1085
|
-
}
|
1086
|
-
}
|
1087
|
-
}
|
1088
|
-
|
1089
|
-
co.stroke();
|
1090
|
-
|
1091
|
-
|
1092
|
-
} else if (prop['chart.filled'] && prop['chart.filled.range']) {
|
1093
|
-
alert('[LINE] You must have only two sets of data for a filled range chart');
|
1094
|
-
}
|
1095
|
-
|
1096
|
-
/**
|
1097
|
-
* This function enables resizing
|
1098
|
-
*/
|
1099
|
-
if (prop['chart.resizable']) {
|
1100
|
-
RG.AllowResizing(this);
|
1101
|
-
}
|
1102
|
-
|
1103
|
-
|
1104
|
-
/**
|
1105
|
-
* This installs the event listeners
|
1106
|
-
*/
|
1107
|
-
RG.InstallEventListeners(this);
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
/**
|
1115
|
-
* Fire the onfirstdraw event
|
1116
|
-
*/
|
1117
|
-
if (this.firstDraw) {
|
1118
|
-
RG.fireCustomEvent(this, 'onfirstdraw');
|
1119
|
-
this.firstDraw = false;
|
1120
|
-
this.firstDrawFunc();
|
1121
|
-
}
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
/**
|
1127
|
-
* Fire the RGraph ondraw event
|
1128
|
-
*/
|
1129
|
-
RG.FireCustomEvent(this, 'ondraw');
|
1130
|
-
|
1131
|
-
return this;
|
1132
|
-
};
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
/**
|
1137
|
-
* Used in chaining. Runs a function there and then - not waiting for
|
1138
|
-
* the events to fire (eg the onbeforedraw event)
|
1139
|
-
*
|
1140
|
-
* @param function func The function to execute
|
1141
|
-
*/
|
1142
|
-
this.exec = function (func)
|
1143
|
-
{
|
1144
|
-
func(this);
|
1145
|
-
|
1146
|
-
return this;
|
1147
|
-
};
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
/**
|
1153
|
-
* Draws the axes
|
1154
|
-
*/
|
1155
|
-
this.drawAxes =
|
1156
|
-
this.DrawAxes = function ()
|
1157
|
-
{
|
1158
|
-
// Don't draw the axes?
|
1159
|
-
if (prop['chart.noaxes']) {
|
1160
|
-
return;
|
1161
|
-
}
|
1162
|
-
|
1163
|
-
// Turn any shadow off
|
1164
|
-
RG.noShadow(this);
|
1165
|
-
|
1166
|
-
co.lineWidth = prop['chart.axis.linewidth'] + 0.001;
|
1167
|
-
co.lineCap = 'square';
|
1168
|
-
co.lineJoin = 'miter';
|
1169
|
-
co.strokeStyle = prop['chart.axis.color'];
|
1170
|
-
coords = {
|
1171
|
-
xaxis: {},
|
1172
|
-
yaxis: {}
|
1173
|
-
};
|
1174
|
-
|
1175
|
-
co.beginPath();
|
1176
|
-
|
1177
|
-
// Draw the X axis
|
1178
|
-
if (prop['chart.noxaxis'] == false) {
|
1179
|
-
if (prop['chart.xaxispos'] == 'center') {
|
1180
|
-
coords.xaxis = [
|
1181
|
-
this.gutterLeft,
|
1182
|
-
ma.round((this.grapharea / 2) + this.gutterTop),
|
1183
|
-
ca.width - this.gutterRight,
|
1184
|
-
ma.round((this.grapharea / 2) + this.gutterTop)
|
1185
|
-
];
|
1186
|
-
} else if (prop['chart.xaxispos'] === 'top') {
|
1187
|
-
coords.xaxis = [
|
1188
|
-
this.gutterLeft,
|
1189
|
-
this.gutterTop,
|
1190
|
-
ca.width - this.gutterRight,
|
1191
|
-
this.gutterTop
|
1192
|
-
];
|
1193
|
-
} else {
|
1194
|
-
|
1195
|
-
var y = ma.round(this.getYCoord(prop['chart.ymin'] > 0 ? prop['chart.ymin'] : 0));
|
1196
|
-
|
1197
|
-
coords.xaxis = [
|
1198
|
-
this.gutterLeft,
|
1199
|
-
y,
|
1200
|
-
ca.width - this.gutterRight,
|
1201
|
-
y
|
1202
|
-
];
|
1203
|
-
}
|
1204
|
-
|
1205
|
-
co.moveTo(coords.xaxis[0], coords.xaxis[1]);
|
1206
|
-
co.lineTo(coords.xaxis[2], coords.xaxis[3]);
|
1207
|
-
|
1208
|
-
// Save the coords so that they can
|
1209
|
-
// be referenced at a later time
|
1210
|
-
this.coordsAxes = coords;
|
1211
|
-
}
|
1212
|
-
|
1213
|
-
// Draw the Y axis
|
1214
|
-
if (prop['chart.noyaxis'] == false) {
|
1215
|
-
if (prop['chart.yaxispos'] == 'left') {
|
1216
|
-
co.moveTo(this.gutterLeft, this.gutterTop);
|
1217
|
-
co.lineTo(this.gutterLeft, ca.height - this.gutterBottom);
|
1218
|
-
} else {
|
1219
|
-
co.moveTo(ca.width - this.gutterRight, this.gutterTop);
|
1220
|
-
co.lineTo(ca.width - this.gutterRight, ca.height - this.gutterBottom);
|
1221
|
-
}
|
1222
|
-
}
|
1223
|
-
|
1224
|
-
/**
|
1225
|
-
* Draw the X tickmarks
|
1226
|
-
*/
|
1227
|
-
if (prop['chart.noxaxis'] == false && prop['chart.numxticks'] > 0) {
|
1228
|
-
|
1229
|
-
var xTickInterval = (ca.width - this.gutterLeft - this.gutterRight) / prop['chart.numxticks'];
|
1230
|
-
|
1231
|
-
|
1232
|
-
if (!xTickInterval || xTickInterval <= 0) {
|
1233
|
-
xTickInterval = (ca.width - this.gutterLeft - this.gutterRight) / (prop['chart.labels'] && prop['chart.labels'].length ? prop['chart.labels'].length - 1 : 10);
|
1234
|
-
}
|
1235
|
-
|
1236
|
-
for (x=this.gutterLeft + (prop['chart.yaxispos'] == 'left' ? xTickInterval : 0); x<=(ca.width - this.gutterRight + 1 ); x+=xTickInterval) {
|
1237
|
-
|
1238
|
-
if (prop['chart.yaxispos'] == 'right' && x >= (ca.width - this.gutterRight - 1) ) {
|
1239
|
-
break;
|
1240
|
-
}
|
1241
|
-
|
1242
|
-
// If the last tick is not desired...
|
1243
|
-
if (prop['chart.noendxtick']) {
|
1244
|
-
if (prop['chart.yaxispos'] == 'left' && x >= (ca.width - this.gutterRight - 1)) {
|
1245
|
-
break;
|
1246
|
-
} else if (prop['chart.yaxispos'] == 'right' && x == this.gutterLeft) {
|
1247
|
-
continue;
|
1248
|
-
}
|
1249
|
-
}
|
1250
|
-
|
1251
|
-
var yStart = prop['chart.xaxispos'] === 'center' ? (this.gutterTop + (this.grapharea / 2)) - 3 : ca.height - this.gutterBottom;
|
1252
|
-
var yEnd = prop['chart.xaxispos'] === 'center' ? yStart + 6 : ca.height - this.gutterBottom - (x % 60 == 0 ? prop['chart.largexticks'] * prop['chart.tickdirection'] : prop['chart.smallxticks'] * prop['chart.tickdirection']);
|
1253
|
-
|
1254
|
-
|
1255
|
-
// Draw the tick
|
1256
|
-
if (prop['chart.ymin'] >= 0 && prop['chart.xaxispos'] === 'bottom') {
|
1257
|
-
var yStart = this.getYCoord(prop['chart.ymin']) - (prop['chart.ymin'] >= 0 ? 0 : 3),
|
1258
|
-
yEnd = this.getYCoord(prop['chart.ymin']) + 3;
|
1259
|
-
|
1260
|
-
} else if (prop['chart.xaxispos'] == 'center') {
|
1261
|
-
var yStart = Math.round((this.gutterTop + (this.grapharea / 2))) - 3,
|
1262
|
-
yEnd = yStart + 6;
|
1263
|
-
|
1264
|
-
} else if (prop['chart.xaxispos'] == 'bottom') {
|
1265
|
-
|
1266
|
-
var yStart = this.getYCoord(0) - (prop['chart.ymin'] !== 0 ? 3 : 0),
|
1267
|
-
yEnd = this.getYCoord(0) - (x % 60 == 0 ? prop['chart.largexticks'] * prop['chart.tickdirection'] : prop['chart.smallxticks'] * prop['chart.tickdirection']);
|
1268
|
-
yEnd += 0;
|
1269
|
-
|
1270
|
-
|
1271
|
-
} else if (prop['chart.xaxispos'] == 'top') {
|
1272
|
-
|
1273
|
-
yStart = this.gutterTop - 3;
|
1274
|
-
yEnd = this.gutterTop;
|
1275
|
-
}
|
1276
|
-
|
1277
|
-
|
1278
|
-
co.moveTo(ma.round(x), yStart);
|
1279
|
-
co.lineTo(ma.round(x), yEnd);
|
1280
|
-
}
|
1281
|
-
|
1282
|
-
// Draw an extra tickmark if there is no X axis, but there IS a Y axis
|
1283
|
-
// OR if there is an offset X axis
|
1284
|
-
} else if (prop['chart.noyaxis'] == false && prop['chart.numyticks'] > 0) {
|
1285
|
-
|
1286
|
-
if (!prop['chart.noendytick']) {
|
1287
|
-
if (prop['chart.yaxispos'] == 'left') {
|
1288
|
-
co.moveTo(this.gutterLeft, Math.round(ca.height - this.gutterBottom));
|
1289
|
-
co.lineTo(this.gutterLeft - prop['chart.smallyticks'], Math.round(ca.height - this.gutterBottom));
|
1290
|
-
} else {
|
1291
|
-
co.moveTo(ca.width - this.gutterRight, Math.round(ca.height - this.gutterBottom));
|
1292
|
-
co.lineTo(ca.width - this.gutterRight + prop['chart.smallyticks'], Math.round(ca.height - this.gutterBottom));
|
1293
|
-
}
|
1294
|
-
}
|
1295
|
-
}
|
1296
|
-
|
1297
|
-
/**
|
1298
|
-
* Draw the Y tickmarks
|
1299
|
-
*/
|
1300
|
-
var numyticks = prop['chart.numyticks'];
|
1301
|
-
|
1302
|
-
if (prop['chart.noyaxis'] == false && numyticks > 0) {
|
1303
|
-
|
1304
|
-
var counter = 0,
|
1305
|
-
adjustment = 0;
|
1306
|
-
|
1307
|
-
if (prop['chart.yaxispos'] == 'right') {
|
1308
|
-
adjustment = (ca.width - this.gutterLeft - this.gutterRight);
|
1309
|
-
}
|
1310
|
-
|
1311
|
-
// X axis at the center
|
1312
|
-
if (prop['chart.xaxispos'] == 'center') {
|
1313
|
-
var interval = (this.grapharea / numyticks);
|
1314
|
-
var lineto = (prop['chart.yaxispos'] == 'left' ? this.gutterLeft : ca.width - this.gutterRight + prop['chart.smallyticks']);
|
1315
|
-
|
1316
|
-
// Draw the upper halves Y tick marks
|
1317
|
-
for (y=this.gutterTop; y<(this.grapharea / 2) + this.gutterTop; y+=interval) {
|
1318
|
-
if (y < (this.grapharea / 2) + this.gutterTop) {
|
1319
|
-
co.moveTo((prop['chart.yaxispos'] == 'left' ? this.gutterLeft - prop['chart.smallyticks'] : ca.width - this.gutterRight), Math.round(y));
|
1320
|
-
co.lineTo(lineto, Math.round(y));
|
1321
|
-
}
|
1322
|
-
}
|
1323
|
-
|
1324
|
-
// Draw the lower halves Y tick marks
|
1325
|
-
for (y=this.gutterTop + (this.halfgrapharea) + interval; y <= this.grapharea + this.gutterTop; y+=interval) {
|
1326
|
-
co.moveTo((prop['chart.yaxispos'] == 'left' ? this.gutterLeft - prop['chart.smallyticks'] : ca.width - this.gutterRight), Math.round(y));
|
1327
|
-
co.lineTo(lineto, Math.round(y));
|
1328
|
-
}
|
1329
|
-
|
1330
|
-
// X axis at the top
|
1331
|
-
} else if (prop['chart.xaxispos'] == 'top') {
|
1332
|
-
var interval = (this.grapharea / numyticks);
|
1333
|
-
var lineto = (prop['chart.yaxispos'] == 'left' ? this.gutterLeft : ca.width - this.gutterRight + prop['chart.smallyticks']);
|
1334
|
-
|
1335
|
-
// Draw the Y tick marks
|
1336
|
-
for (y=this.gutterTop + interval; y <= this.grapharea + this.gutterBottom; y+=interval) {
|
1337
|
-
co.moveTo((prop['chart.yaxispos'] == 'left' ? this.gutterLeft - prop['chart.smallyticks'] : ca.width - this.gutterRight), Math.round(y));
|
1338
|
-
co.lineTo(lineto, Math.round(y));
|
1339
|
-
}
|
1340
|
-
|
1341
|
-
|
1342
|
-
// If there's no X axis draw an extra tick
|
1343
|
-
if (prop['chart.noxaxis'] && prop['chart.noendytick'] == false) {
|
1344
|
-
co.moveTo((prop['chart.yaxispos'] == 'left' ? this.gutterLeft - prop['chart.smallyticks'] : ca.width - this.gutterRight), this.gutterTop);
|
1345
|
-
co.lineTo(lineto, this.gutterTop);
|
1346
|
-
}
|
1347
|
-
|
1348
|
-
// X axis at the bottom
|
1349
|
-
} else {
|
1350
|
-
|
1351
|
-
var lineto = (prop['chart.yaxispos'] == 'left' ? this.gutterLeft - prop['chart.smallyticks'] : ca.width - this.gutterRight + prop['chart.smallyticks']);
|
1352
|
-
|
1353
|
-
for (y=this.gutterTop;
|
1354
|
-
y<(ca.height - this.gutterBottom) && counter < numyticks;
|
1355
|
-
y+=( (ca.height - this.gutterTop - this.gutterBottom) / numyticks)
|
1356
|
-
) {
|
1357
|
-
|
1358
|
-
// This check is so that there's no tickmark at
|
1359
|
-
// the same position as the X axis
|
1360
|
-
if (ma.round(y) !== ma.round(this.coordsAxes.xaxis[1])) {
|
1361
|
-
co.moveTo(this.gutterLeft + adjustment, ma.round(y));
|
1362
|
-
co.lineTo(lineto, ma.round(y));
|
1363
|
-
}
|
1364
|
-
|
1365
|
-
var counter = counter + 1;
|
1366
|
-
}
|
1367
|
-
|
1368
|
-
// Draw an extra Y tick if there's an offsetX axis
|
1369
|
-
if (prop['chart.ymin'] < 0) {
|
1370
|
-
|
1371
|
-
co.moveTo(
|
1372
|
-
(prop['chart.yaxispos'] == 'left' ? this.gutterLeft : ca.width - this.gutterRight),
|
1373
|
-
ma.round(y)
|
1374
|
-
);
|
1375
|
-
|
1376
|
-
co.lineTo(
|
1377
|
-
lineto,
|
1378
|
-
ma.round(y)
|
1379
|
-
);
|
1380
|
-
}
|
1381
|
-
}
|
1382
|
-
|
1383
|
-
// Draw an extra X tickmark
|
1384
|
-
} else if (prop['chart.noxaxis'] == false && prop['chart.numxticks'] > 0) {
|
1385
|
-
|
1386
|
-
if (prop['chart.yaxispos'] == 'left') {
|
1387
|
-
co.moveTo(this.gutterLeft, prop['chart.xaxispos'] == 'top' ? this.gutterTop : ca.height - this.gutterBottom);
|
1388
|
-
co.lineTo(this.gutterLeft, prop['chart.xaxispos'] == 'top' ? this.gutterTop - prop['chart.smallxticks'] : ca.height - this.gutterBottom + prop['chart.smallxticks']);
|
1389
|
-
} else {
|
1390
|
-
co.moveTo(ca.width - this.gutterRight, ca.height - this.gutterBottom);
|
1391
|
-
co.lineTo(ca.width - this.gutterRight, ca.height - this.gutterBottom + prop['chart.smallxticks']);
|
1392
|
-
}
|
1393
|
-
}
|
1394
|
-
|
1395
|
-
co.stroke();
|
1396
|
-
|
1397
|
-
/**
|
1398
|
-
* This is here so that setting the color after this function doesn't
|
1399
|
-
* change the color of the axes
|
1400
|
-
*/
|
1401
|
-
co.beginPath();
|
1402
|
-
};
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
/**
|
1408
|
-
* Draw the text labels for the axes
|
1409
|
-
*/
|
1410
|
-
this.drawLabels =
|
1411
|
-
this.DrawLabels = function ()
|
1412
|
-
{
|
1413
|
-
co.strokeStyle = 'black';
|
1414
|
-
co.fillStyle = prop['chart.text.color'];
|
1415
|
-
co.lineWidth = 1;
|
1416
|
-
|
1417
|
-
// Turn off any shadow
|
1418
|
-
RG.NoShadow(this);
|
1419
|
-
|
1420
|
-
// This needs to be here
|
1421
|
-
var font = prop['chart.text.font'];
|
1422
|
-
var text_size = prop['chart.text.size'];
|
1423
|
-
var decimals = prop['chart.scale.decimals'];
|
1424
|
-
var context = co;
|
1425
|
-
var canvas = ca;
|
1426
|
-
var ymin = prop['chart.ymin'];
|
1427
|
-
|
1428
|
-
// Draw the Y axis labels
|
1429
|
-
if (prop['chart.ylabels'] && prop['chart.ylabels.specific'] == null) {
|
1430
|
-
|
1431
|
-
var units_pre = prop['chart.units.pre'];
|
1432
|
-
var units_post = prop['chart.units.post'];
|
1433
|
-
var xpos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft - 5 : ca.width - this.gutterRight + 5;
|
1434
|
-
var align = prop['chart.yaxispos'] == 'left' ? 'right' : 'left';
|
1435
|
-
var numYLabels = this.scale2.labels.length;
|
1436
|
-
var bounding = false;
|
1437
|
-
var bgcolor = prop['chart.ylabels.inside'] ? prop['chart.ylabels.inside.color'] : null;
|
1438
|
-
var offsetx = prop['chart.ylabels.offsetx'];
|
1439
|
-
var offsety = prop['chart.ylabels.offsety'];
|
1440
|
-
|
1441
|
-
|
1442
|
-
/**
|
1443
|
-
* If the Y labels are inside the Y axis, invert the alignment
|
1444
|
-
*/
|
1445
|
-
if (prop['chart.ylabels.inside'] == true && align == 'left') {
|
1446
|
-
xpos -= 10;
|
1447
|
-
align = 'right';
|
1448
|
-
bounding = true;
|
1449
|
-
|
1450
|
-
|
1451
|
-
} else if (prop['chart.ylabels.inside'] == true && align == 'right') {
|
1452
|
-
xpos += 10;
|
1453
|
-
align = 'left';
|
1454
|
-
bounding = true;
|
1455
|
-
}
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
/**
|
1461
|
-
* X axis in the center
|
1462
|
-
*/
|
1463
|
-
if (prop['chart.xaxispos'] == 'center') {
|
1464
|
-
|
1465
|
-
var half = this.grapharea / 2;
|
1466
|
-
|
1467
|
-
/**
|
1468
|
-
* Draw the top half
|
1469
|
-
*/
|
1470
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1471
|
-
RG.text2(this, {
|
1472
|
-
'font': font,
|
1473
|
-
'size': text_size,
|
1474
|
-
'x': xpos + offsetx,
|
1475
|
-
'y': this.gutterTop + half - (((i+1)/numYLabels) * half) + offsety,
|
1476
|
-
'valign': 'center',
|
1477
|
-
'halign':align,
|
1478
|
-
'bounding': bounding,
|
1479
|
-
'boundingFill': bgcolor,
|
1480
|
-
'text': this.scale2.labels[i],
|
1481
|
-
'tag': 'scale'
|
1482
|
-
});
|
1483
|
-
}
|
1484
|
-
|
1485
|
-
/**
|
1486
|
-
* Draw the bottom half
|
1487
|
-
*/
|
1488
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1489
|
-
RG.text2(this, {
|
1490
|
-
'font': font,
|
1491
|
-
'size': text_size,
|
1492
|
-
'x': xpos + offsetx,
|
1493
|
-
'y': this.gutterTop + half + (((i+1)/numYLabels) * half) + offsety,
|
1494
|
-
'valign': 'center',
|
1495
|
-
'halign':align,
|
1496
|
-
'bounding': bounding,
|
1497
|
-
'boundingFill': bgcolor,
|
1498
|
-
'text': '-' + this.scale2.labels[i],
|
1499
|
-
'tag': 'scale'
|
1500
|
-
});
|
1501
|
-
}
|
1502
|
-
|
1503
|
-
// No X axis - so draw 0
|
1504
|
-
if (prop['chart.noxaxis'] == true || ymin != 0 || prop['chart.scale.zerostart']) {
|
1505
|
-
RG.text2(this,{
|
1506
|
-
'font':font,
|
1507
|
-
'size':text_size,
|
1508
|
-
'x':xpos + offsetx,
|
1509
|
-
'y':this.gutterTop + half + offsety,
|
1510
|
-
'text':prop['chart.units.pre'] + ymin.toFixed(decimals) + prop['chart.units.post'],
|
1511
|
-
'bounding':bounding,
|
1512
|
-
'boundingFill':bgcolor,
|
1513
|
-
'valign':'center',
|
1514
|
-
'halign':align,
|
1515
|
-
'tag': 'scale'
|
1516
|
-
});
|
1517
|
-
}
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
/**
|
1522
|
-
* X axis at the top
|
1523
|
-
*/
|
1524
|
-
} else if (prop['chart.xaxispos'] == 'top') {
|
1525
|
-
|
1526
|
-
var half = this.grapharea / 2;
|
1527
|
-
|
1528
|
-
if (prop['chart.scale.invert']) {
|
1529
|
-
|
1530
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1531
|
-
|
1532
|
-
RG.text2(this, {
|
1533
|
-
'font': font,
|
1534
|
-
'size': text_size,
|
1535
|
-
'x': xpos + offsetx,
|
1536
|
-
'y': this.gutterTop + ((i/this.scale2.labels.length) * this.grapharea) + offsety,
|
1537
|
-
'valign': 'center',
|
1538
|
-
'halign':align,
|
1539
|
-
'bounding': bounding,
|
1540
|
-
'boundingFill': bgcolor,
|
1541
|
-
'text': '-' + this.scale2.labels[this.scale2.labels.length - (i+1)],
|
1542
|
-
'tag': 'scale'
|
1543
|
-
});
|
1544
|
-
}
|
1545
|
-
} else {
|
1546
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1547
|
-
RG.text2(this, {
|
1548
|
-
'font': font,
|
1549
|
-
'size': text_size,
|
1550
|
-
'x': xpos + offsetx,
|
1551
|
-
'y': this.gutterTop + (((i+1)/numYLabels) * this.grapharea) + offsety,
|
1552
|
-
'valign': 'center',
|
1553
|
-
'halign':align,
|
1554
|
-
'bounding': bounding,
|
1555
|
-
'boundingFill': bgcolor,
|
1556
|
-
'text': '-' + this.scale2.labels[i],
|
1557
|
-
'tag': 'scale'
|
1558
|
-
});
|
1559
|
-
}
|
1560
|
-
}
|
1561
|
-
|
1562
|
-
// Draw the lower limit if chart.ymin is specified
|
1563
|
-
if ((prop['chart.ymin'] != 0 || prop['chart.noxaxis']) || prop['chart.scale.invert'] || prop['chart.scale.zerostart']) {
|
1564
|
-
RG.text2(this, {
|
1565
|
-
'font':font,
|
1566
|
-
'size':text_size,
|
1567
|
-
'x':xpos + offsetx,
|
1568
|
-
'y': prop['chart.scale.invert'] ? ca.height - this.gutterBottom + offsety : this.gutterTop + offsety,
|
1569
|
-
'text': (prop['chart.ymin'] != 0 ? '-' : '') + RG.number_format(this, prop['chart.ymin'].toFixed(decimals), units_pre, units_post),
|
1570
|
-
'valign':'center',
|
1571
|
-
'halign': align,
|
1572
|
-
'bounding':bounding,
|
1573
|
-
'boundingFill':bgcolor,
|
1574
|
-
'tag': 'scale'
|
1575
|
-
});
|
1576
|
-
}
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
/**
|
1584
|
-
* X axis labels at the bottom
|
1585
|
-
*/
|
1586
|
-
} else {
|
1587
|
-
|
1588
|
-
if (prop['chart.scale.invert']) {
|
1589
|
-
|
1590
|
-
// Draw the minimum value
|
1591
|
-
RG.text2(this, {
|
1592
|
-
'font': font,
|
1593
|
-
'size': text_size,
|
1594
|
-
'x': xpos + offsetx,
|
1595
|
-
'y': this.gutterTop + offsety,
|
1596
|
-
'valign': 'center',
|
1597
|
-
'halign':align,
|
1598
|
-
'bounding': bounding,
|
1599
|
-
'boundingFill': bgcolor,
|
1600
|
-
'text': RG.numberFormat(this, this.min.toFixed(prop['chart.scale.decimals']), units_pre, units_post),
|
1601
|
-
'tag': 'scale'
|
1602
|
-
});
|
1603
|
-
|
1604
|
-
for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
|
1605
|
-
RG.Text2(this, {
|
1606
|
-
'font': font,
|
1607
|
-
'size': text_size,
|
1608
|
-
'x': xpos + offsetx,
|
1609
|
-
'y': this.gutterTop + (((i+1)/this.scale2.labels.length) * this.grapharea) + offsety,
|
1610
|
-
'valign': 'center',
|
1611
|
-
'halign':align,
|
1612
|
-
'bounding': bounding,
|
1613
|
-
'boundingFill': bgcolor,
|
1614
|
-
'text': this.scale2.labels[i],
|
1615
|
-
'tag': 'scale'
|
1616
|
-
});
|
1617
|
-
}
|
1618
|
-
|
1619
|
-
} else {
|
1620
|
-
for (var i=0,len=this.scale2.labels.length; i<len; ++i) {
|
1621
|
-
RG.text2(this, {
|
1622
|
-
'font': font,
|
1623
|
-
'size': text_size,
|
1624
|
-
'x': xpos + offsetx,
|
1625
|
-
'y': this.gutterTop + ((i/this.scale2.labels.length) * this.grapharea) + offsety,
|
1626
|
-
'valign': 'center',
|
1627
|
-
'halign':align,
|
1628
|
-
'bounding': bounding,
|
1629
|
-
'boundingFill': bgcolor,
|
1630
|
-
'text': this.scale2.labels[this.scale2.labels.length - (i + 1)],
|
1631
|
-
'tag': 'scale'
|
1632
|
-
});
|
1633
|
-
}
|
1634
|
-
}
|
1635
|
-
|
1636
|
-
// Draw the lower limit if chart.ymin is specified
|
1637
|
-
if ( (prop['chart.ymin']!= 0 && !prop['chart.scale.invert'] || prop['chart.scale.zerostart'])
|
1638
|
-
|| prop['chart.noxaxis']
|
1639
|
-
) {
|
1640
|
-
|
1641
|
-
RG.text2(this, {
|
1642
|
-
'font':font,
|
1643
|
-
'size':text_size,
|
1644
|
-
'x':xpos + offsetx,
|
1645
|
-
'y':prop['chart.scale.invert'] ? this.gutterTop + offsety : ca.height - this.gutterBottom + offsety,
|
1646
|
-
'text':RG.number_format(this, prop['chart.ymin'].toFixed(prop['chart.scale.decimals']), units_pre, units_post),
|
1647
|
-
'valign':'center',
|
1648
|
-
'halign':align,
|
1649
|
-
'bounding':bounding,
|
1650
|
-
'boundingFill':bgcolor,
|
1651
|
-
'tag': 'scale'
|
1652
|
-
});
|
1653
|
-
|
1654
|
-
}
|
1655
|
-
}
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
// No X axis - so draw 0 - but not if the X axis is in the center
|
1664
|
-
if ( prop['chart.noxaxis'] == true
|
1665
|
-
&& prop['chart.ymin'] == null
|
1666
|
-
&& prop['chart.xaxispos'] != 'center'
|
1667
|
-
&& prop['chart.noendytick'] == false
|
1668
|
-
) {
|
1669
|
-
|
1670
|
-
RG.text2(this, {
|
1671
|
-
'font':font,
|
1672
|
-
'size':text_size,
|
1673
|
-
'x':xpos + offsetx,
|
1674
|
-
'y':prop['chart.xaxispos'] == 'top' ? this.gutterTop + offsety : (ca.height - this.gutterBottom),'text': prop['chart.units.pre'] + Number(0).toFixed(prop['chart.scale.decimals']) + prop['chart.units.post'] + offsety,
|
1675
|
-
'valign':'center',
|
1676
|
-
'halign':align,
|
1677
|
-
'bounding':bounding,
|
1678
|
-
'boundingFill':bgcolor,
|
1679
|
-
'tag':'scale'
|
1680
|
-
});
|
1681
|
-
}
|
1682
|
-
|
1683
|
-
} else if (prop['chart.ylabels'] && typeof(prop['chart.ylabels.specific']) == 'object') {
|
1684
|
-
|
1685
|
-
// A few things
|
1686
|
-
var gap = this.grapharea / prop['chart.ylabels.specific'].length;
|
1687
|
-
var halign = prop['chart.yaxispos'] == 'left' ? 'right' : 'left';
|
1688
|
-
var bounding = false;
|
1689
|
-
var bgcolor = null;
|
1690
|
-
var ymin = prop['chart.ymin'] != null && prop['chart.ymin'];
|
1691
|
-
|
1692
|
-
// Figure out the X coord based on the position of the axis
|
1693
|
-
if (prop['chart.yaxispos'] == 'left') {
|
1694
|
-
var x = this.gutterLeft - 5;
|
1695
|
-
|
1696
|
-
if (prop['chart.ylabels.inside']) {
|
1697
|
-
x += 10;
|
1698
|
-
halign = 'left';
|
1699
|
-
bounding = true;
|
1700
|
-
bgcolor = 'rgba(255,255,255,0.5)';
|
1701
|
-
}
|
1702
|
-
|
1703
|
-
} else if (prop['chart.yaxispos'] == 'right') {
|
1704
|
-
var x = ca.width - this.gutterRight + 5;
|
1705
|
-
|
1706
|
-
if (prop['chart.ylabels.inside']) {
|
1707
|
-
x -= 10;
|
1708
|
-
halign = 'right';
|
1709
|
-
bounding = true;
|
1710
|
-
bgcolor = 'rgba(255,255,255,0.5)';
|
1711
|
-
}
|
1712
|
-
}
|
1713
|
-
|
1714
|
-
var offsetx = prop['chart.ylabels.offsetx'];
|
1715
|
-
var offsety = prop['chart.ylabels.offsety'];
|
1716
|
-
|
1717
|
-
// Draw the labels
|
1718
|
-
if (prop['chart.xaxispos'] == 'center') {
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
// Draw the top halfs labels
|
1723
|
-
for (var i=0; i<prop['chart.ylabels.specific'].length; ++i) {
|
1724
|
-
|
1725
|
-
var y = this.gutterTop + (this.grapharea / (((prop['chart.ylabels.specific'].length - 1)) * 2) * i);
|
1726
|
-
|
1727
|
-
if (ymin && ymin > 0) {
|
1728
|
-
var y = ((this.grapharea / 2) / (prop['chart.ylabels.specific'].length - (ymin ? 1 : 0)) ) * i;
|
1729
|
-
y += this.gutterTop;
|
1730
|
-
}
|
1731
|
-
|
1732
|
-
RG.text2(this, {
|
1733
|
-
'font':font,
|
1734
|
-
'size':text_size,
|
1735
|
-
'x':x + offsetx,
|
1736
|
-
'y':y + offsety,
|
1737
|
-
'text':String(prop['chart.ylabels.specific'][i]),
|
1738
|
-
'valign': 'center',
|
1739
|
-
'halign':halign,
|
1740
|
-
'bounding':bounding,
|
1741
|
-
'boundingFill':bgcolor,
|
1742
|
-
'tag': 'ylabels.specific'
|
1743
|
-
});
|
1744
|
-
}
|
1745
|
-
|
1746
|
-
// Now reverse the labels and draw the bottom half
|
1747
|
-
var reversed_labels = RG.array_reverse(prop['chart.ylabels.specific']);
|
1748
|
-
|
1749
|
-
// Draw the bottom halfs labels
|
1750
|
-
for (var i=0; i<reversed_labels.length; ++i) {
|
1751
|
-
|
1752
|
-
var y = (this.grapharea / 2) + this.gutterTop + ((this.grapharea / ((reversed_labels.length - 1) * 2) ) * i);
|
1753
|
-
|
1754
|
-
RG.text2(this, {
|
1755
|
-
'font':font,
|
1756
|
-
'size':text_size,
|
1757
|
-
'x':x + offsetx,
|
1758
|
-
'y':y + offsety,
|
1759
|
-
'text':i == 0 ? '' : String(reversed_labels[i]),
|
1760
|
-
'valign': 'center',
|
1761
|
-
'halign':halign,
|
1762
|
-
'bounding':bounding,
|
1763
|
-
'boundingFill':bgcolor,
|
1764
|
-
'tag': 'ylabels.specific'
|
1765
|
-
});
|
1766
|
-
}
|
1767
|
-
|
1768
|
-
} else if (prop['chart.xaxispos'] == 'top') {
|
1769
|
-
|
1770
|
-
// Reverse the labels and draw
|
1771
|
-
var reversed_labels = RG.array_reverse(prop['chart.ylabels.specific']);
|
1772
|
-
|
1773
|
-
// Draw the bottom halfs labels
|
1774
|
-
for (var i=0; i<reversed_labels.length; ++i) {
|
1775
|
-
|
1776
|
-
var y = (this.grapharea / (reversed_labels.length - 1)) * i;
|
1777
|
-
y = y + this.gutterTop;
|
1778
|
-
|
1779
|
-
RG.Text2(this, {
|
1780
|
-
'font':font,
|
1781
|
-
'size':text_size,
|
1782
|
-
'x':x + offsetx,
|
1783
|
-
'y':y + offsety,
|
1784
|
-
'text':String(reversed_labels[i]),
|
1785
|
-
'valign': 'center',
|
1786
|
-
'halign':halign,
|
1787
|
-
'bounding':bounding,
|
1788
|
-
'boundingFill':bgcolor,
|
1789
|
-
'tag': 'ylabels.specific'
|
1790
|
-
});
|
1791
|
-
}
|
1792
|
-
|
1793
|
-
} else {
|
1794
|
-
for (var i=0; i<prop['chart.ylabels.specific'].length; ++i) {
|
1795
|
-
var y = this.gutterTop + ((this.grapharea / (prop['chart.ylabels.specific'].length - 1)) * i);
|
1796
|
-
RG.text2(this, {
|
1797
|
-
'font':font,
|
1798
|
-
'size':text_size,
|
1799
|
-
'x':x + offsetx,
|
1800
|
-
'y':y + offsety,
|
1801
|
-
'text':String(prop['chart.ylabels.specific'][i]),
|
1802
|
-
'valign':'center',
|
1803
|
-
'halign':halign,
|
1804
|
-
'bounding':bounding,
|
1805
|
-
'boundingFill':bgcolor,
|
1806
|
-
'tag': 'ylabels.specific'
|
1807
|
-
});
|
1808
|
-
}
|
1809
|
-
}
|
1810
|
-
}
|
1811
|
-
|
1812
|
-
// Draw the X axis labels
|
1813
|
-
if (prop['chart.labels'] && prop['chart.labels'].length > 0) {
|
1814
|
-
|
1815
|
-
var yOffset = 5,
|
1816
|
-
bordered = false,
|
1817
|
-
bgcolor = null
|
1818
|
-
|
1819
|
-
co.fillStyle = prop['chart.labels.color'] || prop['chart.text.color'];
|
1820
|
-
|
1821
|
-
/**
|
1822
|
-
* Text angle
|
1823
|
-
*/
|
1824
|
-
var angle = 0,
|
1825
|
-
valign = 'top',
|
1826
|
-
halign = 'center',
|
1827
|
-
bold = prop['chart.labels.bold']
|
1828
|
-
|
1829
|
-
if (prop['chart.xlabels.inside']) {
|
1830
|
-
yOffset = -5;
|
1831
|
-
bordered = true;
|
1832
|
-
bgcolor = prop['chart.xlabels.inside.color'];
|
1833
|
-
valign = 'bottom';
|
1834
|
-
}
|
1835
|
-
|
1836
|
-
if (prop['chart.xaxispos'] == 'top') {
|
1837
|
-
valign = 'bottom';
|
1838
|
-
yOffset += 2;
|
1839
|
-
}
|
1840
|
-
|
1841
|
-
if (typeof(prop['chart.text.angle']) == 'number' && prop['chart.text.angle'] > 0) {
|
1842
|
-
angle = -1 * prop['chart.text.angle'];
|
1843
|
-
valign = 'center';
|
1844
|
-
halign = 'right';
|
1845
|
-
yOffset = 10;
|
1846
|
-
|
1847
|
-
if (prop['chart.xaxispos'] == 'top') {
|
1848
|
-
yOffset = 10;
|
1849
|
-
}
|
1850
|
-
}
|
1851
|
-
|
1852
|
-
var numLabels = prop['chart.labels'].length,
|
1853
|
-
offsetx = prop['chart.labels.offsetx'],
|
1854
|
-
offsety = prop['chart.labels.offsety'];
|
1855
|
-
|
1856
|
-
for (i=0; i<numLabels; ++i) {
|
1857
|
-
|
1858
|
-
// Changed 8th Nov 2010 to be not reliant on the coords
|
1859
|
-
//if (this.properties['chart.labels'][i] && this.coords && this.coords[i] && this.coords[i][0]) {
|
1860
|
-
if (prop['chart.labels'][i]) {
|
1861
|
-
|
1862
|
-
var labelX = ((ca.width - this.gutterLeft - this.gutterRight - (2 * prop['chart.hmargin'])) / (numLabels - 1) ) * i;
|
1863
|
-
labelX += this.gutterLeft + prop['chart.hmargin'];
|
1864
|
-
|
1865
|
-
/**
|
1866
|
-
* Account for an unrelated number of labels
|
1867
|
-
*/
|
1868
|
-
|
1869
|
-
if (this.data.length === 0 || !this.data[0] || prop['chart.labels'].length != this.data[0].length) {
|
1870
|
-
labelX = this.gutterLeft + prop['chart.hmargin'] + ((ca.width - this.gutterLeft - this.gutterRight - (2 * prop['chart.hmargin'])) * (i / (prop['chart.labels'].length - 1)));
|
1871
|
-
}
|
1872
|
-
|
1873
|
-
// This accounts for there only being one point on the chart
|
1874
|
-
if (!labelX) {
|
1875
|
-
labelX = this.gutterLeft + prop['chart.hmargin'];
|
1876
|
-
}
|
1877
|
-
|
1878
|
-
if (prop['chart.xaxispos'] == 'top' && prop['chart.text.angle'] > 0) {
|
1879
|
-
halign = 'left';
|
1880
|
-
}
|
1881
|
-
|
1882
|
-
if (prop['chart.text.angle'] != 0) {
|
1883
|
-
halign = 'right';
|
1884
|
-
}
|
1885
|
-
|
1886
|
-
RG.Text2(this, {
|
1887
|
-
'font':font,
|
1888
|
-
'size':text_size,
|
1889
|
-
'bold': bold,
|
1890
|
-
'x':labelX + offsetx,
|
1891
|
-
'y':(prop['chart.xaxispos'] == 'top') ? this.gutterTop - yOffset - (prop['chart.xlabels.inside'] ? -22 : 0) + offsety : (ca.height - this.gutterBottom) + yOffset + offsety,
|
1892
|
-
'text':String(prop['chart.labels'][i]),
|
1893
|
-
'valign':valign,
|
1894
|
-
'halign':halign,
|
1895
|
-
'bounding':bordered,
|
1896
|
-
'boundingFill':bgcolor,
|
1897
|
-
'angle':angle,
|
1898
|
-
'tag': 'labels'
|
1899
|
-
});
|
1900
|
-
}
|
1901
|
-
}
|
1902
|
-
|
1903
|
-
}
|
1904
|
-
|
1905
|
-
co.stroke();
|
1906
|
-
co.fill();
|
1907
|
-
}
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1911
|
-
/**
|
1912
|
-
* Draws the line
|
1913
|
-
*/
|
1914
|
-
this.drawLine =
|
1915
|
-
this.DrawLine = function (lineData, color, fill, linewidth, tickmarks, index)
|
1916
|
-
{
|
1917
|
-
// This facilitates the Rise animation (the Y value only)
|
1918
|
-
if (prop['chart.animation.unfold.y'] && prop['chart.animation.factor'] != 1) {
|
1919
|
-
for (var i=0; i<lineData.length; ++i) {
|
1920
|
-
lineData[i] *= prop['chart.animation.factor'];
|
1921
|
-
}
|
1922
|
-
}
|
1923
|
-
|
1924
|
-
var penUp = false;
|
1925
|
-
var yPos = null;
|
1926
|
-
var xPos = 0;
|
1927
|
-
co.lineWidth = 1;
|
1928
|
-
var lineCoords = [];
|
1929
|
-
|
1930
|
-
/**
|
1931
|
-
* Get the previous line data
|
1932
|
-
*/
|
1933
|
-
if (index > 0) {
|
1934
|
-
var prevLineCoords = this.coords2[index - 1];
|
1935
|
-
}
|
1936
|
-
|
1937
|
-
|
1938
|
-
// Work out the X interval
|
1939
|
-
var xInterval = (ca.width - (2 * prop['chart.hmargin']) - this.gutterLeft - this.gutterRight) / (lineData.length - 1);
|
1940
|
-
|
1941
|
-
// Loop thru each value given, plotting the line
|
1942
|
-
// (FORMERLY FIRST)
|
1943
|
-
for (i=0,len=lineData.length; i<len; i+=1) {
|
1944
|
-
|
1945
|
-
var data_point = lineData[i];
|
1946
|
-
|
1947
|
-
/**
|
1948
|
-
* Get the yPos for the given data point
|
1949
|
-
*/
|
1950
|
-
var yPos = this.getYCoord(data_point);
|
1951
|
-
|
1952
|
-
|
1953
|
-
// Null data points, and a special case for this bug:http://dev.rgraph.net/tests/ymin.html
|
1954
|
-
if ( lineData[i] == null
|
1955
|
-
|| (prop['chart.xaxispos'] == 'bottom' && lineData[i] < this.min && !prop['chart.outofbounds'])
|
1956
|
-
|| (prop['chart.xaxispos'] == 'center' && lineData[i] < (-1 * this.max) && !prop['chart.outofbounds'])
|
1957
|
-
|| (((lineData[i] < this.min && prop['chart.xaxispos'] !== 'center') || lineData[i] > this.max) && !prop['chart.outofbounds'])) {
|
1958
|
-
|
1959
|
-
yPos = null;
|
1960
|
-
}
|
1961
|
-
|
1962
|
-
// Not always very noticeable, but it does have an effect
|
1963
|
-
// with thick lines
|
1964
|
-
co.lineCap = 'round';
|
1965
|
-
co.lineJoin = 'round';
|
1966
|
-
|
1967
|
-
// Plot the line if we're at least on the second iteration
|
1968
|
-
if (i > 0) {
|
1969
|
-
xPos = xPos + xInterval;
|
1970
|
-
} else {
|
1971
|
-
xPos = prop['chart.hmargin'] + this.gutterLeft;
|
1972
|
-
}
|
1973
|
-
|
1974
|
-
if (prop['chart.animation.unfold.x']) {
|
1975
|
-
xPos *= prop['chart.animation.factor'];
|
1976
|
-
|
1977
|
-
if (xPos < prop['chart.gutter.left']) {
|
1978
|
-
xPos = prop['chart.gutter.left'];
|
1979
|
-
}
|
1980
|
-
}
|
1981
|
-
|
1982
|
-
/**
|
1983
|
-
* Add the coords to an array
|
1984
|
-
*/
|
1985
|
-
this.coords.push([xPos, yPos]);
|
1986
|
-
lineCoords.push([xPos, yPos]);
|
1987
|
-
}
|
1988
|
-
|
1989
|
-
co.stroke();
|
1990
|
-
|
1991
|
-
// Store the coords in another format, indexed by line number
|
1992
|
-
this.coords2[index] = lineCoords;
|
1993
|
-
|
1994
|
-
/**
|
1995
|
-
* For IE only: Draw the shadow ourselves as ExCanvas doesn't produce shadows
|
1996
|
-
*/
|
1997
|
-
if (RG.ISOLD && prop['chart.shadow']) {
|
1998
|
-
this.DrawIEShadow(lineCoords, co.shadowColor);
|
1999
|
-
}
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
/**
|
2004
|
-
* Now draw the actual line [FORMERLY SECOND]
|
2005
|
-
*/
|
2006
|
-
co.beginPath();
|
2007
|
-
// Transparent now as of 11/19/2011
|
2008
|
-
co.strokeStyle = 'rgba(0,0,0,0)';
|
2009
|
-
//co.strokeStyle = fill;
|
2010
|
-
if (fill) {
|
2011
|
-
co.fillStyle = fill;
|
2012
|
-
}
|
2013
|
-
|
2014
|
-
var isStepped = prop['chart.stepped'];
|
2015
|
-
var isFilled = prop['chart.filled'];
|
2016
|
-
|
2017
|
-
if (prop['chart.xaxispos'] == 'top') {
|
2018
|
-
var xAxisPos = this.gutterTop;
|
2019
|
-
} else if (prop['chart.xaxispos'] == 'center') {
|
2020
|
-
var xAxisPos = this.gutterTop + (this.grapharea / 2);
|
2021
|
-
} else if (prop['chart.xaxispos'] == 'bottom') {
|
2022
|
-
var xAxisPos = ca.height - this.gutterBottom;
|
2023
|
-
}
|
2024
|
-
|
2025
|
-
|
2026
|
-
|
2027
|
-
|
2028
|
-
for (var i=0,len=lineCoords.length; i<len; i+=1) {
|
2029
|
-
|
2030
|
-
xPos = lineCoords[i][0];
|
2031
|
-
yPos = lineCoords[i][1];
|
2032
|
-
var set = index;
|
2033
|
-
|
2034
|
-
var prevY = (lineCoords[i - 1] ? lineCoords[i - 1][1] : null);
|
2035
|
-
var isLast = (i + 1) == lineCoords.length;
|
2036
|
-
|
2037
|
-
/**
|
2038
|
-
* This nullifys values which are out-of-range
|
2039
|
-
*/
|
2040
|
-
if (!prop['chart.outofbounds'] && (prevY < this.gutterTop || prevY > (ca.height - this.gutterBottom) ) ) {
|
2041
|
-
penUp = true;
|
2042
|
-
}
|
2043
|
-
|
2044
|
-
if (i == 0 || penUp || !yPos || !prevY || prevY < this.gutterTop) {
|
2045
|
-
|
2046
|
-
if (prop['chart.filled'] && !prop['chart.filled.range']) {
|
2047
|
-
|
2048
|
-
if (!prop['chart.outofbounds'] || prevY === null || yPos === null) {
|
2049
|
-
co.moveTo(xPos + 1, xAxisPos);
|
2050
|
-
}
|
2051
|
-
|
2052
|
-
// This facilitates the X axis being at the top
|
2053
|
-
// NOTE: Also done below
|
2054
|
-
if (prop['chart.xaxispos'] == 'top') {
|
2055
|
-
co.moveTo(xPos + 1, xAxisPos);
|
2056
|
-
}
|
2057
|
-
|
2058
|
-
if (isStepped && i > 0) {
|
2059
|
-
co.lineTo(xPos, lineCoords[i - 1][1]);
|
2060
|
-
}
|
2061
|
-
|
2062
|
-
co.lineTo(xPos, yPos);
|
2063
|
-
|
2064
|
-
} else {
|
2065
|
-
|
2066
|
-
if (RG.ISOLD && yPos == null) {
|
2067
|
-
// Nada
|
2068
|
-
} else {
|
2069
|
-
co.moveTo(xPos + 1, yPos);
|
2070
|
-
}
|
2071
|
-
}
|
2072
|
-
|
2073
|
-
if (yPos == null) {
|
2074
|
-
penUp = true;
|
2075
|
-
|
2076
|
-
} else {
|
2077
|
-
penUp = false;
|
2078
|
-
}
|
2079
|
-
|
2080
|
-
} else {
|
2081
|
-
|
2082
|
-
// Draw the stepped part of stepped lines
|
2083
|
-
if (isStepped) {
|
2084
|
-
co.lineTo(xPos, lineCoords[i - 1][1]);
|
2085
|
-
}
|
2086
|
-
|
2087
|
-
if ((yPos >= this.gutterTop && yPos <= (ca.height - this.gutterBottom)) || prop['chart.outofbounds'] ) {
|
2088
|
-
|
2089
|
-
if (isLast && prop['chart.filled'] && !prop['chart.filled.range'] && prop['chart.yaxispos'] == 'right') {
|
2090
|
-
xPos -= 1;
|
2091
|
-
}
|
2092
|
-
|
2093
|
-
|
2094
|
-
// Added 8th September 2009
|
2095
|
-
if (!isStepped || !isLast) {
|
2096
|
-
co.lineTo(xPos, yPos);
|
2097
|
-
|
2098
|
-
if (isFilled && lineCoords[i+1] && lineCoords[i+1][1] == null) {
|
2099
|
-
co.lineTo(xPos, xAxisPos);
|
2100
|
-
}
|
2101
|
-
|
2102
|
-
// Added August 2010
|
2103
|
-
} else if (isStepped && isLast) {
|
2104
|
-
co.lineTo(xPos,yPos);
|
2105
|
-
}
|
2106
|
-
|
2107
|
-
|
2108
|
-
penUp = false;
|
2109
|
-
} else {
|
2110
|
-
penUp = true;
|
2111
|
-
}
|
2112
|
-
}
|
2113
|
-
}
|
2114
|
-
|
2115
|
-
/**
|
2116
|
-
* Draw a line to the X axis if the chart is filled
|
2117
|
-
*/
|
2118
|
-
if (prop['chart.filled'] && !prop['chart.filled.range'] && !prop['chart.curvy']) {
|
2119
|
-
|
2120
|
-
// Is this needed ??
|
2121
|
-
var fillStyle = prop['chart.fillstyle'];
|
2122
|
-
|
2123
|
-
/**
|
2124
|
-
* Draw the bottom edge of the filled bit using either the X axis or the prevlinedata,
|
2125
|
-
* depending on the index of the line. The first line uses the X axis, and subsequent
|
2126
|
-
* lines use the prevLineCoords array
|
2127
|
-
*/
|
2128
|
-
if (index > 0 && prop['chart.filled.accumulative']) {
|
2129
|
-
|
2130
|
-
co.lineTo(xPos, prevLineCoords ? prevLineCoords[i - 1][1] : (ca.height - this.gutterBottom - 1 + (prop['chart.xaxispos'] == 'center' ? (ca.height - this.gutterTop - this.gutterBottom) / 2 : 0)));
|
2131
|
-
|
2132
|
-
for (var k=(i - 1); k>=0; --k) {
|
2133
|
-
co.lineTo(k == 0 ? prevLineCoords[k][0] + 1: prevLineCoords[k][0], prevLineCoords[k][1]);
|
2134
|
-
}
|
2135
|
-
} else {
|
2136
|
-
|
2137
|
-
// Draw a line down to the X axis
|
2138
|
-
if (prop['chart.xaxispos'] == 'top') {
|
2139
|
-
co.lineTo(xPos, prop['chart.gutter.top'] + 1);
|
2140
|
-
co.lineTo(lineCoords[0][0],prop['chart.gutter.top'] + 1);
|
2141
|
-
} else if (typeof(lineCoords[i - 1][1]) == 'number') {
|
2142
|
-
|
2143
|
-
var yPosition = prop['chart.xaxispos'] == 'center' ? ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop : this.getYCoord(0);//ca.height - this.gutterBottom;
|
2144
|
-
|
2145
|
-
co.lineTo(xPos,yPosition);
|
2146
|
-
co.lineTo(lineCoords[0][0],yPosition);
|
2147
|
-
}
|
2148
|
-
}
|
2149
|
-
|
2150
|
-
co.fillStyle = !this.hidden(index) ? fill : 'rgba(0,0,0,0)';
|
2151
|
-
|
2152
|
-
co.fill();
|
2153
|
-
co.beginPath();
|
2154
|
-
|
2155
|
-
}
|
2156
|
-
|
2157
|
-
/**
|
2158
|
-
* FIXME this may need removing when Chrome is fixed
|
2159
|
-
* SEARCH TAGS: CHROME SHADOW BUG
|
2160
|
-
*/
|
2161
|
-
//if (false && RGraph.ISCHROME && prop['chart.shadow'] && prop['chart.chromefix'] && prop['chart.shadow.blur'] > 0) {
|
2162
|
-
//
|
2163
|
-
// for (var i=lineCoords.length - 1; i>=0; --i) {
|
2164
|
-
// if (
|
2165
|
-
// typeof(lineCoords[i][1]) != 'number'
|
2166
|
-
// || (typeof(lineCoords[i+1]) == 'object' && typeof(lineCoords[i+1][1]) != 'number')
|
2167
|
-
// ) {
|
2168
|
-
// co.moveTo(lineCoords[i][0],lineCoords[i][1]);
|
2169
|
-
// } else {
|
2170
|
-
// co.lineTo(lineCoords[i][0],lineCoords[i][1]);
|
2171
|
-
// }
|
2172
|
-
// }
|
2173
|
-
//}
|
2174
|
-
|
2175
|
-
co.stroke();
|
2176
|
-
|
2177
|
-
|
2178
|
-
if (prop['chart.backdrop']) {
|
2179
|
-
this.DrawBackdrop(lineCoords, color);
|
2180
|
-
}
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
/**
|
2186
|
-
* TODO CLIP TRACE
|
2187
|
-
* By using the clip() method the Trace animation can be updated.
|
2188
|
-
* NOTE: Needs to be done for the filled part as well
|
2189
|
-
*/
|
2190
|
-
co.save();
|
2191
|
-
co.beginPath();
|
2192
|
-
co.rect(0,0,ca.width * prop['chart.animation.trace.clip'],ca.height);
|
2193
|
-
co.clip();
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
|
2199
|
-
//
|
2200
|
-
// Draw errorbars
|
2201
|
-
//
|
2202
|
-
if (typeof prop['chart.errorbars'] !== 'null') {
|
2203
|
-
this.drawErrorbars();
|
2204
|
-
}
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
// Now redraw the lines with the correct line width
|
2210
|
-
this.SetShadow(index);
|
2211
|
-
this.RedrawLine(lineCoords, color, linewidth, index);
|
2212
|
-
co.stroke();
|
2213
|
-
RG.NoShadow(this);
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
// Draw the tickmarks
|
2222
|
-
for (var i=0; i<lineCoords.length; ++i) {
|
2223
|
-
|
2224
|
-
i = Number(i);
|
2225
|
-
|
2226
|
-
/**
|
2227
|
-
* Set the color
|
2228
|
-
*/
|
2229
|
-
co.strokeStyle = color;
|
2230
|
-
|
2231
|
-
|
2232
|
-
if (isStepped && i == (lineCoords.length - 1)) {
|
2233
|
-
co.beginPath();
|
2234
|
-
//continue;
|
2235
|
-
}
|
2236
|
-
|
2237
|
-
if (
|
2238
|
-
(
|
2239
|
-
tickmarks != 'endcircle'
|
2240
|
-
&& tickmarks != 'endsquare'
|
2241
|
-
&& tickmarks != 'filledendsquare'
|
2242
|
-
&& tickmarks != 'endtick'
|
2243
|
-
&& tickmarks != 'endtriangle'
|
2244
|
-
&& tickmarks != 'arrow'
|
2245
|
-
&& tickmarks != 'filledarrow'
|
2246
|
-
)
|
2247
|
-
|| (i == 0 && tickmarks != 'arrow' && tickmarks != 'filledarrow')
|
2248
|
-
|| i == (lineCoords.length - 1)
|
2249
|
-
) {
|
2250
|
-
|
2251
|
-
var prevX = (i <= 0 ? null : lineCoords[i - 1][0]);
|
2252
|
-
var prevY = (i <= 0 ? null : lineCoords[i - 1][1]);
|
2253
|
-
|
2254
|
-
this.DrawTick(
|
2255
|
-
lineData,
|
2256
|
-
lineCoords[i][0],
|
2257
|
-
lineCoords[i][1],
|
2258
|
-
color,
|
2259
|
-
false,
|
2260
|
-
prevX,
|
2261
|
-
prevY,
|
2262
|
-
tickmarks,
|
2263
|
-
i,
|
2264
|
-
index
|
2265
|
-
);
|
2266
|
-
|
2267
|
-
// Draws tickmarks on the stepped bits of stepped charts. Takend out 14th July 2010
|
2268
|
-
//
|
2269
|
-
//if (this.properties['chart.stepped'] && lineCoords[i + 1] && this.properties['chart.tickmarks'] != 'endsquare' && this.properties['chart.tickmarks'] != 'endcircle' && this.properties['chart.tickmarks'] != 'endtick') {
|
2270
|
-
// this.DrawTick(lineCoords[i + 1][0], lineCoords[i][1], color);
|
2271
|
-
//}
|
2272
|
-
}
|
2273
|
-
}
|
2274
|
-
|
2275
|
-
co.restore();
|
2276
|
-
|
2277
|
-
// Draw something off canvas to skirt an annoying bug
|
2278
|
-
co.beginPath();
|
2279
|
-
co.arc(ca.width + 50000, ca.height + 50000, 2, 0, 6.38, 1);
|
2280
|
-
};
|
2281
|
-
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
/**
|
2286
|
-
* This functions draws a tick mark on the line
|
2287
|
-
*/
|
2288
|
-
this.drawTick =
|
2289
|
-
this.DrawTick = function (lineData, xPos, yPos, color, isShadow, prevX, prevY, tickmarks, index, dataset)
|
2290
|
-
{
|
2291
|
-
// Various conditions mean no tick
|
2292
|
-
if (this.hidden(dataset)) {
|
2293
|
-
return;
|
2294
|
-
} else if (RG.is_null(yPos)) {
|
2295
|
-
return false;
|
2296
|
-
} else if ((yPos > (ca.height - this.gutterBottom)) && !prop['chart.outofbounds']) {
|
2297
|
-
return;
|
2298
|
-
} else if ((yPos < this.gutterTop) && !prop['chart.outofbounds']) {
|
2299
|
-
return;
|
2300
|
-
}
|
2301
|
-
|
2302
|
-
co.beginPath();
|
2303
|
-
|
2304
|
-
var offset = 0;
|
2305
|
-
|
2306
|
-
// Reset the stroke and lineWidth back to the same as what they were when the line was drawm
|
2307
|
-
// UPDATE 28th July 2011 - the line width is now set to 1
|
2308
|
-
co.lineWidth = prop['chart.tickmarks.linewidth'] ? prop['chart.tickmarks.linewidth'] : prop['chart.linewidth'];
|
2309
|
-
co.strokeStyle = isShadow ? prop['chart.shadow.color'] : co.strokeStyle;
|
2310
|
-
co.fillStyle = isShadow ? prop['chart.shadow.color'] : co.strokeStyle;
|
2311
|
-
|
2312
|
-
// Cicular tick marks
|
2313
|
-
if ( tickmarks == 'circle'
|
2314
|
-
|| tickmarks == 'filledcircle'
|
2315
|
-
|| tickmarks == 'endcircle') {
|
2316
|
-
|
2317
|
-
if (tickmarks == 'circle'|| tickmarks == 'filledcircle' || (tickmarks == 'endcircle' && (index == 0 || index == (lineData.length - 1)))) {
|
2318
|
-
co.beginPath();
|
2319
|
-
co.arc(xPos + offset, yPos + offset, prop['chart.ticksize'], 0, 360 / (180 / RG.PI), false);
|
2320
|
-
|
2321
|
-
if (tickmarks == 'filledcircle') {
|
2322
|
-
co.fillStyle = isShadow ? prop['chart.shadow.color'] : co.strokeStyle;
|
2323
|
-
} else {
|
2324
|
-
co.fillStyle = isShadow ? prop['chart.shadow.color'] : 'white';
|
2325
|
-
}
|
2326
|
-
|
2327
|
-
co.stroke();
|
2328
|
-
co.fill();
|
2329
|
-
}
|
2330
|
-
|
2331
|
-
// Halfheight "Line" style tick marks
|
2332
|
-
} else if (tickmarks == 'halftick') {
|
2333
|
-
co.beginPath();
|
2334
|
-
co.moveTo(Math.round(xPos), yPos);
|
2335
|
-
co.lineTo(Math.round(xPos), yPos + prop['chart.ticksize']);
|
2336
|
-
|
2337
|
-
co.stroke();
|
2338
|
-
|
2339
|
-
// Tick style tickmarks
|
2340
|
-
} else if (tickmarks == 'tick') {
|
2341
|
-
co.beginPath();
|
2342
|
-
co.moveTo(Math.round(xPos), yPos - prop['chart.ticksize']);
|
2343
|
-
co.lineTo(Math.round(xPos), yPos + prop['chart.ticksize']);
|
2344
|
-
|
2345
|
-
co.stroke();
|
2346
|
-
|
2347
|
-
// Endtick style tickmarks
|
2348
|
-
} else if (tickmarks == 'endtick' && (index == 0 || index == (lineData.length - 1))) {
|
2349
|
-
co.beginPath();
|
2350
|
-
co.moveTo(Math.round(xPos), yPos - prop['chart.ticksize']);
|
2351
|
-
co.lineTo(Math.round(xPos), yPos + prop['chart.ticksize']);
|
2352
|
-
|
2353
|
-
co.stroke();
|
2354
|
-
|
2355
|
-
// "Cross" style tick marks
|
2356
|
-
} else if (tickmarks == 'cross') {
|
2357
|
-
co.beginPath();
|
2358
|
-
|
2359
|
-
var ticksize = prop['chart.ticksize'];
|
2360
|
-
|
2361
|
-
co.moveTo(xPos - ticksize, yPos - ticksize);
|
2362
|
-
co.lineTo(xPos + ticksize, yPos + ticksize);
|
2363
|
-
co.moveTo(xPos + ticksize, yPos - ticksize);
|
2364
|
-
co.lineTo(xPos - ticksize, yPos + ticksize);
|
2365
|
-
co.stroke();
|
2366
|
-
|
2367
|
-
|
2368
|
-
// Triangle style tick marks
|
2369
|
-
} else if (tickmarks == 'triangle' || tickmarks == 'filledtriangle' || (tickmarks == 'endtriangle' && (index == 0 || index == (lineData.length - 1)))) {
|
2370
|
-
co.beginPath();
|
2371
|
-
|
2372
|
-
if (tickmarks == 'filledtriangle') {
|
2373
|
-
co.fillStyle = isShadow ? prop['chart.shadow.color'] : co.strokeStyle;
|
2374
|
-
} else {
|
2375
|
-
co.fillStyle = 'white';
|
2376
|
-
}
|
2377
|
-
|
2378
|
-
co.moveTo(ma.round(xPos - prop['chart.ticksize']), yPos + prop['chart.ticksize']);
|
2379
|
-
co.lineTo(ma.round(xPos), yPos - prop['chart.ticksize']);
|
2380
|
-
co.lineTo(ma.round(xPos + prop['chart.ticksize']), yPos + prop['chart.ticksize']);
|
2381
|
-
co.closePath();
|
2382
|
-
|
2383
|
-
co.stroke();
|
2384
|
-
co.fill();
|
2385
|
-
|
2386
|
-
|
2387
|
-
//
|
2388
|
-
// A white bordered circle
|
2389
|
-
//
|
2390
|
-
} else if (tickmarks == 'borderedcircle' || tickmarks == 'dot') {
|
2391
|
-
|
2392
|
-
co.lineWidth = prop['chart.tickmarks.dot.linewidth'] || 0.00000001;
|
2393
|
-
|
2394
|
-
pa2(co, [
|
2395
|
-
'b',
|
2396
|
-
'a',xPos, yPos, prop['chart.ticksize'], 0, 360 / (180 / RG.PI), false,
|
2397
|
-
'c',
|
2398
|
-
'f',prop['chart.tickmarks.dot.fill'] || color,
|
2399
|
-
's',prop['chart.tickmarks.dot.stroke'] || color
|
2400
|
-
]);
|
2401
|
-
|
2402
|
-
} else if ( tickmarks == 'square'
|
2403
|
-
|| tickmarks == 'filledsquare'
|
2404
|
-
|| (tickmarks == 'endsquare' && (index == 0 || index == (lineData.length - 1)))
|
2405
|
-
|| (tickmarks == 'filledendsquare' && (index == 0 || index == (lineData.length - 1))) ) {
|
2406
|
-
|
2407
|
-
co.fillStyle = 'white';
|
2408
|
-
co.strokeStyle = co.strokeStyle;
|
2409
|
-
|
2410
|
-
co.beginPath();
|
2411
|
-
co.rect(Math.round(xPos - prop['chart.ticksize']), Math.round(yPos - prop['chart.ticksize']), prop['chart.ticksize'] * 2, prop['chart.ticksize'] * 2);
|
2412
|
-
|
2413
|
-
// Fillrect
|
2414
|
-
if (tickmarks == 'filledsquare' || tickmarks == 'filledendsquare') {
|
2415
|
-
co.fillStyle = isShadow ? prop['chart.shadow.color'] : co.strokeStyle;
|
2416
|
-
co.rect(Math.round(xPos - prop['chart.ticksize']), Math.round(yPos - prop['chart.ticksize']), prop['chart.ticksize'] * 2, prop['chart.ticksize'] * 2);
|
2417
|
-
|
2418
|
-
} else if (tickmarks == 'square' || tickmarks == 'endsquare') {
|
2419
|
-
co.fillStyle = isShadow ? prop['chart.shadow.color'] : 'white';
|
2420
|
-
co.rect(Math.round((xPos - prop['chart.ticksize']) + 1), Math.round((yPos - prop['chart.ticksize']) + 1), (prop['chart.ticksize'] * 2) - 2, (prop['chart.ticksize'] * 2) - 2);
|
2421
|
-
}
|
2422
|
-
|
2423
|
-
co.stroke();
|
2424
|
-
co.fill();
|
2425
|
-
|
2426
|
-
/**
|
2427
|
-
* FILLED arrowhead
|
2428
|
-
*/
|
2429
|
-
} else if (tickmarks == 'filledarrow') {
|
2430
|
-
|
2431
|
-
var x = Math.abs(xPos - prevX);
|
2432
|
-
var y = Math.abs(yPos - prevY);
|
2433
|
-
|
2434
|
-
if (yPos < prevY) {
|
2435
|
-
var a = Math.atan(x / y) + 1.57;
|
2436
|
-
} else {
|
2437
|
-
var a = Math.atan(y / x) + 3.14;
|
2438
|
-
}
|
2439
|
-
|
2440
|
-
co.beginPath();
|
2441
|
-
co.moveTo(Math.round(xPos), Math.round(yPos));
|
2442
|
-
co.arc(Math.round(xPos), Math.round(yPos), 7, a - 0.5, a + 0.5, false);
|
2443
|
-
co.closePath();
|
2444
|
-
|
2445
|
-
co.stroke();
|
2446
|
-
co.fill();
|
2447
|
-
|
2448
|
-
/**
|
2449
|
-
* Arrow head, NOT filled
|
2450
|
-
*/
|
2451
|
-
} else if (tickmarks == 'arrow') {
|
2452
|
-
|
2453
|
-
var orig_linewidth = co.lineWidth;
|
2454
|
-
|
2455
|
-
var x = Math.abs(xPos - prevX);
|
2456
|
-
var y = Math.abs(yPos - prevY);
|
2457
|
-
|
2458
|
-
co.lineWidth;
|
2459
|
-
|
2460
|
-
if (yPos < prevY) {
|
2461
|
-
var a = Math.atan(x / y) + 1.57;
|
2462
|
-
} else {
|
2463
|
-
var a = Math.atan(y / x) + 3.14;
|
2464
|
-
}
|
2465
|
-
|
2466
|
-
co.beginPath();
|
2467
|
-
co.moveTo(Math.round(xPos), Math.round(yPos));
|
2468
|
-
co.arc(Math.round(xPos), Math.round(yPos), 7, a - 0.5 - (doc.all ? 0.1 : 0.01), a - 0.4, false);
|
2469
|
-
|
2470
|
-
co.moveTo(Math.round(xPos), Math.round(yPos));
|
2471
|
-
co.arc(Math.round(xPos), Math.round(yPos), 7, a + 0.5 + (doc.all ? 0.1 : 0.01), a + 0.5, true);
|
2472
|
-
co.stroke();
|
2473
|
-
co.fill();
|
2474
|
-
|
2475
|
-
// Revert to original lineWidth
|
2476
|
-
co.lineWidth = orig_linewidth;
|
2477
|
-
|
2478
|
-
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2485
|
-
|
2486
|
-
|
2487
|
-
|
2488
|
-
|
2489
|
-
|
2490
|
-
|
2491
|
-
|
2492
|
-
/**
|
2493
|
-
* Image based tickmark
|
2494
|
-
*/
|
2495
|
-
// lineData, xPos, yPos, color, isShadow, prevX, prevY, tickmarks, index
|
2496
|
-
} else if (
|
2497
|
-
typeof tickmarks === 'string' &&
|
2498
|
-
(
|
2499
|
-
tickmarks.substr(0, 6) === 'image:' ||
|
2500
|
-
tickmarks.substr(0, 5) === 'data:' ||
|
2501
|
-
tickmarks.substr(0, 1) === '/' ||
|
2502
|
-
tickmarks.substr(0, 3) === '../' ||
|
2503
|
-
tickmarks.substr(0, 7) === 'images/'
|
2504
|
-
)
|
2505
|
-
) {
|
2506
|
-
|
2507
|
-
var img = new Image();
|
2508
|
-
|
2509
|
-
if (tickmarks.substr(0, 6) === 'image:') {
|
2510
|
-
img.src = tickmarks.substr(6);
|
2511
|
-
} else {
|
2512
|
-
img.src = tickmarks;
|
2513
|
-
}
|
2514
|
-
|
2515
|
-
|
2516
|
-
img.onload = function ()
|
2517
|
-
{
|
2518
|
-
if (prop['chart.tickmarks.image.halign'] === 'center') xPos -= (this.width / 2);
|
2519
|
-
if (prop['chart.tickmarks.image.halign'] === 'right') xPos -= this.width;
|
2520
|
-
|
2521
|
-
if (prop['chart.tickmarks.image.valign'] === 'center') yPos -= (this.height / 2);
|
2522
|
-
if (prop['chart.tickmarks.image.valign'] === 'bottom') yPos -= this.height;
|
2523
|
-
|
2524
|
-
xPos += prop['chart.tickmarks.image.offsetx'];
|
2525
|
-
yPos += prop['chart.tickmarks.image.offsety'];
|
2526
|
-
|
2527
|
-
co.drawImage(this, xPos, yPos);
|
2528
|
-
};
|
2529
|
-
|
2530
|
-
|
2531
|
-
|
2532
|
-
|
2533
|
-
|
2534
|
-
|
2535
|
-
|
2536
|
-
|
2537
|
-
|
2538
|
-
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
/**
|
2543
|
-
* Custom tick drawing function
|
2544
|
-
*/
|
2545
|
-
} else if (typeof(tickmarks) == 'function') {
|
2546
|
-
tickmarks(this, lineData, lineData[index], index, xPos, yPos, color, prevX, prevY);
|
2547
|
-
}
|
2548
|
-
};
|
2549
|
-
|
2550
|
-
|
2551
|
-
|
2552
|
-
|
2553
|
-
/**
|
2554
|
-
* Draws a filled range if necessary
|
2555
|
-
*/
|
2556
|
-
this.drawRange =
|
2557
|
-
this.DrawRange = function ()
|
2558
|
-
{
|
2559
|
-
/**
|
2560
|
-
* Fill the range if necessary
|
2561
|
-
*/
|
2562
|
-
if (prop['chart.filled.range'] && prop['chart.filled']) {
|
2563
|
-
|
2564
|
-
if (RG.isNull(prop['chart.filled.range.threshold'])) {
|
2565
|
-
prop['chart.filled.range.threshold'] = this.ymin
|
2566
|
-
prop['chart.filled.range.threshold.colors'] = [prop['chart.fillstyle'], prop['chart.fillstyle']]
|
2567
|
-
}
|
2568
|
-
|
2569
|
-
for (var idx=0; idx<2; ++idx) {
|
2570
|
-
|
2571
|
-
var threshold_colors = prop['chart.filled.range.threshold.colors'];
|
2572
|
-
var y = this.getYCoord(prop['chart.filled.range.threshold'])
|
2573
|
-
|
2574
|
-
co.save();
|
2575
|
-
if (idx == 0) {
|
2576
|
-
co.beginPath();
|
2577
|
-
co.rect(0,0,ca.width,y);
|
2578
|
-
co.clip();
|
2579
|
-
|
2580
|
-
} else {
|
2581
|
-
|
2582
|
-
co.beginPath();
|
2583
|
-
co.rect(0,y,ca.width, ca.height);
|
2584
|
-
co.clip();
|
2585
|
-
}
|
2586
|
-
|
2587
|
-
co.beginPath();
|
2588
|
-
co.fillStyle = (idx == 1 ? prop['chart.filled.range.threshold.colors'][1] : prop['chart.filled.range.threshold.colors'][0]);
|
2589
|
-
|
2590
|
-
//co.strokeStyle = prop['chart.fillstyle']; // Strokestyle not used now (10th October 2012)
|
2591
|
-
|
2592
|
-
co.lineWidth = !this.hidden(idx) ? 1 : 0;
|
2593
|
-
var len = (this.coords.length / 2);
|
2594
|
-
|
2595
|
-
|
2596
|
-
|
2597
|
-
for (var i=0; i<len; ++i) {
|
2598
|
-
if (!RG.is_null(this.coords[i][1])) {
|
2599
|
-
if (i == 0) {
|
2600
|
-
co.moveTo(this.coords[i][0], this.coords[i][1])
|
2601
|
-
} else {
|
2602
|
-
co.lineTo(this.coords[i][0], this.coords[i][1])
|
2603
|
-
}
|
2604
|
-
}
|
2605
|
-
}
|
2606
|
-
|
2607
|
-
|
2608
|
-
for (var i=this.coords.length - 1; i>=len; --i) {
|
2609
|
-
if (RG.is_null(this.coords[i][1])) {
|
2610
|
-
co.moveTo(this.coords[i][0], this.coords[i][1])
|
2611
|
-
} else {
|
2612
|
-
co.lineTo(this.coords[i][0], this.coords[i][1])
|
2613
|
-
}
|
2614
|
-
//co.lineTo(this.coords[i][0], this.coords[i][1])
|
2615
|
-
}
|
2616
|
-
|
2617
|
-
|
2618
|
-
|
2619
|
-
// Taken out - 10th Oct 2012
|
2620
|
-
//co.stroke();
|
2621
|
-
|
2622
|
-
co.fill();
|
2623
|
-
co.restore();
|
2624
|
-
}
|
2625
|
-
}
|
2626
|
-
};
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2631
|
-
/**
|
2632
|
-
* Redraws the line with the correct line width etc
|
2633
|
-
*
|
2634
|
-
* @param array coords The coordinates of the line
|
2635
|
-
*/
|
2636
|
-
this.redrawLine =
|
2637
|
-
this.RedrawLine = function (coords, color, linewidth, index)
|
2638
|
-
{
|
2639
|
-
|
2640
|
-
if (prop['chart.noredraw'] || prop['chart.filled.range']) {
|
2641
|
-
return;
|
2642
|
-
}
|
2643
|
-
|
2644
|
-
co.strokeStyle = (typeof(color) == 'object' && color && color.toString().indexOf('CanvasGradient') == -1 ? color[0] : color);
|
2645
|
-
co.lineWidth = linewidth;
|
2646
|
-
|
2647
|
-
if (this.hidden(index)) {
|
2648
|
-
co.strokeStyle = 'rgba(0,0,0,0)';
|
2649
|
-
}
|
2650
|
-
|
2651
|
-
|
2652
|
-
|
2653
|
-
|
2654
|
-
|
2655
|
-
|
2656
|
-
|
2657
|
-
|
2658
|
-
if (!RG.ISOLD && (prop['chart.curvy'] || prop['chart.spline'])) {
|
2659
|
-
this.DrawCurvyLine(coords, this.hidden(index) ? 'rgba(0,0,0,0)' : color, linewidth, index);
|
2660
|
-
return;
|
2661
|
-
}
|
2662
|
-
|
2663
|
-
|
2664
|
-
|
2665
|
-
|
2666
|
-
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2670
|
-
co.beginPath();
|
2671
|
-
|
2672
|
-
var len = coords.length;
|
2673
|
-
var width = ca.width
|
2674
|
-
var height = ca.height;
|
2675
|
-
var penUp = false;
|
2676
|
-
|
2677
|
-
for (var i=0; i<len; ++i) {
|
2678
|
-
|
2679
|
-
var xPos = coords[i][0];
|
2680
|
-
var yPos = coords[i][1];
|
2681
|
-
|
2682
|
-
if (i > 0) {
|
2683
|
-
var prevX = coords[i - 1][0];
|
2684
|
-
var prevY = coords[i - 1][1];
|
2685
|
-
}
|
2686
|
-
|
2687
|
-
|
2688
|
-
if ((
|
2689
|
-
(i == 0 && coords[i])
|
2690
|
-
|| (yPos < this.gutterTop)
|
2691
|
-
|| (prevY < this.gutterTop)
|
2692
|
-
|| (yPos > (height - this.gutterBottom))
|
2693
|
-
|| (i > 0 && prevX > (width - this.gutterRight))
|
2694
|
-
|| (i > 0 && prevY > (height - this.gutterBottom))
|
2695
|
-
|| prevY == null
|
2696
|
-
|| penUp == true
|
2697
|
-
) && (!prop['chart.outofbounds'] || yPos == null || prevY == null) ) {
|
2698
|
-
|
2699
|
-
if (RG.ISOLD && yPos == null) {
|
2700
|
-
// ...?
|
2701
|
-
} else {
|
2702
|
-
co.moveTo(coords[i][0], coords[i][1]);
|
2703
|
-
}
|
2704
|
-
|
2705
|
-
penUp = false;
|
2706
|
-
|
2707
|
-
} else {
|
2708
|
-
|
2709
|
-
if (prop['chart.stepped'] && i > 0) {
|
2710
|
-
co.lineTo(coords[i][0], coords[i - 1][1]);
|
2711
|
-
}
|
2712
|
-
|
2713
|
-
// Don't draw the last bit of a stepped chart. Now DO
|
2714
|
-
//if (!this.properties['chart.stepped'] || i < (coords.length - 1)) {
|
2715
|
-
co.lineTo(coords[i][0], coords[i][1]);
|
2716
|
-
//}
|
2717
|
-
penUp = false;
|
2718
|
-
}
|
2719
|
-
}
|
2720
|
-
|
2721
|
-
/**
|
2722
|
-
* If two colors are specified instead of one, go over the up bits
|
2723
|
-
*/
|
2724
|
-
if (prop['chart.colors.alternate'] && typeof(color) == 'object' && color[0] && color[1]) {
|
2725
|
-
for (var i=1; i<len; ++i) {
|
2726
|
-
|
2727
|
-
var prevX = coords[i - 1][0];
|
2728
|
-
var prevY = coords[i - 1][1];
|
2729
|
-
|
2730
|
-
if (prevY != null && coords[i][1] != null) {
|
2731
|
-
co.beginPath();
|
2732
|
-
co.strokeStyle = color[coords[i][1] < prevY ? 0 : 1];
|
2733
|
-
co.lineWidth = prop['chart.linewidth'];
|
2734
|
-
co.moveTo(prevX, prevY);
|
2735
|
-
co.lineTo(coords[i][0], coords[i][1]);
|
2736
|
-
co.stroke();
|
2737
|
-
}
|
2738
|
-
}
|
2739
|
-
}
|
2740
|
-
};
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
/**
|
2746
|
-
* This function is used by MSIE only to manually draw the shadow
|
2747
|
-
*
|
2748
|
-
* @param array coords The coords for the line
|
2749
|
-
*/
|
2750
|
-
this.drawIEShadow =
|
2751
|
-
this.DrawIEShadow = function (coords, color)
|
2752
|
-
{
|
2753
|
-
var offsetx = prop['chart.shadow.offsetx'];
|
2754
|
-
var offsety = prop['chart.shadow.offsety'];
|
2755
|
-
|
2756
|
-
co.lineWidth = prop['chart.linewidth'];
|
2757
|
-
co.strokeStyle = color;
|
2758
|
-
|
2759
|
-
co.beginPath();
|
2760
|
-
for (var i=0; i<coords.length; ++i) {
|
2761
|
-
|
2762
|
-
var isNull = RG.isNull(coords[i][1]);
|
2763
|
-
var prevIsNull = RG.isNull(coords[i-1]) || RG.isNull(coords[i-1][1]);
|
2764
|
-
|
2765
|
-
if (i == 0 || isNull || prevIsNull) {
|
2766
|
-
if (!isNull) {
|
2767
|
-
co.moveTo(coords[i][0] + offsetx, coords[i][1] + offsety);
|
2768
|
-
}
|
2769
|
-
} else {
|
2770
|
-
co.lineTo(coords[i][0] + offsetx, coords[i][1] + offsety);
|
2771
|
-
}
|
2772
|
-
}
|
2773
|
-
co.stroke();
|
2774
|
-
};
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
2779
|
-
/**
|
2780
|
-
* Draw the backdrop
|
2781
|
-
*/
|
2782
|
-
this.drawBackdrop =
|
2783
|
-
this.DrawBackdrop = function (coords, color)
|
2784
|
-
{
|
2785
|
-
//var ca = this.canvas;
|
2786
|
-
//var co = this.context;
|
2787
|
-
//var prop = this.properties;
|
2788
|
-
|
2789
|
-
var size = prop['chart.backdrop.size'];
|
2790
|
-
co.lineWidth = size;
|
2791
|
-
co.globalAlpha = prop['chart.backdrop.alpha'];
|
2792
|
-
co.strokeStyle = color;
|
2793
|
-
var yCoords = [];
|
2794
|
-
|
2795
|
-
co.beginPath();
|
2796
|
-
if (prop['chart.curvy'] && !RG.ISOLD) {
|
2797
|
-
|
2798
|
-
// The DrawSpline function only takes the Y coords so extract them from the coords that have
|
2799
|
-
// (which are X/Y pairs)
|
2800
|
-
for (var i=0; i<coords.length; ++i) {
|
2801
|
-
yCoords.push(coords[i][1])
|
2802
|
-
}
|
2803
|
-
|
2804
|
-
this.DrawSpline(co, yCoords, color, null);
|
2805
|
-
|
2806
|
-
} else {
|
2807
|
-
co.moveTo(coords[0][0], coords[0][1]);
|
2808
|
-
for (var j=1; j<coords.length; ++j) {
|
2809
|
-
co.lineTo(coords[j][0], coords[j][1]);
|
2810
|
-
}
|
2811
|
-
}
|
2812
|
-
co.stroke();
|
2813
|
-
|
2814
|
-
// Reset the alpha value
|
2815
|
-
co.globalAlpha = 1;
|
2816
|
-
RG.NoShadow(this);
|
2817
|
-
};
|
2818
|
-
|
2819
|
-
|
2820
|
-
|
2821
|
-
|
2822
|
-
/**
|
2823
|
-
* Returns the linewidth
|
2824
|
-
*/
|
2825
|
-
this.getLineWidth =
|
2826
|
-
this.GetLineWidth = function (i)
|
2827
|
-
{
|
2828
|
-
var linewidth = prop['chart.linewidth'];
|
2829
|
-
|
2830
|
-
if (typeof(linewidth) == 'number') {
|
2831
|
-
return linewidth;
|
2832
|
-
|
2833
|
-
} else if (typeof(linewidth) == 'object') {
|
2834
|
-
if (linewidth[i]) {
|
2835
|
-
return linewidth[i];
|
2836
|
-
} else {
|
2837
|
-
return linewidth[0];
|
2838
|
-
}
|
2839
|
-
|
2840
|
-
alert('[LINE] Error! chart.linewidth should be a single number or an array of one or more numbers');
|
2841
|
-
}
|
2842
|
-
};
|
2843
|
-
|
2844
|
-
|
2845
|
-
|
2846
|
-
|
2847
|
-
/**
|
2848
|
-
* The getPoint() method - used to get the point the mouse is currently over, if any
|
2849
|
-
*
|
2850
|
-
* @param object e The event object
|
2851
|
-
* @param object OPTIONAL You can pass in the bar object instead of the
|
2852
|
-
* function getting it from the canvas
|
2853
|
-
*/
|
2854
|
-
this.getShape =
|
2855
|
-
this.getPoint = function (e)
|
2856
|
-
{
|
2857
|
-
var obj = this,
|
2858
|
-
RG = RGraph,
|
2859
|
-
ca = canvas = e.target,
|
2860
|
-
co = context = this.context,
|
2861
|
-
prop = this.properties;
|
2862
|
-
|
2863
|
-
var mouseXY = RG.getMouseXY(e),
|
2864
|
-
mouseX = mouseXY[0],
|
2865
|
-
mouseY = mouseXY[1];
|
2866
|
-
|
2867
|
-
// This facilitates you being able to pass in the bar object as a parameter instead of
|
2868
|
-
// the function getting it from the object
|
2869
|
-
if (arguments[1]) {
|
2870
|
-
obj = arguments[1];
|
2871
|
-
}
|
2872
|
-
|
2873
|
-
for (var i=0; i<obj.coords.length; ++i) {
|
2874
|
-
|
2875
|
-
var x = obj.coords[i][0];
|
2876
|
-
var y = obj.coords[i][1];
|
2877
|
-
|
2878
|
-
// Do this if the hotspot is triggered by the X coord AND the Y coord
|
2879
|
-
if ( mouseX <= (x + prop['chart.tooltips.hotspot.size'])
|
2880
|
-
&& mouseX >= (x - prop['chart.tooltips.hotspot.size'])
|
2881
|
-
&& mouseY <= (y + prop['chart.tooltips.hotspot.size'])
|
2882
|
-
&& mouseY >= (y - prop['chart.tooltips.hotspot.size'])
|
2883
|
-
) {
|
2884
|
-
|
2885
|
-
if (RG.parseTooltipText) {
|
2886
|
-
var tooltip = RG.parseTooltipText(prop['chart.tooltips'], i);
|
2887
|
-
}
|
2888
|
-
|
2889
|
-
// Work out the dataset
|
2890
|
-
var dataset = 0;
|
2891
|
-
var idx = i;
|
2892
|
-
while ((idx + 1) > this.data[dataset].length) {
|
2893
|
-
idx -= this.data[dataset].length;
|
2894
|
-
dataset++;
|
2895
|
-
}
|
2896
|
-
|
2897
|
-
return {0:obj, 1:x, 2:y, 3:i, 'object': obj, 'x': x, 'y': y, 'index': i, 'tooltip': tooltip, 'dataset': dataset, 'index_adjusted': idx};
|
2898
|
-
|
2899
|
-
} else if ( prop['chart.tooltips.hotspot.xonly'] == true
|
2900
|
-
&& mouseX <= (x + prop['chart.tooltips.hotspot.size'])
|
2901
|
-
&& mouseX >= (x - prop['chart.tooltips.hotspot.size'])) {
|
2902
|
-
|
2903
|
-
var tooltip = RG.parseTooltipText(prop['chart.tooltips'], i);
|
2904
|
-
|
2905
|
-
return {0:obj, 1:x, 2:y, 3:i, 'object': obj, 'x': x, 'y': y, 'index': i, 'tooltip': tooltip};
|
2906
|
-
}
|
2907
|
-
}
|
2908
|
-
};
|
2909
|
-
|
2910
|
-
|
2911
|
-
|
2912
|
-
|
2913
|
-
/**
|
2914
|
-
* Draws the above line labels
|
2915
|
-
*/
|
2916
|
-
this.drawAboveLabels =
|
2917
|
-
this.DrawAboveLabels = function ()
|
2918
|
-
{
|
2919
|
-
var size = prop['chart.labels.above.size'],
|
2920
|
-
font = prop['chart.labels.above.font'] || prop['chart.text.font'],
|
2921
|
-
units_pre = prop['chart.labels.above.units.pre'],
|
2922
|
-
units_post = prop['chart.labels.above.units.post'],
|
2923
|
-
decimals = prop['chart.labels.above.decimals'],
|
2924
|
-
color = prop['chart.labels.above.color'] || prop['chart.text.color'],
|
2925
|
-
bgcolor = prop['chart.labels.above.background'] || 'white',
|
2926
|
-
border = ((
|
2927
|
-
typeof prop['chart.labels.above.border'] === 'boolean'
|
2928
|
-
|| typeof prop['chart.labels.above.border'] === 'number'
|
2929
|
-
) ? prop['chart.labels.above.border'] : true),
|
2930
|
-
offsety = prop['chart.labels.above.offsety'] + size,
|
2931
|
-
specific = prop['chart.labels.above.specific'];
|
2932
|
-
|
2933
|
-
// Use this to 'reset' the drawing state
|
2934
|
-
co.beginPath();
|
2935
|
-
|
2936
|
-
// Don't need to check that chart.labels.above is enabled here, it's been done already
|
2937
|
-
for (var i=0, len=this.coords.length; i<len; i+=1) {
|
2938
|
-
|
2939
|
-
var coords = this.coords[i];
|
2940
|
-
|
2941
|
-
RG.text2(this, {
|
2942
|
-
color:color,
|
2943
|
-
'font':font,
|
2944
|
-
'size':size,
|
2945
|
-
'x':coords[0],
|
2946
|
-
'y':coords[1] - offsety,
|
2947
|
-
'text':(specific && specific[i]) ? specific[i] : (specific ? null : RG.numberFormat(this, typeof decimals === 'number' ? this.data_arr[i].toFixed(decimals) : this.data_arr[i], units_pre, units_post)),
|
2948
|
-
'valign':'center',
|
2949
|
-
'halign':'center',
|
2950
|
-
'bounding':true,
|
2951
|
-
'boundingFill':bgcolor,
|
2952
|
-
'boundingStroke':border ? 'black' : 'rgba(0,0,0,0)',
|
2953
|
-
'tag':'labels.above'
|
2954
|
-
});
|
2955
|
-
}
|
2956
|
-
};
|
2957
|
-
|
2958
|
-
|
2959
|
-
|
2960
|
-
|
2961
|
-
/**
|
2962
|
-
* Draw a curvy line.
|
2963
|
-
*/
|
2964
|
-
this.drawCurvyLine =
|
2965
|
-
this.DrawCurvyLine = function (coords, color, linewidth, index)
|
2966
|
-
{
|
2967
|
-
var yCoords = [];
|
2968
|
-
|
2969
|
-
for (var i=0; i<coords.length; ++i) {
|
2970
|
-
yCoords.push(coords[i][1]);
|
2971
|
-
}
|
2972
|
-
|
2973
|
-
if (prop['chart.filled']) {
|
2974
|
-
co.beginPath();
|
2975
|
-
|
2976
|
-
// First, work out the xaxispos
|
2977
|
-
if (prop['chart.xaxispos'] === 'center') {
|
2978
|
-
var xaxisY = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop;
|
2979
|
-
} else {
|
2980
|
-
var xaxisY = this.getYCoord(0);
|
2981
|
-
}
|
2982
|
-
|
2983
|
-
|
2984
|
-
co.moveTo(coords[0][0],xaxisY);
|
2985
|
-
this.drawSpline(co, yCoords, color, index);
|
2986
|
-
|
2987
|
-
if (prop['chart.filled.accumulative'] && index > 0) {
|
2988
|
-
for (var i=(this.coordsSpline[index - 1].length - 1); i>=0; i-=1) {
|
2989
|
-
co.lineTo(this.coordsSpline[index - 1][i][0], this.coordsSpline[index - 1][i][1]);
|
2990
|
-
}
|
2991
|
-
} else {
|
2992
|
-
co.lineTo(coords[coords.length - 1][0],xaxisY);
|
2993
|
-
}
|
2994
|
-
co.fill();
|
2995
|
-
}
|
2996
|
-
|
2997
|
-
co.beginPath();
|
2998
|
-
this.DrawSpline(co, yCoords, color, index);
|
2999
|
-
co.stroke();
|
3000
|
-
};
|
3001
|
-
|
3002
|
-
|
3003
|
-
|
3004
|
-
|
3005
|
-
/**
|
3006
|
-
* When you click on the chart, this method can return the Y value at that point. It works for any point on the
|
3007
|
-
* chart (that is inside the gutters) - not just points on the Line.
|
3008
|
-
*
|
3009
|
-
* @param object e The event object
|
3010
|
-
*/
|
3011
|
-
this.getValue = function (arg)
|
3012
|
-
{
|
3013
|
-
if (arg.length == 2) {
|
3014
|
-
var mouseX = arg[0];
|
3015
|
-
var mouseY = arg[1];
|
3016
|
-
} else {
|
3017
|
-
var mouseCoords = RG.getMouseXY(arg);
|
3018
|
-
var mouseX = mouseCoords[0];
|
3019
|
-
var mouseY = mouseCoords[1];
|
3020
|
-
}
|
3021
|
-
|
3022
|
-
var obj = this;
|
3023
|
-
var xaxispos = prop['chart.xaxispos'];
|
3024
|
-
|
3025
|
-
if (mouseY < prop['chart.gutter.top']) {
|
3026
|
-
return xaxispos == 'bottom' || xaxispos == 'center' ? this.max : this.min;
|
3027
|
-
} else if (mouseY > (ca.height - prop['chart.gutter.bottom'])) {
|
3028
|
-
return xaxispos == 'bottom' ? this.min : this.max;
|
3029
|
-
}
|
3030
|
-
|
3031
|
-
if (prop['chart.xaxispos'] == 'center') {
|
3032
|
-
var value = (( (obj.grapharea / 2) - (mouseY - prop['chart.gutter.top'])) / obj.grapharea) * (obj.max - obj.min);
|
3033
|
-
value *= 2;
|
3034
|
-
value > 0 ? value += this.min : value -= this.min;
|
3035
|
-
return value;
|
3036
|
-
} else if (prop['chart.xaxispos'] == 'top') {
|
3037
|
-
var value = ((obj.grapharea - (mouseY - prop['chart.gutter.top'])) / obj.grapharea) * (obj.max - obj.min);
|
3038
|
-
value = Math.abs(obj.max - value) * -1;
|
3039
|
-
return value;
|
3040
|
-
} else {
|
3041
|
-
var value = ((obj.grapharea - (mouseY - prop['chart.gutter.top'])) / obj.grapharea) * (obj.max - obj.min)
|
3042
|
-
value += obj.min;
|
3043
|
-
return value;
|
3044
|
-
}
|
3045
|
-
};
|
3046
|
-
|
3047
|
-
|
3048
|
-
|
3049
|
-
|
3050
|
-
/**
|
3051
|
-
* Each object type has its own Highlight() function which highlights the appropriate shape
|
3052
|
-
*
|
3053
|
-
* @param object shape The shape to highlight
|
3054
|
-
*/
|
3055
|
-
this.highlight =
|
3056
|
-
this.Highlight = function (shape)
|
3057
|
-
{
|
3058
|
-
if (prop['chart.tooltips.highlight']) {
|
3059
|
-
|
3060
|
-
if (typeof prop['chart.highlight.style'] === 'function') {
|
3061
|
-
(prop['chart.highlight.style'])(shape);
|
3062
|
-
|
3063
|
-
} else if (prop['chart.highlight.style'] === 'halo') {
|
3064
|
-
|
3065
|
-
var obj = shape.object,
|
3066
|
-
color = prop['chart.colors'][shape.dataset];
|
3067
|
-
|
3068
|
-
// Clear a space in white first for the tickmark
|
3069
|
-
RG.path2(obj.context, 'b a % % 13 0 6.2830 false f rgba(255,255,255,0.75)',
|
3070
|
-
shape.x,
|
3071
|
-
shape.y
|
3072
|
-
);
|
3073
|
-
|
3074
|
-
RG.path2(obj.context, 'ga 0.15 b a % % 13 0 6.2830 false f % ga 1',
|
3075
|
-
shape.x,
|
3076
|
-
shape.y,
|
3077
|
-
color
|
3078
|
-
);
|
3079
|
-
|
3080
|
-
RG.path2(obj.context, 'b a % % 7 0 6.2830 false f white',
|
3081
|
-
shape.x,
|
3082
|
-
shape.y
|
3083
|
-
);
|
3084
|
-
|
3085
|
-
RG.path2(obj.context, 'b a % % 5 0 6.2830 false f %',
|
3086
|
-
shape.x,
|
3087
|
-
shape.y,
|
3088
|
-
color
|
3089
|
-
);
|
3090
|
-
|
3091
|
-
} else {
|
3092
|
-
RG.Highlight.Point(this, shape);
|
3093
|
-
}
|
3094
|
-
}
|
3095
|
-
};
|
3096
|
-
|
3097
|
-
|
3098
|
-
|
3099
|
-
|
3100
|
-
/**
|
3101
|
-
* The getObjectByXY() worker method. Don't call this call:
|
3102
|
-
*
|
3103
|
-
* RG.ObjectRegistry.getObjectByXY(e)
|
3104
|
-
*
|
3105
|
-
* @param object e The event object
|
3106
|
-
*/
|
3107
|
-
this.getObjectByXY = function (e)
|
3108
|
-
{
|
3109
|
-
//var ca = this.canvas;
|
3110
|
-
//var prop = this.properties;
|
3111
|
-
var mouseXY = RG.getMouseXY(e);
|
3112
|
-
|
3113
|
-
// The 5 is so that the cursor doesn't have to be over the graphArea to trigger the hotspot
|
3114
|
-
if (
|
3115
|
-
(mouseXY[0] > prop['chart.gutter.left'] - 5)
|
3116
|
-
&& mouseXY[0] < (ca.width - prop['chart.gutter.right'] + 5)
|
3117
|
-
&& mouseXY[1] > (prop['chart.gutter.top'] - 5)
|
3118
|
-
&& mouseXY[1] < (ca.height - prop['chart.gutter.bottom'] + 5)
|
3119
|
-
) {
|
3120
|
-
|
3121
|
-
return this;
|
3122
|
-
}
|
3123
|
-
};
|
3124
|
-
|
3125
|
-
|
3126
|
-
|
3127
|
-
|
3128
|
-
/**
|
3129
|
-
* This method handles the adjusting calculation for when the mouse is moved
|
3130
|
-
*
|
3131
|
-
* @param object e The event object
|
3132
|
-
*/
|
3133
|
-
this.adjusting_mousemove =
|
3134
|
-
this.Adjusting_mousemove = function (e)
|
3135
|
-
{
|
3136
|
-
/**
|
3137
|
-
* Handle adjusting for the Bar
|
3138
|
-
*/
|
3139
|
-
if (prop['chart.adjustable'] && RG.Registry.Get('chart.adjusting') && RG.Registry.Get('chart.adjusting').uid == this.uid) {
|
3140
|
-
|
3141
|
-
// Rounding the value to the given number of decimals make the chart step
|
3142
|
-
var value = Number(this.getValue(e));//.toFixed(this.properties['chart.scale.decimals']);
|
3143
|
-
var shape = RG.Registry.Get('chart.adjusting.shape');
|
3144
|
-
|
3145
|
-
if (shape) {
|
3146
|
-
|
3147
|
-
RG.Registry.Set('chart.adjusting.shape', shape);
|
3148
|
-
|
3149
|
-
this.original_data[shape['dataset']][shape['index_adjusted']] = Number(value);
|
3150
|
-
|
3151
|
-
RG.redrawCanvas(e.target);
|
3152
|
-
|
3153
|
-
RG.fireCustomEvent(this, 'onadjust');
|
3154
|
-
}
|
3155
|
-
}
|
3156
|
-
};
|
3157
|
-
|
3158
|
-
|
3159
|
-
|
3160
|
-
|
3161
|
-
/**
|
3162
|
-
* This function can be used when the canvas is clicked on (or similar - depending on the event)
|
3163
|
-
* to retrieve the relevant Y coordinate for a particular value.
|
3164
|
-
*
|
3165
|
-
* @param int value The value to get the Y coordinate for
|
3166
|
-
*/
|
3167
|
-
this.getYCoord = function (value)
|
3168
|
-
{
|
3169
|
-
if (typeof(value) != 'number') {
|
3170
|
-
return null;
|
3171
|
-
}
|
3172
|
-
|
3173
|
-
var y;
|
3174
|
-
var xaxispos = prop['chart.xaxispos'];
|
3175
|
-
|
3176
|
-
// Higher than max
|
3177
|
-
// Commented out on March 7th 2013 because the tan curve was not showing correctly
|
3178
|
-
//if (value > this.max) {
|
3179
|
-
// value = this.max;
|
3180
|
-
//}
|
3181
|
-
|
3182
|
-
if (xaxispos == 'top') {
|
3183
|
-
|
3184
|
-
// Account for negative numbers
|
3185
|
-
//if (value < 0) {
|
3186
|
-
// value = Math.abs(value);
|
3187
|
-
//}
|
3188
|
-
|
3189
|
-
y = ((value - this.min) / (this.max - this.min)) * this.grapharea;
|
3190
|
-
|
3191
|
-
// Inverted Y labels
|
3192
|
-
if (prop['chart.scale.invert']) {
|
3193
|
-
y = this.grapharea - y;
|
3194
|
-
}
|
3195
|
-
|
3196
|
-
y = y + this.gutterTop
|
3197
|
-
|
3198
|
-
} else if (xaxispos == 'center') {
|
3199
|
-
|
3200
|
-
y = ((value - this.min) / (this.max - this.min)) * (this.grapharea / 2);
|
3201
|
-
y = (this.grapharea / 2) - y;
|
3202
|
-
y += this.gutterTop;
|
3203
|
-
|
3204
|
-
} else {
|
3205
|
-
|
3206
|
-
if ((value < this.min || value > this.max) && prop['chart.outofbounds'] == false) {
|
3207
|
-
return null;
|
3208
|
-
}
|
3209
|
-
|
3210
|
-
y = ((value - this.min) / (this.max - this.min)) * this.grapharea;
|
3211
|
-
|
3212
|
-
// Inverted Y labels
|
3213
|
-
if (prop['chart.scale.invert']) {
|
3214
|
-
y = this.grapharea - y;
|
3215
|
-
}
|
3216
|
-
|
3217
|
-
y = ca.height - this.gutterBottom - y;
|
3218
|
-
}
|
3219
|
-
|
3220
|
-
return y;
|
3221
|
-
};
|
3222
|
-
|
3223
|
-
|
3224
|
-
|
3225
|
-
|
3226
|
-
/**
|
3227
|
-
* This function positions a tooltip when it is displayed
|
3228
|
-
*
|
3229
|
-
* @param obj object The chart object
|
3230
|
-
* @param int x The X coordinate specified for the tooltip
|
3231
|
-
* @param int y The Y coordinate specified for the tooltip
|
3232
|
-
* @param objec tooltip The tooltips DIV element
|
3233
|
-
*/
|
3234
|
-
this.positionTooltip = function (obj, x, y, tooltip, idx)
|
3235
|
-
{
|
3236
|
-
|
3237
|
-
var coordX = obj.coords[tooltip.__index__][0];
|
3238
|
-
var coordY = obj.coords[tooltip.__index__][1];
|
3239
|
-
var canvasXY = RG.getCanvasXY(obj.canvas);
|
3240
|
-
var gutterLeft = prop['chart.gutter.left'];
|
3241
|
-
var gutterTop = prop['chart.gutter.top'];
|
3242
|
-
var width = tooltip.offsetWidth;
|
3243
|
-
var height = tooltip.offsetHeight;
|
3244
|
-
var mouseXY = RG.getMouseXY(window.event);
|
3245
|
-
|
3246
|
-
// Set the top position
|
3247
|
-
tooltip.style.left = 0;
|
3248
|
-
tooltip.style.top = window.event.pageY - height - 20 + 'px';
|
3249
|
-
|
3250
|
-
// By default any overflow is hidden
|
3251
|
-
tooltip.style.overflow = '';
|
3252
|
-
|
3253
|
-
// Reposition the tooltip if at the edges:
|
3254
|
-
|
3255
|
-
// LEFT edge
|
3256
|
-
if (canvasXY[0] + mouseXY[0] - (width / 2) < 0) {
|
3257
|
-
tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
|
3258
|
-
|
3259
|
-
// RIGHT edge
|
3260
|
-
} else if (canvasXY[0] + mouseXY[0] + (width / 2) > doc.body.offsetWidth) {
|
3261
|
-
tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
|
3262
|
-
|
3263
|
-
// Default positioning - CENTERED
|
3264
|
-
} else {
|
3265
|
-
tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
|
3266
|
-
}
|
3267
|
-
};
|
3268
|
-
|
3269
|
-
|
3270
|
-
|
3271
|
-
|
3272
|
-
/**
|
3273
|
-
* This function draws a curvy line
|
3274
|
-
*
|
3275
|
-
* @param object context The 2D context
|
3276
|
-
* @param array coords The coordinates
|
3277
|
-
*/
|
3278
|
-
this.drawSpline =
|
3279
|
-
this.DrawSpline = function (context, coords, color, index)
|
3280
|
-
{
|
3281
|
-
this.coordsSpline[index] = [];
|
3282
|
-
var xCoords = [];
|
3283
|
-
var gutterLeft = prop['chart.gutter.left'];
|
3284
|
-
var gutterRight = prop['chart.gutter.right'];
|
3285
|
-
var hmargin = prop['chart.hmargin'];
|
3286
|
-
var interval = (ca.width - (gutterLeft + gutterRight) - (2 * hmargin)) / (coords.length - 1);
|
3287
|
-
|
3288
|
-
co.strokeStyle = color;
|
3289
|
-
|
3290
|
-
/**
|
3291
|
-
* The drawSpline function takes an array of JUST Y coords - not X/Y coords. So the line coords need converting
|
3292
|
-
* if we've been given X/Y pairs
|
3293
|
-
*/
|
3294
|
-
for (var i=0,len=coords.length; i<len;i+=1) {
|
3295
|
-
if (typeof coords[i] == 'object' && coords[i] && coords[i].length == 2) {
|
3296
|
-
coords[i] = Number(coords[i][1]);
|
3297
|
-
}
|
3298
|
-
}
|
3299
|
-
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3303
|
-
/**
|
3304
|
-
* Get the Points array in the format we want - first value should be null along with the lst value
|
3305
|
-
*/
|
3306
|
-
var P = [coords[0]];
|
3307
|
-
for (var i=0; i<coords.length; ++i) {
|
3308
|
-
P.push(coords[i]);
|
3309
|
-
}
|
3310
|
-
P.push(coords[coords.length - 1] + (coords[coords.length - 1] - coords[coords.length - 2]));
|
3311
|
-
|
3312
|
-
for (var j=1; j<P.length-2; ++j) {
|
3313
|
-
for (var t=0; t<10; ++t) {
|
3314
|
-
|
3315
|
-
var yCoord = Spline( t/10, P[j-1], P[j], P[j+1], P[j+2] );
|
3316
|
-
|
3317
|
-
xCoords.push(((j-1) * interval) + (t * (interval / 10)) + gutterLeft + hmargin);
|
3318
|
-
|
3319
|
-
co.lineTo(xCoords[xCoords.length - 1], yCoord);
|
3320
|
-
|
3321
|
-
|
3322
|
-
if (typeof index == 'number') {
|
3323
|
-
this.coordsSpline[index].push([xCoords[xCoords.length - 1], yCoord]);
|
3324
|
-
}
|
3325
|
-
}
|
3326
|
-
}
|
3327
|
-
|
3328
|
-
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
3332
|
-
// Draw the last section
|
3333
|
-
co.lineTo(((j-1) * interval) + gutterLeft + hmargin, P[j]);
|
3334
|
-
if (typeof index == 'number') {
|
3335
|
-
this.coordsSpline[index].push([((j-1) * interval) + gutterLeft + hmargin, P[j]]);
|
3336
|
-
}
|
3337
|
-
|
3338
|
-
|
3339
|
-
|
3340
|
-
|
3341
|
-
|
3342
|
-
|
3343
|
-
function Spline (t, P0, P1, P2, P3)
|
3344
|
-
{
|
3345
|
-
return 0.5 * ((2 * P1) +
|
3346
|
-
((0-P0) + P2) * t +
|
3347
|
-
((2*P0 - (5*P1) + (4*P2) - P3) * (t*t) +
|
3348
|
-
((0-P0) + (3*P1)- (3*P2) + P3) * (t*t*t)));
|
3349
|
-
}
|
3350
|
-
};
|
3351
|
-
|
3352
|
-
|
3353
|
-
|
3354
|
-
|
3355
|
-
/**
|
3356
|
-
* This allows for easy specification of gradients
|
3357
|
-
*/
|
3358
|
-
this.parseColors = function ()
|
3359
|
-
{
|
3360
|
-
// Save the original colors so that they can be restored when the canvas is reset
|
3361
|
-
if (this.original_colors.length === 0) {
|
3362
|
-
this.original_colors['chart.colors'] = RGraph.array_clone(prop['chart.colors']);
|
3363
|
-
this.original_colors['chart.fillstyle'] = RGraph.array_clone(prop['chart.fillstyle']);
|
3364
|
-
this.original_colors['chart.key.colors'] = RGraph.array_clone(prop['chart.key.colors']);
|
3365
|
-
this.original_colors['chart.background.barcolor1'] = prop['chart.background.barcolor1'];
|
3366
|
-
this.original_colors['chart.background.barcolor2'] = prop['chart.background.barcolor2'];
|
3367
|
-
this.original_colors['chart.background.grid.color'] = prop['chart.background.grid.color'];
|
3368
|
-
this.original_colors['chart.background.color'] = prop['chart.background.color'];
|
3369
|
-
this.original_colors['chart.text.color'] = prop['chart.text.color'];
|
3370
|
-
this.original_colors['chart.crosshairs.color'] = prop['chart.crosshairs.color'];
|
3371
|
-
this.original_colors['chart.annotate.color'] = prop['chart.annotate.color'];
|
3372
|
-
this.original_colors['chart.title.color'] = prop['chart.title.color'];
|
3373
|
-
this.original_colors['chart.title.yaxis.color'] = prop['chart.title.yaxis.color'];
|
3374
|
-
this.original_colors['chart.key.background'] = prop['chart.key.background'];
|
3375
|
-
this.original_colors['chart.axis.color'] = prop['chart.axis.color'];
|
3376
|
-
this.original_colors['chart.highlight.fill'] = prop['chart.highlight.fill'];
|
3377
|
-
}
|
3378
|
-
|
3379
|
-
|
3380
|
-
|
3381
|
-
for (var i=0; i<prop['chart.colors'].length; ++i) {
|
3382
|
-
if (typeof(prop['chart.colors'][i]) == 'object' && prop['chart.colors'][i][0] && prop['chart.colors'][i][1]) {
|
3383
|
-
prop['chart.colors'][i][0] = this.parseSingleColorForGradient(prop['chart.colors'][i][0]);
|
3384
|
-
prop['chart.colors'][i][1] = this.parseSingleColorForGradient(prop['chart.colors'][i][1]);
|
3385
|
-
} else {
|
3386
|
-
prop['chart.colors'][i] = this.parseSingleColorForGradient(prop['chart.colors'][i]);
|
3387
|
-
}
|
3388
|
-
}
|
3389
|
-
|
3390
|
-
/**
|
3391
|
-
* Fillstyle
|
3392
|
-
*/
|
3393
|
-
if (prop['chart.fillstyle']) {
|
3394
|
-
if (typeof(prop['chart.fillstyle']) == 'string') {
|
3395
|
-
prop['chart.fillstyle'] = this.parseSingleColorForGradient(prop['chart.fillstyle'], 'vertical');
|
3396
|
-
} else {
|
3397
|
-
for (var i=0; i<prop['chart.fillstyle'].length; ++i) {
|
3398
|
-
prop['chart.fillstyle'][i] = this.parseSingleColorForGradient(prop['chart.fillstyle'][i], 'vertical');
|
3399
|
-
}
|
3400
|
-
}
|
3401
|
-
}
|
3402
|
-
|
3403
|
-
/**
|
3404
|
-
* Key colors
|
3405
|
-
*/
|
3406
|
-
if (!RG.is_null(prop['chart.key.colors'])) {
|
3407
|
-
for (var i=0; i<prop['chart.key.colors'].length; ++i) {
|
3408
|
-
prop['chart.key.colors'][i] = this.parseSingleColorForGradient(prop['chart.key.colors'][i]);
|
3409
|
-
}
|
3410
|
-
}
|
3411
|
-
|
3412
|
-
/**
|
3413
|
-
* Parse various properties for colors
|
3414
|
-
*/
|
3415
|
-
var properties = [
|
3416
|
-
'chart.background.barcolor1',
|
3417
|
-
'chart.background.barcolor2',
|
3418
|
-
'chart.background.grid.color',
|
3419
|
-
'chart.background.color',
|
3420
|
-
'chart.text.color',
|
3421
|
-
'chart.crosshairs.color',
|
3422
|
-
'chart.annotate.color',
|
3423
|
-
'chart.title.color',
|
3424
|
-
'chart.title.yaxis.color',
|
3425
|
-
'chart.key.background',
|
3426
|
-
'chart.axis.color',
|
3427
|
-
'chart.highlight.fill'
|
3428
|
-
];
|
3429
|
-
|
3430
|
-
for (var i=0; i<properties.length; ++i) {
|
3431
|
-
prop[properties[i]] = this.parseSingleColorForGradient(prop[properties[i]]);
|
3432
|
-
}
|
3433
|
-
};
|
3434
|
-
|
3435
|
-
|
3436
|
-
|
3437
|
-
|
3438
|
-
/**
|
3439
|
-
* Use this function to reset the object to the post-constructor state. Eg reset colors if
|
3440
|
-
* need be etc
|
3441
|
-
*/
|
3442
|
-
this.reset = function ()
|
3443
|
-
{
|
3444
|
-
};
|
3445
|
-
|
3446
|
-
|
3447
|
-
|
3448
|
-
|
3449
|
-
/**
|
3450
|
-
* This parses a single color value
|
3451
|
-
*/
|
3452
|
-
this.parseSingleColorForGradient = function (color)
|
3453
|
-
{
|
3454
|
-
if (!color || typeof(color) != 'string') {
|
3455
|
-
return color;
|
3456
|
-
}
|
3457
|
-
|
3458
|
-
/**
|
3459
|
-
* Horizontal or vertical gradient
|
3460
|
-
*/
|
3461
|
-
var dir = typeof(arguments[1]) == 'string' ? arguments[1] : 'vertical';
|
3462
|
-
|
3463
|
-
if (typeof color === 'string' && color.match(/^gradient\((.*)\)$/i)) {
|
3464
|
-
|
3465
|
-
var parts = RegExp.$1.split(':');
|
3466
|
-
|
3467
|
-
// Create the gradient
|
3468
|
-
if (dir == 'horizontal') {
|
3469
|
-
var grad = co.createLinearGradient(0,0,ca.width,0);
|
3470
|
-
} else {
|
3471
|
-
var grad = co.createLinearGradient(0,ca.height - prop['chart.gutter.bottom'],0,prop['chart.gutter.top']);
|
3472
|
-
}
|
3473
|
-
|
3474
|
-
var diff = 1 / (parts.length - 1);
|
3475
|
-
|
3476
|
-
grad.addColorStop(0, RG.trim(parts[0]));
|
3477
|
-
|
3478
|
-
for (var j=1; j<parts.length; ++j) {
|
3479
|
-
grad.addColorStop(j * diff, RG.trim(parts[j]));
|
3480
|
-
}
|
3481
|
-
}
|
3482
|
-
|
3483
|
-
return grad ? grad : color;
|
3484
|
-
};
|
3485
|
-
|
3486
|
-
|
3487
|
-
|
3488
|
-
|
3489
|
-
/**
|
3490
|
-
* Sets the appropriate shadow
|
3491
|
-
*/
|
3492
|
-
this.setShadow =
|
3493
|
-
this.SetShadow = function (i)
|
3494
|
-
{
|
3495
|
-
//var ca = this.canvas;
|
3496
|
-
//var co = this.context;
|
3497
|
-
//var prop = this.properties;
|
3498
|
-
|
3499
|
-
if (prop['chart.shadow']) {
|
3500
|
-
/**
|
3501
|
-
* Handle the appropriate shadow color. This now facilitates an array of differing
|
3502
|
-
* shadow colors
|
3503
|
-
*/
|
3504
|
-
var shadowColor = prop['chart.shadow.color'];
|
3505
|
-
|
3506
|
-
/**
|
3507
|
-
* Accommodate an array of shadow colors as well as a single string
|
3508
|
-
*/
|
3509
|
-
if (typeof(shadowColor) == 'object' && shadowColor[i - 1]) {
|
3510
|
-
co.shadowColor = shadowColor[i];
|
3511
|
-
|
3512
|
-
} else if (typeof(shadowColor) == 'object') {
|
3513
|
-
co.shadowColor = shadowColor[0];
|
3514
|
-
|
3515
|
-
} else if (typeof(shadowColor) == 'string') {
|
3516
|
-
co.shadowColor = shadowColor;
|
3517
|
-
}
|
3518
|
-
|
3519
|
-
co.shadowBlur = prop['chart.shadow.blur'];
|
3520
|
-
co.shadowOffsetX = prop['chart.shadow.offsetx'];
|
3521
|
-
co.shadowOffsetY = prop['chart.shadow.offsety'];
|
3522
|
-
}
|
3523
|
-
};
|
3524
|
-
|
3525
|
-
|
3526
|
-
|
3527
|
-
|
3528
|
-
/**
|
3529
|
-
* This function handles highlighting an entire data-series for the interactive
|
3530
|
-
* key
|
3531
|
-
*
|
3532
|
-
* @param int index The index of the data series to be highlighted
|
3533
|
-
*/
|
3534
|
-
this.interactiveKeyHighlight = function (index)
|
3535
|
-
{
|
3536
|
-
var coords = this.coords2[index];
|
3537
|
-
|
3538
|
-
if (coords) {
|
3539
|
-
|
3540
|
-
var pre_linewidth = co.lineWidth;
|
3541
|
-
var pre_linecap = co.lineCap;
|
3542
|
-
|
3543
|
-
co.lineWidth = prop['chart.linewidth'] + 10;
|
3544
|
-
co.lineCap = 'round';
|
3545
|
-
co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
|
3546
|
-
|
3547
|
-
|
3548
|
-
co.beginPath();
|
3549
|
-
if (prop['chart.curvy']) {
|
3550
|
-
this.DrawSpline(co, coords, prop['chart.key.interactive.highlight.chart'], null);
|
3551
|
-
} else {
|
3552
|
-
for (var i=0,len=coords.length; i<len; i+=1) {
|
3553
|
-
if ( i == 0
|
3554
|
-
|| RG.is_null(coords[i][1])
|
3555
|
-
|| (typeof coords[i - 1][1] != undefined && RG.is_null(coords[i - 1][1]))) {
|
3556
|
-
co.moveTo(coords[i][0], coords[i][1]);
|
3557
|
-
} else {
|
3558
|
-
co.lineTo(coords[i][0], coords[i][1]);
|
3559
|
-
}
|
3560
|
-
}
|
3561
|
-
}
|
3562
|
-
co.stroke();
|
3563
|
-
|
3564
|
-
// Reset the lineCap and lineWidth
|
3565
|
-
co.lineWidth = pre_linewidth;
|
3566
|
-
co.lineCap = pre_linecap;
|
3567
|
-
}
|
3568
|
-
};
|
3569
|
-
|
3570
|
-
|
3571
|
-
|
3572
|
-
|
3573
|
-
/**
|
3574
|
-
* Using a function to add events makes it easier to facilitate method chaining
|
3575
|
-
*
|
3576
|
-
* @param string type The type of even to add
|
3577
|
-
* @param function func
|
3578
|
-
*/
|
3579
|
-
this.on = function (type, func)
|
3580
|
-
{
|
3581
|
-
if (type.substr(0,2) !== 'on') {
|
3582
|
-
type = 'on' + type;
|
3583
|
-
}
|
3584
|
-
|
3585
|
-
this[type] = func;
|
3586
|
-
|
3587
|
-
return this;
|
3588
|
-
};
|
3589
|
-
|
3590
|
-
|
3591
|
-
|
3592
|
-
|
3593
|
-
/**
|
3594
|
-
* This function runs once only
|
3595
|
-
* (put at the end of the file (before any effects))
|
3596
|
-
*/
|
3597
|
-
this.firstDrawFunc = function ()
|
3598
|
-
{
|
3599
|
-
};
|
3600
|
-
|
3601
|
-
|
3602
|
-
|
3603
|
-
|
3604
|
-
//
|
3605
|
-
// Draws error-bars for the Bar and Line charts
|
3606
|
-
//
|
3607
|
-
this.drawErrorbars = function ()
|
3608
|
-
{
|
3609
|
-
// Save the state of the canvas so that it can be restored at the end
|
3610
|
-
co.save();
|
3611
|
-
|
3612
|
-
RG.noShadow(this);
|
3613
|
-
|
3614
|
-
var coords = this.coords,
|
3615
|
-
x = 0,
|
3616
|
-
errorbars = prop['chart.errorbars'],
|
3617
|
-
length = 0;
|
3618
|
-
|
3619
|
-
// If not capped set the width of the cap to zero
|
3620
|
-
if (!prop['chart.errorbars.capped']) {
|
3621
|
-
prop['chart.errorbars.capped.width'] = 0.001;
|
3622
|
-
halfwidth = 0.0005;
|
3623
|
-
}
|
3624
|
-
|
3625
|
-
// Set the linewidth
|
3626
|
-
co.lineWidth = prop['chart.errorbars.linewidth'];
|
3627
|
-
|
3628
|
-
|
3629
|
-
|
3630
|
-
|
3631
|
-
for (var i=0; i<coords.length; ++i) {
|
3632
|
-
|
3633
|
-
var halfwidth = prop['chart.errorbars.capped.width'] / 2 || 5,
|
3634
|
-
color = prop['chart.errorbars.color'] || 'black';
|
3635
|
-
|
3636
|
-
// Set the perbar linewidth if the fourth option in the array
|
3637
|
-
// is specified
|
3638
|
-
if (errorbars[i] && typeof errorbars[i][3] === 'number') {
|
3639
|
-
co.lineWidth = errorbars[i][3];
|
3640
|
-
} else if (typeof prop['chart.errorbars.linewidth'] === 'number') {
|
3641
|
-
co.lineWidth = prop['chart.errorbars.linewidth'];
|
3642
|
-
} else {
|
3643
|
-
co.lineWidth = 1;
|
3644
|
-
}
|
3645
|
-
|
3646
|
-
|
3647
|
-
|
3648
|
-
// Calulate the pixel size
|
3649
|
-
if (typeof errorbars === 'number' || typeof errorbars[i] === 'number') {
|
3650
|
-
|
3651
|
-
if (typeof errorbars === 'number') {
|
3652
|
-
var positiveLength = this.getYCoord(this.min) - this.getYCoord(this.min + errorbars),
|
3653
|
-
negativeLength = positiveLength;
|
3654
|
-
} else {
|
3655
|
-
var positiveLength = this.getYCoord(this.min) - this.getYCoord(this.min + errorbars[i]),
|
3656
|
-
negativeLength = positiveLength;
|
3657
|
-
}
|
3658
|
-
|
3659
|
-
if (positiveLength || negativeLength) {
|
3660
|
-
|
3661
|
-
pa2(
|
3662
|
-
co,
|
3663
|
-
'lj miter lc square b m % % l % % m % % l % % l % % m % % l % % s %',
|
3664
|
-
coords[i][0] - halfwidth,
|
3665
|
-
coords[i][1] + negativeLength,
|
3666
|
-
coords[i][0] + halfwidth,
|
3667
|
-
coords[i][1] + negativeLength,
|
3668
|
-
coords[i][0],
|
3669
|
-
coords[i][1] + negativeLength,
|
3670
|
-
coords[i][0],
|
3671
|
-
coords[i][1] - positiveLength,
|
3672
|
-
coords[i][0] - halfwidth,
|
3673
|
-
coords[i][1] - positiveLength,
|
3674
|
-
coords[i][0],
|
3675
|
-
coords[i][1] - positiveLength,
|
3676
|
-
coords[i][0] + halfwidth,
|
3677
|
-
coords[i][1] - positiveLength,
|
3678
|
-
color
|
3679
|
-
);
|
3680
|
-
|
3681
|
-
pa2(
|
3682
|
-
co,
|
3683
|
-
'lj miter lc square b m % % l % % s %',
|
3684
|
-
coords[i][0] - halfwidth,
|
3685
|
-
coords[i][1] + negativeLength,
|
3686
|
-
coords[i][0] + halfwidth,
|
3687
|
-
coords[i][1] + negativeLength,
|
3688
|
-
color
|
3689
|
-
);
|
3690
|
-
}
|
3691
|
-
|
3692
|
-
|
3693
|
-
|
3694
|
-
} else if (typeof errorbars[i] === 'object' && !RG.isNull(errorbars[i])) {
|
3695
|
-
|
3696
|
-
var positiveLength = this.getYCoord(this.min) - this.getYCoord(this.min + errorbars[i][0]),
|
3697
|
-
negativeLength = this.getYCoord(this.min) - this.getYCoord(this.min + errorbars[i][1]);
|
3698
|
-
|
3699
|
-
|
3700
|
-
// Color
|
3701
|
-
if (typeof errorbars[i][2] === 'string') {
|
3702
|
-
color = errorbars[i][2];
|
3703
|
-
}
|
3704
|
-
|
3705
|
-
// Cap width
|
3706
|
-
halfwidth = typeof errorbars[i][4] === 'number' ? errorbars[i][4] / 2 : halfwidth;
|
3707
|
-
|
3708
|
-
|
3709
|
-
// Set the linewidth
|
3710
|
-
if (typeof errorbars[i] === 'object' && typeof errorbars[i][3] === 'number') {
|
3711
|
-
co.lineWidth = errorbars[i][3];
|
3712
|
-
} else if (typeof prop['chart.errorbars.linewidth'] === 'number') {
|
3713
|
-
co.lineWidth = prop['chart.errorbars.linewidth'];
|
3714
|
-
} else {
|
3715
|
-
co.lineWidth = 1;
|
3716
|
-
}
|
3717
|
-
|
3718
|
-
|
3719
|
-
if (!RG.isNull(errorbars[i][0])) {
|
3720
|
-
|
3721
|
-
pa2(
|
3722
|
-
co,
|
3723
|
-
'lc square b m % % l % % l % % m % % l % % s %',
|
3724
|
-
coords[i][0],
|
3725
|
-
coords[i][1],
|
3726
|
-
coords[i][0],
|
3727
|
-
coords[i][1] - positiveLength,
|
3728
|
-
coords[i][0] - halfwidth,
|
3729
|
-
ma.round(coords[i][1] - positiveLength),
|
3730
|
-
coords[i][0],
|
3731
|
-
ma.round(coords[i][1] - positiveLength),
|
3732
|
-
coords[i][0] + halfwidth,
|
3733
|
-
ma.round(coords[i][1] - positiveLength),
|
3734
|
-
color
|
3735
|
-
);
|
3736
|
-
}
|
3737
|
-
|
3738
|
-
if (typeof errorbars[i][1] === 'number') {
|
3739
|
-
|
3740
|
-
var negativeLength = ma.abs(this.getYCoord(errorbars[i][1]) - this.getYCoord(0));
|
3741
|
-
|
3742
|
-
pa2(
|
3743
|
-
co,
|
3744
|
-
'b m % % l % % l % % m % % l % % s %',
|
3745
|
-
coords[i][0],
|
3746
|
-
coords[i][1],
|
3747
|
-
coords[i][0],
|
3748
|
-
coords[i][1] + negativeLength,
|
3749
|
-
coords[i][0] - halfwidth,
|
3750
|
-
ma.round(coords[i][1] + negativeLength),
|
3751
|
-
coords[i][0],
|
3752
|
-
ma.round(coords[i][1] + negativeLength),
|
3753
|
-
coords[i][0] + halfwidth,
|
3754
|
-
ma.round(coords[i][1] + negativeLength),
|
3755
|
-
color
|
3756
|
-
);
|
3757
|
-
}
|
3758
|
-
}
|
3759
|
-
}
|
3760
|
-
|
3761
|
-
co.restore();
|
3762
|
-
};
|
3763
|
-
|
3764
|
-
|
3765
|
-
|
3766
|
-
|
3767
|
-
/**
|
3768
|
-
* Hides a line by setting the appropriate flag so that the .visible(index)
|
3769
|
-
* function returns the relevant result.
|
3770
|
-
*
|
3771
|
-
* @param int index The index of the line to hide
|
3772
|
-
*/
|
3773
|
-
this.hide = function ()
|
3774
|
-
{
|
3775
|
-
// Hide a single line
|
3776
|
-
if (typeof arguments[0] === 'number') {
|
3777
|
-
prop['chart.line.visible'][arguments[0]] = false;
|
3778
|
-
|
3779
|
-
// Hide multiple lines
|
3780
|
-
} else if (typeof arguments[0] === 'object') {
|
3781
|
-
for (var i=0; i<arguments[0].length; ++i) {
|
3782
|
-
prop['chart.line.visible'][arguments[0][i]] = false;
|
3783
|
-
}
|
3784
|
-
|
3785
|
-
// Hide all lines
|
3786
|
-
} else {
|
3787
|
-
for (var i=0; i<this.original_data.length; ++i) {
|
3788
|
-
prop['chart.line.visible'][i] = false;
|
3789
|
-
}
|
3790
|
-
}
|
3791
|
-
|
3792
|
-
RG.redraw();
|
3793
|
-
|
3794
|
-
// Facilitate chaining
|
3795
|
-
return this;
|
3796
|
-
};
|
3797
|
-
|
3798
|
-
|
3799
|
-
|
3800
|
-
|
3801
|
-
/**
|
3802
|
-
* Shows a line by setting the appropriate flag so that the .visible(index)
|
3803
|
-
* function returns the relevant result.
|
3804
|
-
*
|
3805
|
-
* @param int index The index of the line to show
|
3806
|
-
*/
|
3807
|
-
this.show = function ()
|
3808
|
-
{
|
3809
|
-
// Show a single line
|
3810
|
-
if (typeof arguments[0] === 'number') {
|
3811
|
-
prop['chart.line.visible'][arguments[0]] = true;
|
3812
|
-
|
3813
|
-
// Show multiple lines
|
3814
|
-
} else if (typeof arguments[0] === 'object') {
|
3815
|
-
for (var i=0; i<arguments[0].length; ++i) {
|
3816
|
-
prop['chart.line.visible'][arguments[0][i]] = true;
|
3817
|
-
}
|
3818
|
-
|
3819
|
-
// Show all lines
|
3820
|
-
} else {
|
3821
|
-
for (var i=0; i<this.original_data.length; ++i) {
|
3822
|
-
prop['chart.line.visible'][i] = true;
|
3823
|
-
}
|
3824
|
-
}
|
3825
|
-
|
3826
|
-
RG.redraw();
|
3827
|
-
|
3828
|
-
// Facilitate chaining
|
3829
|
-
return this;
|
3830
|
-
};
|
3831
|
-
|
3832
|
-
|
3833
|
-
|
3834
|
-
|
3835
|
-
/**
|
3836
|
-
* Returns true/false as to wether a line is hidden or not
|
3837
|
-
*
|
3838
|
-
* @param int index The index of the line to hide
|
3839
|
-
*/
|
3840
|
-
this.hidden = function (index)
|
3841
|
-
{
|
3842
|
-
return !prop['chart.line.visible'][index];
|
3843
|
-
};
|
3844
|
-
|
3845
|
-
|
3846
|
-
|
3847
|
-
/**
|
3848
|
-
* Unfold
|
3849
|
-
*
|
3850
|
-
* This effect gradually increases the X/Y coordinatesfrom 0
|
3851
|
-
*
|
3852
|
-
* @param object obj The chart object
|
3853
|
-
*/
|
3854
|
-
this.unfold = function ()
|
3855
|
-
{
|
3856
|
-
var obj = this;
|
3857
|
-
var opt = arguments[0] ? arguments[0] : {};
|
3858
|
-
var frames = opt.frames ? opt.frames : 30;
|
3859
|
-
var frame = 0;
|
3860
|
-
var callback = arguments[1] ? arguments[1] : function () {};
|
3861
|
-
var initial = prop['chart.animation.unfold.initial'];
|
3862
|
-
|
3863
|
-
prop['chart.animation.factor'] = prop['chart.animation.unfold.initial'];
|
3864
|
-
|
3865
|
-
function iterator ()
|
3866
|
-
{
|
3867
|
-
prop['chart.animation.factor'] = ((1 - initial) * (frame / frames)) + initial;
|
3868
|
-
|
3869
|
-
RG.clear(obj.canvas);
|
3870
|
-
RG.redrawCanvas(obj.canvas);
|
3871
|
-
|
3872
|
-
if (frame < frames) {
|
3873
|
-
frame++;
|
3874
|
-
RG.Effects.updateCanvas(iterator);
|
3875
|
-
} else {
|
3876
|
-
callback(obj);
|
3877
|
-
}
|
3878
|
-
}
|
3879
|
-
|
3880
|
-
|
3881
|
-
iterator();
|
3882
|
-
|
3883
|
-
return this;
|
3884
|
-
};
|
3885
|
-
|
3886
|
-
|
3887
|
-
|
3888
|
-
|
3889
|
-
/**
|
3890
|
-
* Trace2
|
3891
|
-
*
|
3892
|
-
* This is a new version of the Trace effect which no longer requires jQuery and is more compatible
|
3893
|
-
* with other effects (eg Expand). This new effect is considerably simpler and less code.
|
3894
|
-
*
|
3895
|
-
* @param object Options for the effect. Currently only "frames" is available.
|
3896
|
-
* @param int A function that is called when the ffect is complete
|
3897
|
-
*/
|
3898
|
-
this.trace =
|
3899
|
-
this.trace2 = function ()
|
3900
|
-
{
|
3901
|
-
var obj = this;
|
3902
|
-
var callback = arguments[2];
|
3903
|
-
var opt = arguments[0] || {};
|
3904
|
-
var frames = opt.frames || 30;
|
3905
|
-
var frame = 0;
|
3906
|
-
var callback = arguments[1] || function () {};
|
3907
|
-
|
3908
|
-
obj.Set('animation.trace.clip', 0);
|
3909
|
-
|
3910
|
-
function iterator ()
|
3911
|
-
{
|
3912
|
-
RG.clear(obj.canvas);
|
3913
|
-
|
3914
|
-
RG.redrawCanvas(obj.canvas);
|
3915
|
-
|
3916
|
-
if (frame++ < frames) {
|
3917
|
-
obj.Set('animation.trace.clip', frame / frames);
|
3918
|
-
RG.Effects.updateCanvas(iterator);
|
3919
|
-
} else {
|
3920
|
-
callback(obj);
|
3921
|
-
}
|
3922
|
-
}
|
3923
|
-
|
3924
|
-
iterator();
|
3925
|
-
|
3926
|
-
return this;
|
3927
|
-
};
|
3928
|
-
|
3929
|
-
|
3930
|
-
|
3931
|
-
|
3932
|
-
/**
|
3933
|
-
* FoldToCenter
|
3934
|
-
*
|
3935
|
-
* Line chart FoldTocenter
|
3936
|
-
*
|
3937
|
-
* @param object OPTIONAL An object map of options
|
3938
|
-
* @param function OPTIONAL A callback to run when the effect is complete
|
3939
|
-
*/
|
3940
|
-
this.foldtocenter =
|
3941
|
-
this.foldToCenter = function ()
|
3942
|
-
{
|
3943
|
-
var obj = this;
|
3944
|
-
var opt = arguments[0] || {};
|
3945
|
-
var frames = opt.frames || 30;
|
3946
|
-
var frame = 0;
|
3947
|
-
var callback = arguments[1] || function () {};
|
3948
|
-
var center_value = obj.scale2.max / 2;
|
3949
|
-
|
3950
|
-
obj.Set('chart.ymax', obj.scale2.max);
|
3951
|
-
|
3952
|
-
var original_data = RG.array_clone(obj.original_data);
|
3953
|
-
|
3954
|
-
function iterator ()
|
3955
|
-
{
|
3956
|
-
for (var i=0,len=obj.data.length; i<len; ++i) {
|
3957
|
-
if (obj.data[i].length) {
|
3958
|
-
for (var j=0,len2=obj.data[i].length; j<len2; ++j) {
|
3959
|
-
|
3960
|
-
var dataset = obj.original_data[i];
|
3961
|
-
|
3962
|
-
if (dataset[j] > center_value) {
|
3963
|
-
dataset[j] = original_data[i][j] - ((original_data[i][j] - center_value) * (frame / frames));
|
3964
|
-
} else {
|
3965
|
-
dataset[j] = original_data[i][j] + (((center_value - original_data[i][j]) / frames) * frame);
|
3966
|
-
}
|
3967
|
-
}
|
3968
|
-
}
|
3969
|
-
}
|
3970
|
-
|
3971
|
-
RG.clear(obj.canvas);
|
3972
|
-
RG.redrawCanvas(obj.canvas)
|
3973
|
-
|
3974
|
-
if (frame++ < frames) {
|
3975
|
-
RG.Effects.updateCanvas(iterator);
|
3976
|
-
} else {
|
3977
|
-
callback(obj);
|
3978
|
-
}
|
3979
|
-
}
|
3980
|
-
|
3981
|
-
|
3982
|
-
|
3983
|
-
iterator();
|
3984
|
-
|
3985
|
-
|
3986
|
-
|
3987
|
-
return this;
|
3988
|
-
};
|
3989
|
-
|
3990
|
-
|
3991
|
-
|
3992
|
-
|
3993
|
-
/**
|
3994
|
-
* UnfoldFromCenterTrace effect
|
3995
|
-
*
|
3996
|
-
* @param object An object containing options
|
3997
|
-
* @param function A callback function
|
3998
|
-
*/
|
3999
|
-
this.unfoldFromCenterTrace =
|
4000
|
-
this.unfoldFromCenterTrace2 = function ()
|
4001
|
-
{
|
4002
|
-
var obj = this,
|
4003
|
-
opt = arguments[0] || {},
|
4004
|
-
frames = opt.frames || 30,
|
4005
|
-
frame = 0,
|
4006
|
-
data = RG.arrayClone(obj.original_data),
|
4007
|
-
callback = arguments[1] || function () {};
|
4008
|
-
|
4009
|
-
|
4010
|
-
|
4011
|
-
// Draw the chart once to get the scale values
|
4012
|
-
obj.canvas.style.visibility = 'hidden';
|
4013
|
-
obj.draw();
|
4014
|
-
var max = obj.scale2.max;
|
4015
|
-
RG.clear(obj.canvas);
|
4016
|
-
obj.canvas.style.visibility = 'visible';
|
4017
|
-
|
4018
|
-
|
4019
|
-
|
4020
|
-
|
4021
|
-
/**
|
4022
|
-
* When the Trace function finishes it calls this function
|
4023
|
-
*/
|
4024
|
-
var unfoldCallback = function ()
|
4025
|
-
{
|
4026
|
-
obj.original_data = data;
|
4027
|
-
obj.unfoldFromCenter({frames: frames / 2}, callback);
|
4028
|
-
};
|
4029
|
-
|
4030
|
-
|
4031
|
-
|
4032
|
-
/**
|
4033
|
-
* Determine the mid-point
|
4034
|
-
*/
|
4035
|
-
var half = obj.Get('chart.xaxispos') == 'center' ? obj.min : ((obj.max - obj.min) / 2) + obj.min;
|
4036
|
-
obj.Set('chart.ymax', obj.max);
|
4037
|
-
|
4038
|
-
for (var i=0,len=obj.original_data.length; i<len; ++i) {
|
4039
|
-
for (var j=0; j<obj.original_data[i].length; ++j) {
|
4040
|
-
obj.original_data[i][j] = (obj.Get('chart.filled') && obj.Get('chart.filled.accumulative') && i > 0) ? 0 : half;
|
4041
|
-
}
|
4042
|
-
}
|
4043
|
-
|
4044
|
-
RG.clear(obj.canvas);
|
4045
|
-
obj.trace2({frames: frames / 2}, unfoldCallback);
|
4046
|
-
|
4047
|
-
return obj;
|
4048
|
-
};
|
4049
|
-
|
4050
|
-
|
4051
|
-
|
4052
|
-
|
4053
|
-
/**
|
4054
|
-
* UnfoldFromCenter
|
4055
|
-
*
|
4056
|
-
* Line chart unfold from center
|
4057
|
-
*
|
4058
|
-
* @param object An option map of properties. Only frames is supported: {frames: 30}
|
4059
|
-
* @param function An optional callback
|
4060
|
-
*/
|
4061
|
-
this.unfoldFromCenter = function ()
|
4062
|
-
{
|
4063
|
-
var obj = this;
|
4064
|
-
var opt = arguments[0] || {};
|
4065
|
-
var frames = opt.frames || 30;
|
4066
|
-
var frame = 0;
|
4067
|
-
var callback = arguments[1] || function () {};
|
4068
|
-
|
4069
|
-
// Draw the chart once to get the scale values
|
4070
|
-
obj.canvas.style.visibility = 'hidden';
|
4071
|
-
obj.Draw();
|
4072
|
-
var max = obj.scale2.max;
|
4073
|
-
RG.clear(obj.canvas);
|
4074
|
-
obj.canvas.style.visibility = 'visible';
|
4075
|
-
|
4076
|
-
var center_value = obj.Get('chart.xaxispos') === 'center' ? prop['chart.ymin'] : ((obj.max - obj.min) / 2) + obj.min;
|
4077
|
-
var original_data = RG.array_clone(obj.original_data);
|
4078
|
-
var steps = null;
|
4079
|
-
|
4080
|
-
obj.Set('chart.ymax', max);
|
4081
|
-
|
4082
|
-
if (!steps) {
|
4083
|
-
|
4084
|
-
steps = [];
|
4085
|
-
|
4086
|
-
for (var dataset=0,len=original_data.length; dataset<len; ++dataset) {
|
4087
|
-
|
4088
|
-
steps[dataset] = []
|
4089
|
-
|
4090
|
-
for (var i=0,len2=original_data[dataset].length; i<len2; ++i) {
|
4091
|
-
if (prop['chart.filled'] && prop['chart.filled.accumulative'] && dataset > 0) {
|
4092
|
-
steps[dataset][i] = original_data[dataset][i] / frames;
|
4093
|
-
obj.original_data[dataset][i] = center_value;
|
4094
|
-
} else {
|
4095
|
-
steps[dataset][i] = (original_data[dataset][i] - center_value) / frames;
|
4096
|
-
obj.original_data[dataset][i] = center_value;
|
4097
|
-
}
|
4098
|
-
}
|
4099
|
-
}
|
4100
|
-
}
|
4101
|
-
|
4102
|
-
function unfoldFromCenter ()
|
4103
|
-
{
|
4104
|
-
for (var dataset=0; dataset<original_data.length; ++dataset) {
|
4105
|
-
for (var i=0; i<original_data[dataset].length; ++i) {
|
4106
|
-
obj.original_data[dataset][i] += steps[dataset][i];
|
4107
|
-
}
|
4108
|
-
}
|
4109
|
-
|
4110
|
-
RG.clear(obj.canvas);
|
4111
|
-
RG.redrawCanvas(obj.canvas);
|
4112
|
-
|
4113
|
-
if (--frames > 0) {
|
4114
|
-
RG.Effects.updateCanvas(unfoldFromCenter);
|
4115
|
-
} else {
|
4116
|
-
obj.original_data = RG.array_clone(original_data);
|
4117
|
-
RG.clear(obj.canvas);
|
4118
|
-
RG.redrawCanvas(obj.canvas);
|
4119
|
-
|
4120
|
-
callback(obj);
|
4121
|
-
}
|
4122
|
-
}
|
4123
|
-
|
4124
|
-
unfoldFromCenter();
|
4125
|
-
|
4126
|
-
return this;
|
4127
|
-
};
|
4128
|
-
|
4129
|
-
|
4130
|
-
|
4131
|
-
|
4132
|
-
|
4133
|
-
|
4134
|
-
|
4135
|
-
|
4136
|
-
RG.att(ca);
|
4137
|
-
|
4138
|
-
|
4139
|
-
|
4140
|
-
|
4141
|
-
/**
|
4142
|
-
* Register the object so it is redrawn when necessary
|
4143
|
-
*/
|
4144
|
-
RG.Register(this);
|
4145
|
-
|
4146
|
-
|
4147
|
-
|
4148
|
-
|
4149
|
-
/**
|
4150
|
-
* This is the 'end' of the constructor so if the first argument
|
4151
|
-
* contains configuration data - handle that.
|
4152
|
-
*/
|
4153
|
-
if (parseConfObjectForOptions) {
|
4154
|
-
RG.parseObjectStyleConfig(this, conf.options);
|
4155
|
-
}
|
4156
|
-
|
4157
|
-
/**
|
4158
|
-
* Allow all lines to start off as visible
|
4159
|
-
*/
|
4160
|
-
for (var i=0; i<this.original_data.length; ++i) {
|
4161
|
-
prop['chart.line.visible'][i] = true;
|
4162
|
-
}
|
4163
|
-
};
|
2
|
+
RGraph=window.RGraph||{isRGraph:true};RGraph.Line=function(conf)
|
3
|
+
{if(typeof conf==='object'&&typeof conf.data==='object'&&typeof conf.id==='string'){var id=conf.id;var canvas=document.getElementById(id);var data=conf.data;var parseConfObjectForOptions=true;}else{var id=conf;var canvas=document.getElementById(id);var data=arguments[1];}
|
4
|
+
this.id=id;this.canvas=canvas;this.context=this.canvas.getContext('2d');this.canvas.__object__=this;this.type='line';this.max=0;this.coords=[];this.coords2=[];this.coords.key=[];this.coordsText=[];this.coordsSpline=[];this.coordsAxes={xaxis:[],yaxis:[]};this.hasnegativevalues=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.firstDraw=true;this.properties={'chart.background.barcolor1':'rgba(0,0,0,0)','chart.background.barcolor2':'rgba(0,0,0,0)','chart.background.grid':1,'chart.background.grid.width':1,'chart.background.grid.hsize':25,'chart.background.grid.vsize':25,'chart.background.grid.color':'#ddd','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':null,'chart.background.grid.dashed':false,'chart.background.grid.dotted':false,'chart.background.hbars':null,'chart.background.image':null,'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.labels':null,'chart.labels.bold':false,'chart.labels.color':null,'chart.labels.ingraph':null,'chart.labels.above':false,'chart.labels.above.size':8,'chart.labels.above.decimals':null,'chart.labels.above.color':null,'chart.labels.above.background':'white','chart.labels.above.font':null,'chart.labels.above.border':true,'chart.labels.above.offsety':5,'chart.labels.above.units.pre':'','chart.labels.above.units.post':'','chart.labels.above.specific':null,'chart.labels.offsetx':0,'chart.labels.offsety':0,'chart.xtickgap':20,'chart.smallxticks':3,'chart.largexticks':5,'chart.ytickgap':20,'chart.smallyticks':3,'chart.largeyticks':5,'chart.numyticks':10,'chart.linewidth':2.01,'chart.colors':['red','#0f0','#00f','#f0f','#ff0','#0ff','green','pink','blue','black'],'chart.hmargin':0,'chart.tickmarks.dot.stroke':'white','chart.tickmarks.dot.fill':null,'chart.tickmarks.dot.linewidth':3,'chart.tickmarks':'endcircle','chart.tickmarks.linewidth':null,'chart.tickmarks.image':null,'chart.tickmarks.image.halign':'center','chart.tickmarks.image.valign':'center','chart.tickmarks.image.offsetx':0,'chart.tickmarks.image.offsety':0,'chart.ticksize':3,'chart.gutter.left':25,'chart.gutter.right':25,'chart.gutter.top':25,'chart.gutter.bottom':30,'chart.tickdirection':-1,'chart.yaxispoints':5,'chart.fillstyle':null,'chart.xaxispos':'bottom','chart.xaxispos.value':0,'chart.yaxispos':'left','chart.xticks':null,'chart.text.size':12,'chart.text.angle':0,'chart.text.color':'black','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.background':null,'chart.title.hpos':null,'chart.title.vpos':null,'chart.title.bold':true,'chart.title.font':null,'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.shadow':true,'chart.shadow.offsetx':2,'chart.shadow.offsety':2,'chart.shadow.blur':3,'chart.shadow.color':'rgba(128,128,128,0.5)','chart.tooltips':null,'chart.tooltips.hotspot.xonly':false,'chart.tooltips.hotspot.size':5,'chart.tooltips.effect':'fade','chart.tooltips.css.class':'RGraph_tooltip','chart.tooltips.event':'onmousemove','chart.tooltips.highlight':true,'chart.tooltips.coords.page':false,'chart.highlight.style':null,'chart.highlight.stroke':'gray','chart.highlight.fill':'white','chart.stepped':false,'chart.key':null,'chart.key.background':'white','chart.key.position':'graph','chart.key.halign':null,'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.color.shape':'square','chart.key.rounded':true,'chart.key.linewidth':1,'chart.key.colors':null,'chart.key.interactive':false,'chart.key.interactive.highlight.chart.stroke':'rgba(255,0,0,0.3)','chart.key.interactive.highlight.label':'rgba(255,0,0,0.2)','chart.key.text.color':'black','chart.contextmenu':null,'chart.ylabels':true,'chart.ylabels.count':5,'chart.ylabels.inside':false,'chart.ylabels.offsetx':0,'chart.ylabels.offsety':0,'chart.scale.invert':false,'chart.xlabels.inside':false,'chart.xlabels.inside.color':'rgba(255,255,255,0.5)','chart.noaxes':false,'chart.noyaxis':false,'chart.noxaxis':false,'chart.noendxtick':false,'chart.noendytick':false,'chart.units.post':'','chart.units.pre':'','chart.scale.zerostart':true,'chart.scale.decimals':null,'chart.scale.point':'.','chart.scale.thousand':',','chart.crosshairs':false,'chart.crosshairs.color':'#333','chart.crosshairs.hline':true,'chart.crosshairs.vline':true,'chart.annotatable':false,'chart.annotate.color':'black','chart.axesontop':false,'chart.filled':false,'chart.filled.range':false,'chart.filled.range.threshold':null,'chart.filled.range.threshold.colors':['red','green'],'chart.filled.accumulative':true,'chart.variant':null,'chart.axis.color':'black','chart.axis.linewidth':1,'chart.numxticks':(data&&typeof(data[0])=='number'?data.length-1:(typeof data[0]==='object'&&data[0]&&typeof data[0][0]==='number'?data[0].length-1:20)),'chart.numyticks':10,'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.zoom.action':'zoom','chart.backdrop':false,'chart.backdrop.size':30,'chart.backdrop.alpha':0.2,'chart.resizable':false,'chart.resize.handle.adjust':[0,0],'chart.resize.handle.background':null,'chart.adjustable':false,'chart.noredraw':false,'chart.outofbounds':false,'chart.outofbounds.clip':false,'chart.chromefix':true,'chart.animation.factor':1,'chart.animation.unfold.x':false,'chart.animation.unfold.y':true,'chart.animation.unfold.initial':2,'chart.animation.trace.clip':1,'chart.curvy':false,'chart.line.visible':[],'chart.events.click':null,'chart.events.mousemove':null,'chart.errorbars':false,'chart.errorbars.color':'black','chart.errorbars.capped':true,'chart.errorbars.capped.width':12,'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
|
+
for(var i=1;i<arguments.length;++i){if(typeof(arguments[i])=='null'||!arguments[i]){arguments[i]=[];}}
|
6
|
+
this.original_data=[];if(typeof conf==='object'&&conf.data){if(typeof conf.data[0]==='number'||RGraph.isNull(conf.data[0])){this.original_data[0]=RGraph.arrayClone(conf.data);}else{for(var i=0;i<conf.data.length;++i){this.original_data[i]=RGraph.arrayClone(conf.data[i]);}}}else{for(var i=1;i<arguments.length;++i){if(arguments[1]&&typeof(arguments[1])=='object'&&arguments[1][0]&&typeof(arguments[1][0])=='object'&&arguments[1][0].length){var tmp=[];for(var i=0;i<arguments[1].length;++i){tmp[i]=RGraph.array_clone(arguments[1][i]);}
|
7
|
+
for(var j=0;j<tmp.length;++j){this.original_data[j]=RGraph.array_clone(tmp[j]);}}else{this.original_data[i-1]=RGraph.array_clone(arguments[i]);}}}
|
8
|
+
if(!this.canvas){alert('[LINE] Fatal error: no canvas support');return;}
|
9
|
+
for(var i=0;i<this.original_data.length;++i){for(var j=0;j<this.original_data[i].length;++j){if(typeof this.original_data[i][j]==='string'){this.original_data[i][j]=parseFloat(this.original_data[i][j]);}}}
|
10
|
+
this.data_arr=RGraph.arrayLinearize(this.original_data);for(var i=0;i<this.data_arr.length;++i){this['$'+i]={};}
|
11
|
+
if(!this.canvas.__rgraph_aa_translated__){this.context.translate(0.5,0.5);this.canvas.__rgraph_aa_translated__=true;}
|
12
|
+
var RG=RGraph,ca=this.canvas,co=ca.getContext('2d'),prop=this.properties,pa2=RG.path2,win=window,doc=document,ma=Math
|
13
|
+
if(RG.Effects&&typeof RG.Effects.decorate==='function'){RG.Effects.decorate(this);}
|
14
|
+
this.set=this.Set=function(name)
|
15
|
+
{var value=typeof arguments[1]==='undefined'?null:arguments[1];if(arguments.length===1&&typeof name==='object'){RG.parseObjectStyleConfig(this,name);return this;}
|
16
|
+
if(name.substr(0,6)!='chart.'){name='chart.'+name;}
|
17
|
+
while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
|
18
|
+
if(name=='chart.tooltips'&&typeof value=='object'&&value){var tooltips=[];for(var i=1;i<arguments.length;i++){if(typeof(arguments[i])=='object'&&arguments[i][0]){for(var j=0;j<arguments[i].length;j++){tooltips.push(arguments[i][j]);}}else if(typeof(arguments[i])=='function'){tooltips=arguments[i];}else{tooltips.push(arguments[i]);}}
|
19
|
+
value=tooltips;}
|
20
|
+
if(name=='chart.linewidth'&&navigator.userAgent.match(/Chrome/)){if(value==1){value=1.01;}else if(RGraph.is_array(value)){for(var i=0;i<value.length;++i){if(typeof(value[i])=='number'&&value[i]==1){value[i]=1.01;}}}}
|
21
|
+
if(name=='chart.xaxispos'){if(value!='bottom'&&value!='center'&&value!='top'){alert('[LINE] ('+this.id+') chart.xaxispos should be top, center or bottom. Tried to set it to: '+value+' Changing it to center');value='center';}}
|
22
|
+
if(name=='chart.xticks'){name='chart.numxticks';}
|
23
|
+
if(name=='chart.spline'){name='chart.curvy';}
|
24
|
+
if(name=='chart.ylabels.invert'){name='chart.scale.invert';}
|
25
|
+
this.properties[name]=value;return this;};this.get=this.Get=function(name)
|
26
|
+
{if(name.substr(0,6)!='chart.'){name='chart.'+name;}
|
27
|
+
while(name.match(/([A-Z])/)){name=name.replace(/([A-Z])/,'.'+RegExp.$1.toLowerCase());}
|
28
|
+
if(name=='chart.spline'){name='chart.curvy';}
|
29
|
+
return prop[name];};this.draw=this.Draw=function()
|
30
|
+
{if(typeof(prop['chart.background.image'])=='string'){RG.DrawBackgroundImage(this);}
|
31
|
+
RG.FireCustomEvent(this,'onbeforedraw');if(!this.colorsParsed){this.parseColors();this.colorsParsed=true;}
|
32
|
+
this.gutterLeft=prop['chart.gutter.left'];this.gutterRight=prop['chart.gutter.right'];this.gutterTop=prop['chart.gutter.top'];this.gutterBottom=prop['chart.gutter.bottom'];this.data=RG.array_clone(this.original_data);this.max=0;if(prop['chart.filled']&&!prop['chart.filled.range']&&this.data.length>1&&prop['chart.filled.accumulative']){var accumulation=[];for(var set=0;set<this.data.length;++set){for(var point=0;point<this.data[set].length;++point){this.data[set][point]=Number(accumulation[point]?accumulation[point]:0)+this.data[set][point];accumulation[point]=this.data[set][point];}}}
|
33
|
+
if(prop['chart.ymax']){this.max=prop['chart.ymax'];this.min=prop['chart.ymin']?prop['chart.ymin']:0;this.scale2=RG.getScale2(this,{'max':this.max,'min':prop['chart.ymin'],'strict':true,'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?this.scale2.max:0;if(!prop['chart.outofbounds']){for(dataset=0;dataset<this.data.length;++dataset){if(RGraph.isArray(this.data[dataset])){for(var datapoint=0;datapoint<this.data[dataset].length;datapoint++){this.hasnegativevalues=(this.data[dataset][datapoint]<0)||this.hasnegativevalues;}}}}}else{this.min=prop['chart.ymin']?prop['chart.ymin']:0;for(dataset=0;dataset<this.data.length;++dataset){for(var datapoint=0;datapoint<this.data[dataset].length;datapoint++){this.max=Math.max(this.max,this.data[dataset][datapoint]?Math.abs(parseFloat(this.data[dataset][datapoint])):0);if(!prop['chart.outofbounds']){this.hasnegativevalues=(this.data[dataset][datapoint]<0)||this.hasnegativevalues;}}}
|
34
|
+
this.scale2=RG.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?this.scale2.max:0;}
|
35
|
+
if(prop['chart.contextmenu']){RG.ShowContext(this);}
|
36
|
+
this.coords=[];this.coordsText=[];this.grapharea=ca.height-this.gutterTop-this.gutterBottom;this.halfgrapharea=this.grapharea/2;this.halfTextHeight=prop['chart.text.size']/2;if(prop['chart.variant']=='3d'){RG.Draw3DAxes(this);}
|
37
|
+
RG.background.Draw(this);if(prop['chart.background.hbars']&&prop['chart.background.hbars'].length>0){RG.DrawBars(this);}
|
38
|
+
if(prop['chart.axesontop']==false){this.DrawAxes();}
|
39
|
+
co.save()
|
40
|
+
co.beginPath();co.rect(0,0,ca.width*prop['chart.animation.trace.clip'],ca.height);co.clip();for(var i=0,j=0,len=this.data.length;i<len;i++,j++){co.beginPath();if(!prop['chart.filled']){this.SetShadow(i);}
|
41
|
+
if(prop['chart.fillstyle']){if(typeof(prop['chart.fillstyle'])=='object'&&prop['chart.fillstyle'][j]){var fill=prop['chart.fillstyle'][j];}else if(typeof(prop['chart.fillstyle'])=='object'&&prop['chart.fillstyle'].toString().indexOf('Gradient')>0){var fill=prop['chart.fillstyle'];}else if(typeof(prop['chart.fillstyle'])=='string'){var fill=prop['chart.fillstyle'];}}else if(prop['chart.filled']){var fill=prop['chart.colors'][j];}else{var fill=null;}
|
42
|
+
if(prop['chart.tickmarks']&&typeof(prop['chart.tickmarks'])=='object'){var tickmarks=prop['chart.tickmarks'][i];}else if(prop['chart.tickmarks']&&typeof(prop['chart.tickmarks'])=='string'){var tickmarks=prop['chart.tickmarks'];}else if(prop['chart.tickmarks']&&typeof(prop['chart.tickmarks'])=='function'){var tickmarks=prop['chart.tickmarks'];}else{var tickmarks=null;}
|
43
|
+
if(prop['chart.outofbounds.clip']){pa2(co,'sa b r % % % % cl b',0,this.gutterTop,ca.width,ca.height-this.gutterTop-this.gutterBottom);}
|
44
|
+
this.drawLine(this.data[i],prop['chart.colors'][j],fill,this.getLineWidth(j),tickmarks,i);if(prop['chart.outofbounds.clip']){co.restore();}
|
45
|
+
co.stroke();}
|
46
|
+
if(prop['chart.filled']&&prop['chart.filled.accumulative']&&!prop['chart.curvy']){for(var i=0;i<this.coords2.length;++i){co.beginPath();co.lineWidth=this.GetLineWidth(i);co.strokeStyle=!this.hidden(i)?prop['chart.colors'][i]:'rgba(0,0,0,0)';for(var j=0,len=this.coords2[i].length;j<len;++j){if(j==0||this.coords2[i][j][1]==null||(this.coords2[i][j-1]&&this.coords2[i][j-1][1]==null)){co.moveTo(this.coords2[i][j][0],this.coords2[i][j][1]);}else{if(prop['chart.stepped']){co.lineTo(this.coords2[i][j][0],this.coords2[i][j-1][1]);}
|
47
|
+
co.lineTo(this.coords2[i][j][0],this.coords2[i][j][1]);}}
|
48
|
+
co.stroke();}
|
49
|
+
if(prop['chart.tickmarks']){co.beginPath();co.fillStyle='white';for(var i=0,len=this.coords2.length;i<len;++i){co.beginPath();co.strokeStyle=prop['chart.colors'][i];for(var j=0;j<this.coords2[i].length;++j){if(typeof(this.coords2[i][j])=='object'&&typeof(this.coords2[i][j][0])=='number'&&typeof(this.coords2[i][j][1])=='number'){var tickmarks=typeof(prop['chart.tickmarks'])=='object'?prop['chart.tickmarks'][i]:prop['chart.tickmarks'];this.DrawTick(this.coords2[i],this.coords2[i][j][0],this.coords2[i][j][1],co.strokeStyle,false,j==0?0:this.coords2[i][j-1][0],j==0?0:this.coords2[i][j-1][1],tickmarks,j,i);}}}
|
50
|
+
co.stroke();co.fill();}}else if(prop['chart.filled']&&prop['chart.filled.accumulative']&&prop['chart.curvy']){for(var i=0;i<this.coordsSpline.length;i+=1){co.beginPath();co.strokeStyle=prop['chart.colors'][i];co.lineWidth=this.GetLineWidth(i);for(var j=0,len=this.coordsSpline[i].length;j<len;j+=1){var point=this.coordsSpline[i][j];j==0?co.moveTo(point[0],point[1]):co.lineTo(point[0],point[1]);}
|
51
|
+
co.stroke();}
|
52
|
+
for(var i=0,len=this.coords2.length;i<len;i+=1){for(var j=0,len2=this.coords2[i].length;j<len2;++j){if(typeof(this.coords2[i][j])=='object'&&typeof(this.coords2[i][j][0])=='number'&&typeof(this.coords2[i][j][1])=='number'){var tickmarks=typeof prop['chart.tickmarks']=='object'&&!RGraph.is_null(prop['chart.tickmarks'])?prop['chart.tickmarks'][i]:prop['chart.tickmarks'];co.strokeStyle=prop['chart.colors'][i];this.DrawTick(this.coords2[i],this.coords2[i][j][0],this.coords2[i][j][1],prop['chart.colors'][i],false,j==0?0:this.coords2[i][j-1][0],j==0?0:this.coords2[i][j-1][1],tickmarks,j,i);}}}}
|
53
|
+
co.restore();co.beginPath();if(prop['chart.axesontop']){this.DrawAxes();}
|
54
|
+
this.DrawLabels();this.DrawRange();if(prop['chart.key']&&prop['chart.key'].length&&RG.DrawKey){RG.DrawKey(this,prop['chart.key'],prop['chart.colors']);}
|
55
|
+
if(prop['chart.labels.above']){this.drawAboveLabels();}
|
56
|
+
RG.DrawInGraphLabels(this);if(prop['chart.filled']&&prop['chart.filled.range']&&this.data.length==2){co.beginPath();var len=this.coords.length/2;co.lineWidth=prop['chart.linewidth'];co.strokeStyle=this.hidden(0)?'rgba(0,0,0,0)':prop['chart.colors'][0];for(var i=0;i<len;++i){if(!RG.isNull(this.coords[i][1])){if(i==0){co.moveTo(this.coords[i][0],this.coords[i][1]);}else{co.lineTo(this.coords[i][0],this.coords[i][1]);}}}
|
57
|
+
co.stroke();co.beginPath();if(prop['chart.colors'][1]){co.strokeStyle=this.hidden(1)?'rgba(0,0,0,0)':prop['chart.colors'][1];}
|
58
|
+
for(var i=this.coords.length-1;i>=len;--i){if(!RG.is_null(this.coords[i][1])){if(i==(this.coords.length-1)){co.moveTo(this.coords[i][0],this.coords[i][1]);}else{co.lineTo(this.coords[i][0],this.coords[i][1]);}}}
|
59
|
+
co.stroke();}else if(prop['chart.filled']&&prop['chart.filled.range']){alert('[LINE] You must have only two sets of data for a filled range chart');}
|
60
|
+
if(prop['chart.resizable']){RG.AllowResizing(this);}
|
61
|
+
RG.InstallEventListeners(this);if(this.firstDraw){RG.fireCustomEvent(this,'onfirstdraw');this.firstDraw=false;this.firstDrawFunc();}
|
62
|
+
RG.FireCustomEvent(this,'ondraw');return this;};this.exec=function(func)
|
63
|
+
{func(this);return this;};this.drawAxes=this.DrawAxes=function()
|
64
|
+
{if(prop['chart.noaxes']){return;}
|
65
|
+
RG.noShadow(this);co.lineWidth=prop['chart.axis.linewidth']+0.001;co.lineCap='square';co.lineJoin='miter';co.strokeStyle=prop['chart.axis.color'];coords={xaxis:{},yaxis:{}};co.beginPath();if(prop['chart.noxaxis']==false){if(prop['chart.xaxispos']=='center'){coords.xaxis=[this.gutterLeft,ma.round((this.grapharea/2)+this.gutterTop),ca.width-this.gutterRight,ma.round((this.grapharea/2)+this.gutterTop)];}else if(prop['chart.xaxispos']==='top'){coords.xaxis=[this.gutterLeft,this.gutterTop,ca.width-this.gutterRight,this.gutterTop];}else{var y=ma.round(this.getYCoord(prop['chart.ymin']!=0?prop['chart.ymin']:0));if(prop['chart.scale.invert']&&prop['chart.ymin']===0){y=this.getYCoord(this.scale2.max);}else if(prop['chart.scale.invert']||prop['chart.ymin']<0){y=this.getYCoord(0);}
|
66
|
+
coords.xaxis=[this.gutterLeft,y,ca.width-this.gutterRight,y];}
|
67
|
+
co.moveTo(coords.xaxis[0],coords.xaxis[1]);co.lineTo(coords.xaxis[2],coords.xaxis[3]);this.coordsAxes=coords;}
|
68
|
+
if(prop['chart.noyaxis']==false){if(prop['chart.yaxispos']=='left'){co.moveTo(this.gutterLeft,this.gutterTop);co.lineTo(this.gutterLeft,ca.height-this.gutterBottom);}else{co.moveTo(ca.width-this.gutterRight,this.gutterTop);co.lineTo(ca.width-this.gutterRight,ca.height-this.gutterBottom);}}
|
69
|
+
if(prop['chart.noxaxis']==false&&prop['chart.numxticks']>0){var xTickInterval=(ca.width-this.gutterLeft-this.gutterRight)/prop['chart.numxticks'];if(!xTickInterval||xTickInterval<=0){xTickInterval=(ca.width-this.gutterLeft-this.gutterRight)/(prop['chart.labels']&&prop['chart.labels'].length?prop['chart.labels'].length-1:10);}
|
70
|
+
for(x=this.gutterLeft+(prop['chart.yaxispos']=='left'?xTickInterval:0);x<=(ca.width-this.gutterRight+1);x+=xTickInterval){if(prop['chart.yaxispos']=='right'&&x>=(ca.width-this.gutterRight-1)){break;}
|
71
|
+
if(prop['chart.noendxtick']){if(prop['chart.yaxispos']=='left'&&x>=(ca.width-this.gutterRight-1)){break;}else if(prop['chart.yaxispos']=='right'&&x==this.gutterLeft){continue;}}
|
72
|
+
var yStart=prop['chart.xaxispos']==='center'?(this.gutterTop+(this.grapharea/2))-3:ca.height-this.gutterBottom;var yEnd=prop['chart.xaxispos']==='center'?yStart+6:ca.height-this.gutterBottom-(x%60==0?prop['chart.largexticks']*prop['chart.tickdirection']:prop['chart.smallxticks']*prop['chart.tickdirection']);if(prop['chart.ymin']>=0&&prop['chart.xaxispos']==='bottom'){var yStart=this.getYCoord(prop['chart.ymin'])-(prop['chart.ymin']>=0?0:3),yEnd=this.getYCoord(prop['chart.ymin'])+3;if(prop['chart.scale.invert']){yStart=ca.height-prop['chart.gutter.bottom'];yEnd=yStart+3;}}else if(prop['chart.xaxispos']=='center'){var yStart=Math.round((this.gutterTop+(this.grapharea/2)))-3,yEnd=yStart+6;}else if(prop['chart.xaxispos']=='bottom'){var yStart=this.getYCoord(0)-(prop['chart.ymin']!==0?3:0),yEnd=this.getYCoord(0)-(x%60==0?prop['chart.largexticks']*prop['chart.tickdirection']:prop['chart.smallxticks']*prop['chart.tickdirection']);yEnd+=0;}else if(prop['chart.xaxispos']=='top'){yStart=this.gutterTop-3;yEnd=this.gutterTop;}
|
73
|
+
co.moveTo(ma.round(x),yStart);co.lineTo(ma.round(x),yEnd);}}else if(prop['chart.noyaxis']==false&&prop['chart.numyticks']>0){if(!prop['chart.noendytick']){if(prop['chart.yaxispos']=='left'){co.moveTo(this.gutterLeft,Math.round(ca.height-this.gutterBottom));co.lineTo(this.gutterLeft-prop['chart.smallyticks'],Math.round(ca.height-this.gutterBottom));}else{co.moveTo(ca.width-this.gutterRight,Math.round(ca.height-this.gutterBottom));co.lineTo(ca.width-this.gutterRight+prop['chart.smallyticks'],Math.round(ca.height-this.gutterBottom));}}}
|
74
|
+
var numyticks=prop['chart.numyticks'];if(prop['chart.noyaxis']==false&&numyticks>0){var counter=0,adjustment=0;if(prop['chart.yaxispos']=='right'){adjustment=(ca.width-this.gutterLeft-this.gutterRight);}
|
75
|
+
if(prop['chart.xaxispos']=='center'){var interval=(this.grapharea/numyticks);var lineto=(prop['chart.yaxispos']=='left'?this.gutterLeft:ca.width-this.gutterRight+prop['chart.smallyticks']);for(y=this.gutterTop;y<(this.grapharea/2)+this.gutterTop;y+=interval){if(y<(this.grapharea/2)+this.gutterTop){co.moveTo((prop['chart.yaxispos']=='left'?this.gutterLeft-prop['chart.smallyticks']:ca.width-this.gutterRight),Math.round(y));co.lineTo(lineto,Math.round(y));}}
|
76
|
+
for(y=this.gutterTop+(this.halfgrapharea)+interval;y<=this.grapharea+this.gutterTop;y+=interval){co.moveTo((prop['chart.yaxispos']=='left'?this.gutterLeft-prop['chart.smallyticks']:ca.width-this.gutterRight),Math.round(y));co.lineTo(lineto,Math.round(y));}}else if(prop['chart.xaxispos']=='top'){var interval=(this.grapharea/numyticks);var lineto=(prop['chart.yaxispos']=='left'?this.gutterLeft:ca.width-this.gutterRight+prop['chart.smallyticks']);for(y=this.gutterTop+interval;y<=this.grapharea+this.gutterBottom;y+=interval){co.moveTo((prop['chart.yaxispos']=='left'?this.gutterLeft-prop['chart.smallyticks']:ca.width-this.gutterRight),Math.round(y));co.lineTo(lineto,Math.round(y));}
|
77
|
+
if(prop['chart.noxaxis']&&prop['chart.noendytick']==false){co.moveTo((prop['chart.yaxispos']=='left'?this.gutterLeft-prop['chart.smallyticks']:ca.width-this.gutterRight),this.gutterTop);co.lineTo(lineto,this.gutterTop);}}else{var lineto=(prop['chart.yaxispos']=='left'?this.gutterLeft-prop['chart.smallyticks']:ca.width-this.gutterRight+prop['chart.smallyticks']);for(y=this.gutterTop;y<(ca.height-this.gutterBottom)&&counter<numyticks;y+=((ca.height-this.gutterTop-this.gutterBottom)/numyticks)){if(ma.round(y)!==ma.round(this.coordsAxes.xaxis[1])){co.moveTo(this.gutterLeft+adjustment,ma.round(y));co.lineTo(lineto,ma.round(y));}
|
78
|
+
var counter=counter+1;}
|
79
|
+
if(prop['chart.ymin']<0){co.moveTo((prop['chart.yaxispos']=='left'?this.gutterLeft:ca.width-this.gutterRight),ma.round(y));co.lineTo(lineto,ma.round(y));}}}else if(prop['chart.noxaxis']==false&&prop['chart.numxticks']>0){if(prop['chart.yaxispos']=='left'){co.moveTo(this.gutterLeft,prop['chart.xaxispos']=='top'?this.gutterTop:ca.height-this.gutterBottom);co.lineTo(this.gutterLeft,prop['chart.xaxispos']=='top'?this.gutterTop-prop['chart.smallxticks']:ca.height-this.gutterBottom+prop['chart.smallxticks']);}else{co.moveTo(ca.width-this.gutterRight,ca.height-this.gutterBottom);co.lineTo(ca.width-this.gutterRight,ca.height-this.gutterBottom+prop['chart.smallxticks']);}}
|
80
|
+
co.stroke();co.beginPath();};this.drawLabels=this.DrawLabels=function()
|
81
|
+
{co.strokeStyle='black';co.fillStyle=prop['chart.text.color'];co.lineWidth=1;RG.NoShadow(this);var font=prop['chart.text.font'];var text_size=prop['chart.text.size'];var decimals=prop['chart.scale.decimals'];var context=co;var canvas=ca;var ymin=prop['chart.ymin'];if(prop['chart.ylabels']&&prop['chart.ylabels.specific']==null){var units_pre=prop['chart.units.pre'];var units_post=prop['chart.units.post'];var xpos=prop['chart.yaxispos']=='left'?this.gutterLeft-5:ca.width-this.gutterRight+5;var align=prop['chart.yaxispos']=='left'?'right':'left';var numYLabels=this.scale2.labels.length;var bounding=false;var bgcolor=prop['chart.ylabels.inside']?prop['chart.ylabels.inside.color']:null;var offsetx=prop['chart.ylabels.offsetx'];var offsety=prop['chart.ylabels.offsety'];if(prop['chart.ylabels.inside']==true&&align=='left'){xpos-=10;align='right';bounding=true;}else if(prop['chart.ylabels.inside']==true&&align=='right'){xpos+=10;align='left';bounding=true;}
|
82
|
+
if(prop['chart.xaxispos']=='center'){var half=this.grapharea/2;for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+half-(((i+1)/numYLabels)*half)+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'text':this.scale2.labels[i],'tag':'scale'});}
|
83
|
+
for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+half+(((i+1)/numYLabels)*half)+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'text':'-'+this.scale2.labels[i],'tag':'scale'});}
|
84
|
+
if(prop['chart.noxaxis']==true||ymin!=0||prop['chart.scale.zerostart']){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+half+offsety,'text':prop['chart.units.pre']+ymin.toFixed(ymin===0?0:decimals)+prop['chart.units.post'],'bounding':bounding,'boundingFill':bgcolor,'valign':'center','halign':align,'tag':'scale'});}}else if(prop['chart.xaxispos']=='top'){var half=this.grapharea/2;if(prop['chart.scale.invert']){for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+((i/this.scale2.labels.length)*this.grapharea)+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'text':'-'+this.scale2.labels[this.scale2.labels.length-(i+1)],'tag':'scale'});}}else{for(var i=0;i<this.scale2.labels.length;++i){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+(((i+1)/numYLabels)*this.grapharea)+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'text':'-'+this.scale2.labels[i],'tag':'scale'});}}
|
85
|
+
if((prop['chart.ymin']!=0||prop['chart.noxaxis'])||prop['chart.scale.invert']||prop['chart.scale.zerostart']){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':prop['chart.scale.invert']?ca.height-this.gutterBottom+offsety:this.gutterTop+offsety,'text':(prop['chart.ymin']!=0?'-':'')+RG.numberFormat(this,prop['chart.ymin'].toFixed(ymin===0?0:decimals),units_pre,units_post),'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'tag':'scale'});}}else{if(prop['chart.scale.invert']){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'text':RG.numberFormat(this,this.min.toFixed(prop['chart.ymin']===0?0:prop['chart.scale.decimals']),units_pre,units_post),'tag':'scale'});for(var i=0,len=this.scale2.labels.length;i<len;++i){RG.Text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+(((i+1)/this.scale2.labels.length)*this.grapharea)+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'text':this.scale2.labels[i],'tag':'scale'});}}else{for(var i=0,len=this.scale2.labels.length;i<len;++i){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':this.gutterTop+((i/this.scale2.labels.length)*this.grapharea)+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'text':this.scale2.labels[this.scale2.labels.length-(i+1)],'tag':'scale'});}}
|
86
|
+
if((prop['chart.ymin']!=0&&!prop['chart.scale.invert']||prop['chart.scale.zerostart'])||prop['chart.noxaxis']){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':prop['chart.scale.invert']?this.gutterTop+offsety:ca.height-this.gutterBottom+offsety,'text':RG.numberFormat(this,prop['chart.ymin'].toFixed(prop['chart.ymin']===0?0:prop['chart.scale.decimals']),units_pre,units_post),'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'tag':'scale'});}}
|
87
|
+
if(prop['chart.noxaxis']==true&&prop['chart.ymin']==null&&prop['chart.xaxispos']!='center'&&prop['chart.noendytick']==false){RG.text2(this,{'font':font,'size':text_size,'x':xpos+offsetx,'y':prop['chart.xaxispos']=='top'?this.gutterTop+offsety:(ca.height-this.gutterBottom),'text':prop['chart.units.pre']+Number(0).toFixed(prop['chart.scale.decimals'])+prop['chart.units.post']+offsety,'valign':'center','halign':align,'bounding':bounding,'boundingFill':bgcolor,'tag':'scale'});}}else if(prop['chart.ylabels']&&typeof(prop['chart.ylabels.specific'])=='object'){var gap=this.grapharea/prop['chart.ylabels.specific'].length;var halign=prop['chart.yaxispos']=='left'?'right':'left';var bounding=false;var bgcolor=null;var ymin=prop['chart.ymin']!=null&&prop['chart.ymin'];if(prop['chart.yaxispos']=='left'){var x=this.gutterLeft-5;if(prop['chart.ylabels.inside']){x+=10;halign='left';bounding=true;bgcolor='rgba(255,255,255,0.5)';}}else if(prop['chart.yaxispos']=='right'){var x=ca.width-this.gutterRight+5;if(prop['chart.ylabels.inside']){x-=10;halign='right';bounding=true;bgcolor='rgba(255,255,255,0.5)';}}
|
88
|
+
var offsetx=prop['chart.ylabels.offsetx'];var offsety=prop['chart.ylabels.offsety'];if(prop['chart.xaxispos']=='center'){for(var i=0;i<prop['chart.ylabels.specific'].length;++i){var y=this.gutterTop+(this.grapharea/(((prop['chart.ylabels.specific'].length-1))*2)*i);if(ymin&&ymin>0){var y=((this.grapharea/2)/(prop['chart.ylabels.specific'].length-(ymin?1:0)))*i;y+=this.gutterTop;}
|
89
|
+
RG.text2(this,{'font':font,'size':text_size,'x':x+offsetx,'y':y+offsety,'text':String(prop['chart.ylabels.specific'][i]),'valign':'center','halign':halign,'bounding':bounding,'boundingFill':bgcolor,'tag':'ylabels.specific'});}
|
90
|
+
var reversed_labels=RG.array_reverse(prop['chart.ylabels.specific']);for(var i=0;i<reversed_labels.length;++i){var y=(this.grapharea/2)+this.gutterTop+((this.grapharea/((reversed_labels.length-1)*2))*i);RG.text2(this,{'font':font,'size':text_size,'x':x+offsetx,'y':y+offsety,'text':i==0?'':String(reversed_labels[i]),'valign':'center','halign':halign,'bounding':bounding,'boundingFill':bgcolor,'tag':'ylabels.specific'});}}else if(prop['chart.xaxispos']=='top'){var reversed_labels=RG.array_reverse(prop['chart.ylabels.specific']);for(var i=0;i<reversed_labels.length;++i){var y=(this.grapharea/(reversed_labels.length-1))*i;y=y+this.gutterTop;RG.Text2(this,{'font':font,'size':text_size,'x':x+offsetx,'y':y+offsety,'text':String(reversed_labels[i]),'valign':'center','halign':halign,'bounding':bounding,'boundingFill':bgcolor,'tag':'ylabels.specific'});}}else{for(var i=0;i<prop['chart.ylabels.specific'].length;++i){var y=this.gutterTop+((this.grapharea/(prop['chart.ylabels.specific'].length-1))*i);RG.text2(this,{'font':font,'size':text_size,'x':x+offsetx,'y':y+offsety,'text':String(prop['chart.ylabels.specific'][i]),'valign':'center','halign':halign,'bounding':bounding,'boundingFill':bgcolor,'tag':'ylabels.specific'});}}}
|
91
|
+
if(prop['chart.labels']&&prop['chart.labels'].length>0){var yOffset=5,bordered=false,bgcolor=null
|
92
|
+
co.fillStyle=prop['chart.labels.color']||prop['chart.text.color'];var angle=0,valign='top',halign='center',bold=prop['chart.labels.bold']
|
93
|
+
if(prop['chart.xlabels.inside']){yOffset=-5;bordered=true;bgcolor=prop['chart.xlabels.inside.color'];valign='bottom';}
|
94
|
+
if(prop['chart.xaxispos']=='top'){valign='bottom';yOffset+=2;}
|
95
|
+
if(typeof(prop['chart.text.angle'])=='number'&&prop['chart.text.angle']>0){angle=-1*prop['chart.text.angle'];valign='center';halign='right';yOffset=10;if(prop['chart.xaxispos']=='top'){yOffset=10;}}
|
96
|
+
var numLabels=prop['chart.labels'].length,offsetx=prop['chart.labels.offsetx'],offsety=prop['chart.labels.offsety'];for(i=0;i<numLabels;++i){if(prop['chart.labels'][i]){var labelX=((ca.width-this.gutterLeft-this.gutterRight-(2*prop['chart.hmargin']))/(numLabels-1))*i;labelX+=this.gutterLeft+prop['chart.hmargin'];if(this.data.length===0||!this.data[0]||prop['chart.labels'].length!=this.data[0].length){labelX=this.gutterLeft+prop['chart.hmargin']+((ca.width-this.gutterLeft-this.gutterRight-(2*prop['chart.hmargin']))*(i/(prop['chart.labels'].length-1)));}
|
97
|
+
if(!labelX){labelX=this.gutterLeft+prop['chart.hmargin'];}
|
98
|
+
if(prop['chart.xaxispos']=='top'&&prop['chart.text.angle']>0){halign='left';}
|
99
|
+
if(prop['chart.text.angle']!=0){halign='right';}
|
100
|
+
RG.Text2(this,{'font':font,'size':text_size,'bold':bold,'x':labelX+offsetx,'y':(prop['chart.xaxispos']=='top')?this.gutterTop-yOffset-(prop['chart.xlabels.inside']?-22:0)+offsety:(ca.height-this.gutterBottom)+yOffset+offsety,'text':String(prop['chart.labels'][i]),'valign':valign,'halign':halign,'bounding':bordered,'boundingFill':bgcolor,'angle':angle,'tag':'labels'});}}}
|
101
|
+
co.stroke();co.fill();}
|
102
|
+
this.drawLine=this.DrawLine=function(lineData,color,fill,linewidth,tickmarks,index)
|
103
|
+
{if(prop['chart.animation.unfold.y']&&prop['chart.animation.factor']!=1){for(var i=0;i<lineData.length;++i){lineData[i]*=prop['chart.animation.factor'];}}
|
104
|
+
var penUp=false;var yPos=null;var xPos=0;co.lineWidth=1;var lineCoords=[];if(index>0){var prevLineCoords=this.coords2[index-1];}
|
105
|
+
var xInterval=(ca.width-(2*prop['chart.hmargin'])-this.gutterLeft-this.gutterRight)/(lineData.length-1);for(i=0,len=lineData.length;i<len;i+=1){var data_point=lineData[i];var yPos=this.getYCoord(data_point);if(lineData[i]==null||(prop['chart.xaxispos']=='bottom'&&lineData[i]<this.min&&!prop['chart.outofbounds'])||(prop['chart.xaxispos']=='center'&&lineData[i]<(-1*this.max)&&!prop['chart.outofbounds'])||(((lineData[i]<this.min&&prop['chart.xaxispos']!=='center')||lineData[i]>this.max)&&!prop['chart.outofbounds'])){yPos=null;}
|
106
|
+
co.lineCap='round';co.lineJoin='round';if(i>0){xPos=xPos+xInterval;}else{xPos=prop['chart.hmargin']+this.gutterLeft;}
|
107
|
+
if(prop['chart.animation.unfold.x']){xPos*=prop['chart.animation.factor'];if(xPos<prop['chart.gutter.left']){xPos=prop['chart.gutter.left'];}}
|
108
|
+
this.coords.push([xPos,yPos]);lineCoords.push([xPos,yPos]);}
|
109
|
+
co.stroke();this.coords2[index]=lineCoords;if(RG.ISOLD&&prop['chart.shadow']){this.DrawIEShadow(lineCoords,co.shadowColor);}
|
110
|
+
co.beginPath();co.strokeStyle='rgba(0,0,0,0)';if(fill){co.fillStyle=fill;}
|
111
|
+
var isStepped=prop['chart.stepped'];var isFilled=prop['chart.filled'];if(prop['chart.xaxispos']=='top'){var xAxisPos=this.gutterTop;}else if(prop['chart.xaxispos']=='center'){var xAxisPos=this.gutterTop+(this.grapharea/2);}else if(prop['chart.xaxispos']=='bottom'){var xAxisPos=this.getYCoord(prop['chart.ymin'])}
|
112
|
+
for(var i=0,len=lineCoords.length;i<len;i+=1){xPos=lineCoords[i][0];yPos=lineCoords[i][1];var set=index;var prevY=(lineCoords[i-1]?lineCoords[i-1][1]:null);var isLast=(i+1)==lineCoords.length;if(!prop['chart.outofbounds']&&(prevY<this.gutterTop||prevY>(ca.height-this.gutterBottom))){penUp=true;}
|
113
|
+
if(i==0||penUp||!yPos||!prevY||prevY<this.gutterTop){if(prop['chart.filled']&&!prop['chart.filled.range']){if(!prop['chart.outofbounds']||prevY===null||yPos===null){co.moveTo(xPos+1,xAxisPos);}
|
114
|
+
if(prop['chart.xaxispos']=='top'){co.moveTo(xPos+1,xAxisPos);}
|
115
|
+
if(isStepped&&i>0){co.lineTo(xPos,lineCoords[i-1][1]);}
|
116
|
+
co.lineTo(xPos,yPos);}else{if(RG.ISOLD&&yPos==null){}else{co.moveTo(xPos+1,yPos);}}
|
117
|
+
if(yPos==null){penUp=true;}else{penUp=false;}}else{if(isStepped){co.lineTo(xPos,lineCoords[i-1][1]);}
|
118
|
+
if((yPos>=this.gutterTop&&yPos<=(ca.height-this.gutterBottom))||prop['chart.outofbounds']){if(isLast&&prop['chart.filled']&&!prop['chart.filled.range']&&prop['chart.yaxispos']=='right'){xPos-=1;}
|
119
|
+
if(!isStepped||!isLast){co.lineTo(xPos,yPos);if(isFilled&&lineCoords[i+1]&&lineCoords[i+1][1]==null){co.lineTo(xPos,xAxisPos);}}else if(isStepped&&isLast){co.lineTo(xPos,yPos);}
|
120
|
+
penUp=false;}else{penUp=true;}}}
|
121
|
+
if(prop['chart.filled']&&!prop['chart.filled.range']&&!prop['chart.curvy']){var fillStyle=prop['chart.fillstyle'];if(index>0&&prop['chart.filled.accumulative']){co.lineTo(xPos,prevLineCoords?prevLineCoords[i-1][1]:(ca.height-this.gutterBottom-1+(prop['chart.xaxispos']=='center'?(ca.height-this.gutterTop-this.gutterBottom)/2:0)));for(var k=(i-1);k>=0;--k){co.lineTo(k==0?prevLineCoords[k][0]+1:prevLineCoords[k][0],prevLineCoords[k][1]);}}else{if(prop['chart.xaxispos']=='top'){co.lineTo(xPos,prop['chart.gutter.top']+1);co.lineTo(lineCoords[0][0],prop['chart.gutter.top']+1);}else if(typeof(lineCoords[i-1][1])=='number'){var yPosition=this.getYCoord(0);co.lineTo(xPos,yPosition);co.lineTo(lineCoords[0][0],yPosition);}}
|
122
|
+
co.fillStyle=!this.hidden(index)?fill:'rgba(0,0,0,0)';co.fill();co.beginPath();}
|
123
|
+
co.stroke();if(prop['chart.backdrop']){this.DrawBackdrop(lineCoords,color);}
|
124
|
+
co.save();co.beginPath();co.rect(0,0,ca.width*prop['chart.animation.trace.clip'],ca.height);co.clip();if(typeof prop['chart.errorbars']!=='null'){this.drawErrorbars();}
|
125
|
+
this.SetShadow(index);this.RedrawLine(lineCoords,color,linewidth,index);co.stroke();RG.NoShadow(this);for(var i=0;i<lineCoords.length;++i){i=Number(i);co.strokeStyle=color;if(isStepped&&i==(lineCoords.length-1)){co.beginPath();}
|
126
|
+
if((tickmarks!='endcircle'&&tickmarks!='endsquare'&&tickmarks!='filledendsquare'&&tickmarks!='endtick'&&tickmarks!='endtriangle'&&tickmarks!='arrow'&&tickmarks!='filledarrow')||(i==0&&tickmarks!='arrow'&&tickmarks!='filledarrow')||i==(lineCoords.length-1)){var prevX=(i<=0?null:lineCoords[i-1][0]);var prevY=(i<=0?null:lineCoords[i-1][1]);this.DrawTick(lineData,lineCoords[i][0],lineCoords[i][1],color,false,prevX,prevY,tickmarks,i,index);}}
|
127
|
+
co.restore();co.beginPath();co.arc(ca.width+50000,ca.height+50000,2,0,6.38,1);};this.drawTick=this.DrawTick=function(lineData,xPos,yPos,color,isShadow,prevX,prevY,tickmarks,index,dataset)
|
128
|
+
{if(this.hidden(dataset)){return;}else if(RG.is_null(yPos)){return false;}else if((yPos>(ca.height-this.gutterBottom))&&!prop['chart.outofbounds']){return;}else if((yPos<this.gutterTop)&&!prop['chart.outofbounds']){return;}
|
129
|
+
co.beginPath();var offset=0;co.lineWidth=prop['chart.tickmarks.linewidth']?prop['chart.tickmarks.linewidth']:prop['chart.linewidth'];co.strokeStyle=isShadow?prop['chart.shadow.color']:co.strokeStyle;co.fillStyle=isShadow?prop['chart.shadow.color']:co.strokeStyle;if(tickmarks=='circle'||tickmarks=='filledcircle'||tickmarks=='endcircle'){if(tickmarks=='circle'||tickmarks=='filledcircle'||(tickmarks=='endcircle'&&(index==0||index==(lineData.length-1)))){co.beginPath();co.arc(xPos+offset,yPos+offset,prop['chart.ticksize'],0,360/(180/RG.PI),false);if(tickmarks=='filledcircle'){co.fillStyle=isShadow?prop['chart.shadow.color']:co.strokeStyle;}else{co.fillStyle=isShadow?prop['chart.shadow.color']:'white';}
|
130
|
+
co.stroke();co.fill();}}else if(tickmarks=='halftick'){co.beginPath();co.moveTo(Math.round(xPos),yPos);co.lineTo(Math.round(xPos),yPos+prop['chart.ticksize']);co.stroke();}else if(tickmarks=='tick'){co.beginPath();co.moveTo(Math.round(xPos),yPos-prop['chart.ticksize']);co.lineTo(Math.round(xPos),yPos+prop['chart.ticksize']);co.stroke();}else if(tickmarks=='endtick'&&(index==0||index==(lineData.length-1))){co.beginPath();co.moveTo(Math.round(xPos),yPos-prop['chart.ticksize']);co.lineTo(Math.round(xPos),yPos+prop['chart.ticksize']);co.stroke();}else if(tickmarks=='cross'){co.beginPath();var ticksize=prop['chart.ticksize'];co.moveTo(xPos-ticksize,yPos-ticksize);co.lineTo(xPos+ticksize,yPos+ticksize);co.moveTo(xPos+ticksize,yPos-ticksize);co.lineTo(xPos-ticksize,yPos+ticksize);co.stroke();}else if(tickmarks=='triangle'||tickmarks=='filledtriangle'||(tickmarks=='endtriangle'&&(index==0||index==(lineData.length-1)))){co.beginPath();if(tickmarks=='filledtriangle'){co.fillStyle=isShadow?prop['chart.shadow.color']:co.strokeStyle;}else{co.fillStyle='white';}
|
131
|
+
co.moveTo(ma.round(xPos-prop['chart.ticksize']),yPos+prop['chart.ticksize']);co.lineTo(ma.round(xPos),yPos-prop['chart.ticksize']);co.lineTo(ma.round(xPos+prop['chart.ticksize']),yPos+prop['chart.ticksize']);co.closePath();co.stroke();co.fill();}else if(tickmarks=='borderedcircle'||tickmarks=='dot'){co.lineWidth=prop['chart.tickmarks.dot.linewidth']||0.00000001;pa2(co,['b','a',xPos,yPos,prop['chart.ticksize'],0,360/(180/RG.PI),false,'c','f',prop['chart.tickmarks.dot.fill']||color,'s',prop['chart.tickmarks.dot.stroke']||color]);}else if(tickmarks=='square'||tickmarks=='filledsquare'||(tickmarks=='endsquare'&&(index==0||index==(lineData.length-1)))||(tickmarks=='filledendsquare'&&(index==0||index==(lineData.length-1)))){co.fillStyle='white';co.strokeStyle=co.strokeStyle;co.beginPath();co.rect(Math.round(xPos-prop['chart.ticksize']),Math.round(yPos-prop['chart.ticksize']),prop['chart.ticksize']*2,prop['chart.ticksize']*2);if(tickmarks=='filledsquare'||tickmarks=='filledendsquare'){co.fillStyle=isShadow?prop['chart.shadow.color']:co.strokeStyle;co.rect(Math.round(xPos-prop['chart.ticksize']),Math.round(yPos-prop['chart.ticksize']),prop['chart.ticksize']*2,prop['chart.ticksize']*2);}else if(tickmarks=='square'||tickmarks=='endsquare'){co.fillStyle=isShadow?prop['chart.shadow.color']:'white';co.rect(Math.round((xPos-prop['chart.ticksize'])+1),Math.round((yPos-prop['chart.ticksize'])+1),(prop['chart.ticksize']*2)-2,(prop['chart.ticksize']*2)-2);}
|
132
|
+
co.stroke();co.fill();}else if(tickmarks=='filledarrow'){var x=Math.abs(xPos-prevX);var y=Math.abs(yPos-prevY);if(yPos<prevY){var a=Math.atan(x/y)+1.57;}else{var a=Math.atan(y/x)+3.14;}
|
133
|
+
co.beginPath();co.moveTo(Math.round(xPos),Math.round(yPos));co.arc(Math.round(xPos),Math.round(yPos),7,a-0.5,a+0.5,false);co.closePath();co.stroke();co.fill();}else if(tickmarks=='arrow'){var orig_linewidth=co.lineWidth;var x=Math.abs(xPos-prevX);var y=Math.abs(yPos-prevY);co.lineWidth;if(yPos<prevY){var a=Math.atan(x/y)+1.57;}else{var a=Math.atan(y/x)+3.14;}
|
134
|
+
co.beginPath();co.moveTo(Math.round(xPos),Math.round(yPos));co.arc(Math.round(xPos),Math.round(yPos),7,a-0.5-(doc.all?0.1:0.01),a-0.4,false);co.moveTo(Math.round(xPos),Math.round(yPos));co.arc(Math.round(xPos),Math.round(yPos),7,a+0.5+(doc.all?0.1:0.01),a+0.5,true);co.stroke();co.fill();co.lineWidth=orig_linewidth;}else if(typeof tickmarks==='string'&&(tickmarks.substr(0,6)==='image:'||tickmarks.substr(0,5)==='data:'||tickmarks.substr(0,1)==='/'||tickmarks.substr(0,3)==='../'||tickmarks.substr(0,7)==='images/')){var img=new Image();if(tickmarks.substr(0,6)==='image:'){img.src=tickmarks.substr(6);}else{img.src=tickmarks;}
|
135
|
+
img.onload=function()
|
136
|
+
{if(prop['chart.tickmarks.image.halign']==='center')xPos-=(this.width/2);if(prop['chart.tickmarks.image.halign']==='right')xPos-=this.width;if(prop['chart.tickmarks.image.valign']==='center')yPos-=(this.height/2);if(prop['chart.tickmarks.image.valign']==='bottom')yPos-=this.height;xPos+=prop['chart.tickmarks.image.offsetx'];yPos+=prop['chart.tickmarks.image.offsety'];co.drawImage(this,xPos,yPos);};}else if(typeof(tickmarks)=='function'){tickmarks(this,lineData,lineData[index],index,xPos,yPos,color,prevX,prevY);}};this.drawRange=this.DrawRange=function()
|
137
|
+
{if(prop['chart.filled.range']&&prop['chart.filled']){if(RG.isNull(prop['chart.filled.range.threshold'])){prop['chart.filled.range.threshold']=this.ymin
|
138
|
+
prop['chart.filled.range.threshold.colors']=[prop['chart.fillstyle'],prop['chart.fillstyle']]}
|
139
|
+
for(var idx=0;idx<2;++idx){var threshold_colors=prop['chart.filled.range.threshold.colors'];var y=this.getYCoord(prop['chart.filled.range.threshold'])
|
140
|
+
co.save();if(idx==0){co.beginPath();co.rect(0,0,ca.width,y);co.clip();}else{co.beginPath();co.rect(0,y,ca.width,ca.height);co.clip();}
|
141
|
+
co.beginPath();co.fillStyle=(idx==1?prop['chart.filled.range.threshold.colors'][1]:prop['chart.filled.range.threshold.colors'][0]);co.lineWidth=!this.hidden(idx)?1:0;var len=(this.coords.length/2);for(var i=0;i<len;++i){if(!RG.is_null(this.coords[i][1])){if(i==0){co.moveTo(this.coords[i][0],this.coords[i][1])}else{co.lineTo(this.coords[i][0],this.coords[i][1])}}}
|
142
|
+
for(var i=this.coords.length-1;i>=len;--i){if(RG.is_null(this.coords[i][1])){co.moveTo(this.coords[i][0],this.coords[i][1])}else{co.lineTo(this.coords[i][0],this.coords[i][1])}}
|
143
|
+
co.fill();co.restore();}}};this.redrawLine=this.RedrawLine=function(coords,color,linewidth,index)
|
144
|
+
{if(prop['chart.noredraw']||prop['chart.filled.range']){return;}
|
145
|
+
co.strokeStyle=(typeof(color)=='object'&&color&&color.toString().indexOf('CanvasGradient')==-1?color[0]:color);co.lineWidth=linewidth;if(this.hidden(index)){co.strokeStyle='rgba(0,0,0,0)';}
|
146
|
+
if(!RG.ISOLD&&(prop['chart.curvy']||prop['chart.spline'])){this.DrawCurvyLine(coords,this.hidden(index)?'rgba(0,0,0,0)':color,linewidth,index);return;}
|
147
|
+
co.beginPath();var len=coords.length;var width=ca.width
|
148
|
+
var height=ca.height;var penUp=false;for(var i=0;i<len;++i){var xPos=coords[i][0];var yPos=coords[i][1];if(i>0){var prevX=coords[i-1][0];var prevY=coords[i-1][1];}
|
149
|
+
if(((i==0&&coords[i])||(yPos<this.gutterTop)||(prevY<this.gutterTop)||(yPos>(height-this.gutterBottom))||(i>0&&prevX>(width-this.gutterRight))||(i>0&&prevY>(height-this.gutterBottom))||prevY==null||penUp==true)&&(!prop['chart.outofbounds']||yPos==null||prevY==null)){if(RG.ISOLD&&yPos==null){}else{co.moveTo(coords[i][0],coords[i][1]);}
|
150
|
+
penUp=false;}else{if(prop['chart.stepped']&&i>0){co.lineTo(coords[i][0],coords[i-1][1]);}
|
151
|
+
co.lineTo(coords[i][0],coords[i][1]);penUp=false;}}
|
152
|
+
if(prop['chart.colors.alternate']&&typeof(color)=='object'&&color[0]&&color[1]){for(var i=1;i<len;++i){var prevX=coords[i-1][0];var prevY=coords[i-1][1];if(prevY!=null&&coords[i][1]!=null){co.beginPath();co.strokeStyle=color[coords[i][1]<prevY?0:1];co.lineWidth=prop['chart.linewidth'];co.moveTo(prevX,prevY);co.lineTo(coords[i][0],coords[i][1]);co.stroke();}}}};this.drawIEShadow=this.DrawIEShadow=function(coords,color)
|
153
|
+
{var offsetx=prop['chart.shadow.offsetx'];var offsety=prop['chart.shadow.offsety'];co.lineWidth=prop['chart.linewidth'];co.strokeStyle=color;co.beginPath();for(var i=0;i<coords.length;++i){var isNull=RG.isNull(coords[i][1]);var prevIsNull=RG.isNull(coords[i-1])||RG.isNull(coords[i-1][1]);if(i==0||isNull||prevIsNull){if(!isNull){co.moveTo(coords[i][0]+offsetx,coords[i][1]+offsety);}}else{co.lineTo(coords[i][0]+offsetx,coords[i][1]+offsety);}}
|
154
|
+
co.stroke();};this.drawBackdrop=this.DrawBackdrop=function(coords,color)
|
155
|
+
{var size=prop['chart.backdrop.size'];co.lineWidth=size;co.globalAlpha=prop['chart.backdrop.alpha'];co.strokeStyle=color;var yCoords=[];co.beginPath();if(prop['chart.curvy']&&!RG.ISOLD){for(var i=0;i<coords.length;++i){yCoords.push(coords[i][1])}
|
156
|
+
this.DrawSpline(co,yCoords,color,null);}else{co.moveTo(coords[0][0],coords[0][1]);for(var j=1;j<coords.length;++j){co.lineTo(coords[j][0],coords[j][1]);}}
|
157
|
+
co.stroke();co.globalAlpha=1;RG.NoShadow(this);};this.getLineWidth=this.GetLineWidth=function(i)
|
158
|
+
{var linewidth=prop['chart.linewidth'];if(typeof(linewidth)=='number'){return linewidth;}else if(typeof(linewidth)=='object'){if(linewidth[i]){return linewidth[i];}else{return linewidth[0];}
|
159
|
+
alert('[LINE] Error! chart.linewidth should be a single number or an array of one or more numbers');}};this.getShape=this.getPoint=function(e)
|
160
|
+
{var obj=this,RG=RGraph,ca=canvas=e.target,co=context=this.context,prop=this.properties;var mouseXY=RG.getMouseXY(e),mouseX=mouseXY[0],mouseY=mouseXY[1];if(arguments[1]){obj=arguments[1];}
|
161
|
+
for(var i=0;i<obj.coords.length;++i){var x=obj.coords[i][0];var y=obj.coords[i][1];if(mouseX<=(x+prop['chart.tooltips.hotspot.size'])&&mouseX>=(x-prop['chart.tooltips.hotspot.size'])&&mouseY<=(y+prop['chart.tooltips.hotspot.size'])&&mouseY>=(y-prop['chart.tooltips.hotspot.size'])){if(RG.parseTooltipText){var tooltip=RG.parseTooltipText(prop['chart.tooltips'],i);}
|
162
|
+
var dataset=0;var idx=i;while((idx+1)>this.data[dataset].length){idx-=this.data[dataset].length;dataset++;}
|
163
|
+
return{0:obj,1:x,2:y,3:i,'object':obj,'x':x,'y':y,'index':i,'tooltip':tooltip,'dataset':dataset,'index_adjusted':idx};}else if(prop['chart.tooltips.hotspot.xonly']==true&&mouseX<=(x+prop['chart.tooltips.hotspot.size'])&&mouseX>=(x-prop['chart.tooltips.hotspot.size'])){var tooltip=RG.parseTooltipText(prop['chart.tooltips'],i);return{0:obj,1:x,2:y,3:i,'object':obj,'x':x,'y':y,'index':i,'tooltip':tooltip};}}};this.drawAboveLabels=this.DrawAboveLabels=function()
|
164
|
+
{var size=prop['chart.labels.above.size'],font=prop['chart.labels.above.font']||prop['chart.text.font'],units_pre=prop['chart.labels.above.units.pre'],units_post=prop['chart.labels.above.units.post'],decimals=prop['chart.labels.above.decimals'],color=prop['chart.labels.above.color']||prop['chart.text.color'],bgcolor=prop['chart.labels.above.background']||'white',border=((typeof prop['chart.labels.above.border']==='boolean'||typeof prop['chart.labels.above.border']==='number')?prop['chart.labels.above.border']:true),offsety=prop['chart.labels.above.offsety']+size,specific=prop['chart.labels.above.specific'];co.beginPath();for(var i=0,len=this.coords.length;i<len;i+=1){var coords=this.coords[i];RG.text2(this,{color:color,'font':font,'size':size,'x':coords[0],'y':coords[1]-offsety,'text':(specific&&specific[i])?specific[i]:(specific?null:RG.numberFormat(this,typeof decimals==='number'?this.data_arr[i].toFixed(decimals):this.data_arr[i],units_pre,units_post)),'valign':'center','halign':'center','bounding':true,'boundingFill':bgcolor,'boundingStroke':border?'black':'rgba(0,0,0,0)','tag':'labels.above'});}};this.drawCurvyLine=this.DrawCurvyLine=function(coords,color,linewidth,index)
|
165
|
+
{var yCoords=[];for(var i=0;i<coords.length;++i){yCoords.push(coords[i][1]);}
|
166
|
+
if(prop['chart.filled']){co.beginPath();var xaxisY=this.getYCoord(prop['chart.ymin']);co.moveTo(coords[0][0],xaxisY);this.drawSpline(co,yCoords,color,index);if(prop['chart.filled.accumulative']&&index>0){for(var i=(this.coordsSpline[index-1].length-1);i>=0;i-=1){co.lineTo(this.coordsSpline[index-1][i][0],this.coordsSpline[index-1][i][1]);}}else{co.lineTo(coords[coords.length-1][0],xaxisY);}
|
167
|
+
co.fill();}
|
168
|
+
co.beginPath();this.DrawSpline(co,yCoords,color,index);co.stroke();};this.getValue=function(arg)
|
169
|
+
{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];}
|
170
|
+
var obj=this;var xaxispos=prop['chart.xaxispos'];if(mouseY<prop['chart.gutter.top']){return xaxispos=='bottom'||xaxispos=='center'?this.max:this.min;}else if(mouseY>(ca.height-prop['chart.gutter.bottom'])){return xaxispos=='bottom'?this.min:this.max;}
|
171
|
+
if(prop['chart.xaxispos']=='center'){var value=(((obj.grapharea/2)-(mouseY-prop['chart.gutter.top']))/obj.grapharea)*(obj.max-obj.min);value*=2;value>0?value+=this.min:value-=this.min;return value;}else if(prop['chart.xaxispos']=='top'){var value=((obj.grapharea-(mouseY-prop['chart.gutter.top']))/obj.grapharea)*(obj.max-obj.min);value=Math.abs(obj.max-value)* -1;return value;}else{var value=((obj.grapharea-(mouseY-prop['chart.gutter.top']))/obj.grapharea)*(obj.max-obj.min)
|
172
|
+
value+=obj.min;return value;}};this.highlight=this.Highlight=function(shape)
|
173
|
+
{if(prop['chart.tooltips.highlight']){if(typeof prop['chart.highlight.style']==='function'){(prop['chart.highlight.style'])(shape);}else if(prop['chart.highlight.style']==='halo'){var obj=shape.object,color=prop['chart.colors'][shape.dataset];RG.path2(obj.context,'b a % % 13 0 6.2830 false f rgba(255,255,255,0.75)',shape.x,shape.y);RG.path2(obj.context,'ga 0.15 b a % % 13 0 6.2830 false f % ga 1',shape.x,shape.y,color);RG.path2(obj.context,'b a % % 7 0 6.2830 false f white',shape.x,shape.y);RG.path2(obj.context,'b a % % 5 0 6.2830 false f %',shape.x,shape.y,color);}else{RG.Highlight.Point(this,shape);}}};this.getObjectByXY=function(e)
|
174
|
+
{var mouseXY=RG.getMouseXY(e);if((mouseXY[0]>prop['chart.gutter.left']-5)&&mouseXY[0]<(ca.width-prop['chart.gutter.right']+5)&&mouseXY[1]>(prop['chart.gutter.top']-5)&&mouseXY[1]<(ca.height-prop['chart.gutter.bottom']+5)){return this;}};this.adjusting_mousemove=this.Adjusting_mousemove=function(e)
|
175
|
+
{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');if(shape){RG.Registry.Set('chart.adjusting.shape',shape);this.original_data[shape['dataset']][shape['index_adjusted']]=Number(value);RG.redrawCanvas(e.target);RG.fireCustomEvent(this,'onadjust');}}};this.getYCoord=function(value)
|
176
|
+
{if(typeof(value)!='number'){return null;}
|
177
|
+
var y;var xaxispos=prop['chart.xaxispos'];if(xaxispos=='top'){y=((value-this.min)/(this.max-this.min))*this.grapharea;if(prop['chart.scale.invert']){y=this.grapharea-y;}
|
178
|
+
y=y+this.gutterTop}else if(xaxispos=='center'){y=((value-this.min)/(this.max-this.min))*(this.grapharea/2);y=(this.grapharea/2)-y;y+=this.gutterTop;}else{if((value<this.min||value>this.max)&&prop['chart.outofbounds']==false){return null;}
|
179
|
+
y=((value-this.min)/(this.max-this.min))*this.grapharea;if(prop['chart.scale.invert']){y=this.grapharea-y;}
|
180
|
+
y=ca.height-this.gutterBottom-y;}
|
181
|
+
return y;};this.drawSpline=this.DrawSpline=function(context,coords,color,index)
|
182
|
+
{this.coordsSpline[index]=[];var xCoords=[];var gutterLeft=prop['chart.gutter.left'];var gutterRight=prop['chart.gutter.right'];var hmargin=prop['chart.hmargin'];var interval=(ca.width-(gutterLeft+gutterRight)-(2*hmargin))/(coords.length-1);co.strokeStyle=color;for(var i=0,len=coords.length;i<len;i+=1){if(typeof coords[i]=='object'&&coords[i]&&coords[i].length==2){coords[i]=Number(coords[i][1]);}}
|
183
|
+
var P=[coords[0]];for(var i=0;i<coords.length;++i){P.push(coords[i]);}
|
184
|
+
P.push(coords[coords.length-1]+(coords[coords.length-1]-coords[coords.length-2]));for(var j=1;j<P.length-2;++j){for(var t=0;t<10;++t){var yCoord=Spline(t/10,P[j-1],P[j],P[j+1],P[j+2]);xCoords.push(((j-1)*interval)+(t*(interval/10))+gutterLeft+hmargin);co.lineTo(xCoords[xCoords.length-1],yCoord);if(typeof index=='number'){this.coordsSpline[index].push([xCoords[xCoords.length-1],yCoord]);}}}
|
185
|
+
co.lineTo(((j-1)*interval)+gutterLeft+hmargin,P[j]);if(typeof index=='number'){this.coordsSpline[index].push([((j-1)*interval)+gutterLeft+hmargin,P[j]]);}
|
186
|
+
function Spline(t,P0,P1,P2,P3)
|
187
|
+
{return 0.5*((2*P1)+
|
188
|
+
((0-P0)+P2)*t+
|
189
|
+
((2*P0-(5*P1)+(4*P2)-P3)*(t*t)+
|
190
|
+
((0-P0)+(3*P1)-(3*P2)+P3)*(t*t*t)));}};this.parseColors=function()
|
191
|
+
{if(this.original_colors.length===0){this.original_colors['chart.colors']=RGraph.array_clone(prop['chart.colors']);this.original_colors['chart.fillstyle']=RGraph.array_clone(prop['chart.fillstyle']);this.original_colors['chart.key.colors']=RGraph.array_clone(prop['chart.key.colors']);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.text.color']=prop['chart.text.color'];this.original_colors['chart.crosshairs.color']=prop['chart.crosshairs.color'];this.original_colors['chart.annotate.color']=prop['chart.annotate.color'];this.original_colors['chart.title.color']=prop['chart.title.color'];this.original_colors['chart.title.yaxis.color']=prop['chart.title.yaxis.color'];this.original_colors['chart.key.background']=prop['chart.key.background'];this.original_colors['chart.axis.color']=prop['chart.axis.color'];this.original_colors['chart.highlight.fill']=prop['chart.highlight.fill'];}
|
192
|
+
for(var i=0;i<prop['chart.colors'].length;++i){if(typeof(prop['chart.colors'][i])=='object'&&prop['chart.colors'][i][0]&&prop['chart.colors'][i][1]){prop['chart.colors'][i][0]=this.parseSingleColorForGradient(prop['chart.colors'][i][0]);prop['chart.colors'][i][1]=this.parseSingleColorForGradient(prop['chart.colors'][i][1]);}else{prop['chart.colors'][i]=this.parseSingleColorForGradient(prop['chart.colors'][i]);}}
|
193
|
+
if(prop['chart.fillstyle']){if(typeof(prop['chart.fillstyle'])=='string'){prop['chart.fillstyle']=this.parseSingleColorForGradient(prop['chart.fillstyle'],'vertical');}else{for(var i=0;i<prop['chart.fillstyle'].length;++i){prop['chart.fillstyle'][i]=this.parseSingleColorForGradient(prop['chart.fillstyle'][i],'vertical');}}}
|
194
|
+
if(!RG.is_null(prop['chart.key.colors'])){for(var i=0;i<prop['chart.key.colors'].length;++i){prop['chart.key.colors'][i]=this.parseSingleColorForGradient(prop['chart.key.colors'][i]);}}
|
195
|
+
var properties=['chart.background.barcolor1','chart.background.barcolor2','chart.background.grid.color','chart.background.color','chart.text.color','chart.crosshairs.color','chart.annotate.color','chart.title.color','chart.title.yaxis.color','chart.key.background','chart.axis.color','chart.highlight.fill'];for(var i=0;i<properties.length;++i){prop[properties[i]]=this.parseSingleColorForGradient(prop[properties[i]]);}};this.reset=function()
|
196
|
+
{};this.parseSingleColorForGradient=function(color)
|
197
|
+
{if(!color||typeof(color)!='string'){return color;}
|
198
|
+
var dir=typeof(arguments[1])=='string'?arguments[1]:'vertical';if(typeof color==='string'&&color.match(/^gradient\((.*)\)$/i)){var parts=RegExp.$1.split(':');if(dir=='horizontal'){var grad=co.createLinearGradient(0,0,ca.width,0);}else{var grad=co.createLinearGradient(0,ca.height-prop['chart.gutter.bottom'],0,prop['chart.gutter.top']);}
|
199
|
+
var diff=1/(parts.length-1);grad.addColorStop(0,RG.trim(parts[0]));for(var j=1;j<parts.length;++j){grad.addColorStop(j*diff,RG.trim(parts[j]));}}
|
200
|
+
return grad?grad:color;};this.setShadow=this.SetShadow=function(i)
|
201
|
+
{if(prop['chart.shadow']){var shadowColor=prop['chart.shadow.color'];if(typeof(shadowColor)=='object'&&shadowColor[i-1]){co.shadowColor=shadowColor[i];}else if(typeof(shadowColor)=='object'){co.shadowColor=shadowColor[0];}else if(typeof(shadowColor)=='string'){co.shadowColor=shadowColor;}
|
202
|
+
co.shadowBlur=prop['chart.shadow.blur'];co.shadowOffsetX=prop['chart.shadow.offsetx'];co.shadowOffsetY=prop['chart.shadow.offsety'];}};this.interactiveKeyHighlight=function(index)
|
203
|
+
{var coords=this.coords2[index];if(coords){var pre_linewidth=co.lineWidth;var pre_linecap=co.lineCap;co.lineWidth=prop['chart.linewidth']+10;co.lineCap='round';co.strokeStyle=prop['chart.key.interactive.highlight.chart.stroke'];co.beginPath();if(prop['chart.curvy']){this.DrawSpline(co,coords,prop['chart.key.interactive.highlight.chart'],null);}else{for(var i=0,len=coords.length;i<len;i+=1){if(i==0||RG.is_null(coords[i][1])||(typeof coords[i-1][1]!=undefined&&RG.is_null(coords[i-1][1]))){co.moveTo(coords[i][0],coords[i][1]);}else{co.lineTo(coords[i][0],coords[i][1]);}}}
|
204
|
+
co.stroke();co.lineWidth=pre_linewidth;co.lineCap=pre_linecap;}};this.on=function(type,func)
|
205
|
+
{if(type.substr(0,2)!=='on'){type='on'+type;}
|
206
|
+
if(typeof this[type]!=='function'){this[type]=func;}else{RG.addCustomEventListener(this,type,func);}
|
207
|
+
return this;};this.firstDrawFunc=function()
|
208
|
+
{};this.drawErrorbars=function()
|
209
|
+
{co.save();RG.noShadow(this);var coords=this.coords,x=0,errorbars=prop['chart.errorbars'],length=0;if(!prop['chart.errorbars.capped']){prop['chart.errorbars.capped.width']=0.001;halfwidth=0.0005;}
|
210
|
+
co.lineWidth=prop['chart.errorbars.linewidth'];for(var i=0;i<coords.length;++i){var halfwidth=prop['chart.errorbars.capped.width']/2||5,color=prop['chart.errorbars.color']||'black';if(errorbars[i]&&typeof errorbars[i][3]==='number'){co.lineWidth=errorbars[i][3];}else if(typeof prop['chart.errorbars.linewidth']==='number'){co.lineWidth=prop['chart.errorbars.linewidth'];}else{co.lineWidth=1;}
|
211
|
+
if(typeof errorbars==='number'||typeof errorbars[i]==='number'){if(typeof errorbars==='number'){var positiveLength=this.getYCoord(this.min)-this.getYCoord(this.min+errorbars),negativeLength=positiveLength;}else{var positiveLength=this.getYCoord(this.min)-this.getYCoord(this.min+errorbars[i]),negativeLength=positiveLength;}
|
212
|
+
if(positiveLength||negativeLength){pa2(co,'lj miter lc square b m % % l % % m % % l % % l % % m % % l % % s %',coords[i][0]-halfwidth,coords[i][1]+negativeLength,coords[i][0]+halfwidth,coords[i][1]+negativeLength,coords[i][0],coords[i][1]+negativeLength,coords[i][0],coords[i][1]-positiveLength,coords[i][0]-halfwidth,coords[i][1]-positiveLength,coords[i][0],coords[i][1]-positiveLength,coords[i][0]+halfwidth,coords[i][1]-positiveLength,color);pa2(co,'lj miter lc square b m % % l % % s %',coords[i][0]-halfwidth,coords[i][1]+negativeLength,coords[i][0]+halfwidth,coords[i][1]+negativeLength,color);}}else if(typeof errorbars[i]==='object'&&!RG.isNull(errorbars[i])){var positiveLength=this.getYCoord(this.min)-this.getYCoord(this.min+errorbars[i][0]),negativeLength=this.getYCoord(this.min)-this.getYCoord(this.min+errorbars[i][1]);if(typeof errorbars[i][2]==='string'){color=errorbars[i][2];}
|
213
|
+
halfwidth=typeof errorbars[i][4]==='number'?errorbars[i][4]/2:halfwidth;if(typeof errorbars[i]==='object'&&typeof errorbars[i][3]==='number'){co.lineWidth=errorbars[i][3];}else if(typeof prop['chart.errorbars.linewidth']==='number'){co.lineWidth=prop['chart.errorbars.linewidth'];}else{co.lineWidth=1;}
|
214
|
+
if(!RG.isNull(errorbars[i][0])){pa2(co,'lc square b m % % l % % l % % m % % l % % s %',coords[i][0],coords[i][1],coords[i][0],coords[i][1]-positiveLength,coords[i][0]-halfwidth,ma.round(coords[i][1]-positiveLength),coords[i][0],ma.round(coords[i][1]-positiveLength),coords[i][0]+halfwidth,ma.round(coords[i][1]-positiveLength),color);}
|
215
|
+
if(typeof errorbars[i][1]==='number'){var negativeLength=ma.abs(this.getYCoord(errorbars[i][1])-this.getYCoord(0));pa2(co,'b m % % l % % l % % m % % l % % s %',coords[i][0],coords[i][1],coords[i][0],coords[i][1]+negativeLength,coords[i][0]-halfwidth,ma.round(coords[i][1]+negativeLength),coords[i][0],ma.round(coords[i][1]+negativeLength),coords[i][0]+halfwidth,ma.round(coords[i][1]+negativeLength),color);}}}
|
216
|
+
co.restore();};this.hide=function()
|
217
|
+
{if(typeof arguments[0]==='number'){prop['chart.line.visible'][arguments[0]]=false;}else if(typeof arguments[0]==='object'){for(var i=0;i<arguments[0].length;++i){prop['chart.line.visible'][arguments[0][i]]=false;}}else{for(var i=0;i<this.original_data.length;++i){prop['chart.line.visible'][i]=false;}}
|
218
|
+
RG.redraw();return this;};this.show=function()
|
219
|
+
{if(typeof arguments[0]==='number'){prop['chart.line.visible'][arguments[0]]=true;}else if(typeof arguments[0]==='object'){for(var i=0;i<arguments[0].length;++i){prop['chart.line.visible'][arguments[0][i]]=true;}}else{for(var i=0;i<this.original_data.length;++i){prop['chart.line.visible'][i]=true;}}
|
220
|
+
RG.redraw();return this;};this.hidden=function(index)
|
221
|
+
{return!prop['chart.line.visible'][index];};this.unfold=function()
|
222
|
+
{var obj=this;var opt=arguments[0]?arguments[0]:{};var frames=opt.frames?opt.frames:30;var frame=0;var callback=arguments[1]?arguments[1]:function(){};var initial=prop['chart.animation.unfold.initial'];prop['chart.animation.factor']=prop['chart.animation.unfold.initial'];function iterator()
|
223
|
+
{prop['chart.animation.factor']=((1-initial)*(frame/frames))+initial;RG.clear(obj.canvas);RG.redrawCanvas(obj.canvas);if(frame<frames){frame++;RG.Effects.updateCanvas(iterator);}else{callback(obj);}}
|
224
|
+
iterator();return this;};this.trace=this.trace2=function()
|
225
|
+
{var obj=this;var callback=arguments[2];var opt=arguments[0]||{};var frames=opt.frames||30;var frame=0;var callback=arguments[1]||function(){};obj.Set('animation.trace.clip',0);function iterator()
|
226
|
+
{RG.clear(obj.canvas);RG.redrawCanvas(obj.canvas);if(frame++<frames){obj.Set('animation.trace.clip',frame/frames);RG.Effects.updateCanvas(iterator);}else{callback(obj);}}
|
227
|
+
iterator();return this;};this.foldtocenter=this.foldToCenter=function()
|
228
|
+
{var obj=this;var opt=arguments[0]||{};var frames=opt.frames||30;var frame=0;var callback=arguments[1]||function(){};var center_value=obj.scale2.max/2;obj.Set('chart.ymax',obj.scale2.max);var original_data=RG.array_clone(obj.original_data);function iterator()
|
229
|
+
{for(var i=0,len=obj.data.length;i<len;++i){if(obj.data[i].length){for(var j=0,len2=obj.data[i].length;j<len2;++j){var dataset=obj.original_data[i];if(dataset[j]>center_value){dataset[j]=original_data[i][j]-((original_data[i][j]-center_value)*(frame/frames));}else{dataset[j]=original_data[i][j]+(((center_value-original_data[i][j])/frames)*frame);}}}}
|
230
|
+
RG.clear(obj.canvas);RG.redrawCanvas(obj.canvas)
|
231
|
+
if(frame++<frames){RG.Effects.updateCanvas(iterator);}else{callback(obj);}}
|
232
|
+
iterator();return this;};this.unfoldFromCenterTrace=this.unfoldFromCenterTrace2=function()
|
233
|
+
{var obj=this,opt=arguments[0]||{},frames=opt.frames||30,frame=0,data=RG.arrayClone(obj.original_data),callback=arguments[1]||function(){};obj.canvas.style.visibility='hidden';obj.draw();var max=obj.scale2.max;RG.clear(obj.canvas);obj.canvas.style.visibility='visible';var unfoldCallback=function()
|
234
|
+
{obj.original_data=data;obj.unfoldFromCenter({frames:frames/2},callback);};var half=obj.Get('chart.xaxispos')=='center'?obj.min:((obj.max-obj.min)/2)+obj.min;obj.Set('chart.ymax',obj.max);for(var i=0,len=obj.original_data.length;i<len;++i){for(var j=0;j<obj.original_data[i].length;++j){obj.original_data[i][j]=(obj.Get('chart.filled')&&obj.Get('chart.filled.accumulative')&&i>0)?0:half;}}
|
235
|
+
RG.clear(obj.canvas);obj.trace2({frames:frames/2},unfoldCallback);return obj;};this.unfoldFromCenter=function()
|
236
|
+
{var obj=this;var opt=arguments[0]||{};var frames=opt.frames||30;var frame=0;var callback=arguments[1]||function(){};obj.canvas.style.visibility='hidden';obj.Draw();var max=obj.scale2.max;RG.clear(obj.canvas);obj.canvas.style.visibility='visible';var center_value=obj.Get('chart.xaxispos')==='center'?prop['chart.ymin']:((obj.max-obj.min)/2)+obj.min;var original_data=RG.array_clone(obj.original_data);var steps=null;obj.Set('chart.ymax',max);if(!steps){steps=[];for(var dataset=0,len=original_data.length;dataset<len;++dataset){steps[dataset]=[]
|
237
|
+
for(var i=0,len2=original_data[dataset].length;i<len2;++i){if(prop['chart.filled']&&prop['chart.filled.accumulative']&&dataset>0){steps[dataset][i]=original_data[dataset][i]/frames;obj.original_data[dataset][i]=center_value;}else{steps[dataset][i]=(original_data[dataset][i]-center_value)/frames;obj.original_data[dataset][i]=center_value;}}}}
|
238
|
+
function unfoldFromCenter()
|
239
|
+
{for(var dataset=0;dataset<original_data.length;++dataset){for(var i=0;i<original_data[dataset].length;++i){obj.original_data[dataset][i]+=steps[dataset][i];}}
|
240
|
+
RG.clear(obj.canvas);RG.redrawCanvas(obj.canvas);if(--frames>0){RG.Effects.updateCanvas(unfoldFromCenter);}else{obj.original_data=RG.array_clone(original_data);RG.clear(obj.canvas);RG.redrawCanvas(obj.canvas);callback(obj);}}
|
241
|
+
unfoldFromCenter();return this;};RG.att(ca);RG.Register(this);if(parseConfObjectForOptions){RG.parseObjectStyleConfig(this,conf.options);}
|
242
|
+
for(var i=0;i<this.original_data.length;++i){prop['chart.line.visible'][i]=true;}};
|