rgraph-rails 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/.travis.yml +0 -1
- data/README.md +3 -3
- data/lib/rgraph-rails/version.rb +1 -1
- data/vendor/assets/javascripts/RGraph.bar.js +239 -3764
- data/vendor/assets/javascripts/RGraph.bipolar.js +115 -1986
- data/vendor/assets/javascripts/RGraph.common.annotate.js +35 -399
- data/vendor/assets/javascripts/RGraph.common.context.js +30 -600
- data/vendor/assets/javascripts/RGraph.common.core.js +403 -5187
- data/vendor/assets/javascripts/RGraph.common.csv.js +19 -275
- data/vendor/assets/javascripts/RGraph.common.deprecated.js +35 -454
- data/vendor/assets/javascripts/RGraph.common.dynamic.js +84 -1189
- data/vendor/assets/javascripts/RGraph.common.effects.js +90 -1548
- data/vendor/assets/javascripts/RGraph.common.key.js +54 -755
- data/vendor/assets/javascripts/RGraph.common.resizing.js +37 -567
- data/vendor/assets/javascripts/RGraph.common.sheets.js +29 -356
- data/vendor/assets/javascripts/RGraph.common.tooltips.js +32 -614
- data/vendor/assets/javascripts/RGraph.common.zoom.js +14 -223
- data/vendor/assets/javascripts/RGraph.cornergauge.js +71 -0
- data/vendor/assets/javascripts/RGraph.drawing.background.js +35 -620
- data/vendor/assets/javascripts/RGraph.drawing.circle.js +35 -576
- data/vendor/assets/javascripts/RGraph.drawing.image.js +52 -807
- data/vendor/assets/javascripts/RGraph.drawing.marker1.js +41 -717
- data/vendor/assets/javascripts/RGraph.drawing.marker2.js +37 -668
- data/vendor/assets/javascripts/RGraph.drawing.marker3.js +36 -563
- data/vendor/assets/javascripts/RGraph.drawing.poly.js +40 -608
- data/vendor/assets/javascripts/RGraph.drawing.rect.js +35 -597
- data/vendor/assets/javascripts/RGraph.drawing.text.js +34 -642
- data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +50 -809
- data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +51 -856
- data/vendor/assets/javascripts/RGraph.fuel.js +58 -964
- data/vendor/assets/javascripts/RGraph.funnel.js +55 -984
- data/vendor/assets/javascripts/RGraph.gantt.js +75 -1241
- data/vendor/assets/javascripts/RGraph.gauge.js +87 -1397
- data/vendor/assets/javascripts/RGraph.hbar.js +143 -2376
- data/vendor/assets/javascripts/RGraph.hprogress.js +80 -1397
- data/vendor/assets/javascripts/RGraph.line.js +241 -4162
- data/vendor/assets/javascripts/RGraph.meter.js +74 -1278
- metadata +3 -30
- data/vendor/assets/images/bg.png +0 -0
- data/vendor/assets/images/bullet.png +0 -0
- data/vendor/assets/images/facebook-large.png +0 -0
- data/vendor/assets/images/google-plus-large.png +0 -0
- data/vendor/assets/images/logo.png +0 -0
- data/vendor/assets/images/meter-image-sd-needle.png +0 -0
- data/vendor/assets/images/meter-image-sd.png +0 -0
- data/vendor/assets/images/meter-sketch-needle.png +0 -0
- data/vendor/assets/images/meter-sketch.png +0 -0
- data/vendor/assets/images/odometer-background.png +0 -0
- data/vendor/assets/images/rgraph.jpg +0 -0
- data/vendor/assets/images/title.png +0 -0
- data/vendor/assets/images/twitter-large.png +0 -0
- data/vendor/assets/javascripts/RGraph.modaldialog.js +0 -301
- data/vendor/assets/javascripts/RGraph.odo.js +0 -1265
- data/vendor/assets/javascripts/RGraph.pie.js +0 -2272
- data/vendor/assets/javascripts/RGraph.radar.js +0 -1847
- data/vendor/assets/javascripts/RGraph.rose.js +0 -1877
- data/vendor/assets/javascripts/RGraph.rscatter.js +0 -1425
- data/vendor/assets/javascripts/RGraph.scatter.js +0 -2970
- data/vendor/assets/javascripts/RGraph.semicircularprogress.js +0 -1015
- data/vendor/assets/javascripts/RGraph.thermometer.js +0 -1129
- data/vendor/assets/javascripts/RGraph.vprogress.js +0 -1452
- data/vendor/assets/javascripts/RGraph.waterfall.js +0 -1252
- data/vendor/assets/javascripts/financial-data.js +0 -1067
- data/vendor/assets/stylesheets/ModalDialog.css +0 -90
- data/vendor/assets/stylesheets/animations.css +0 -3347
- data/vendor/assets/stylesheets/website.css +0 -446
@@ -1,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;}};
|