rgraph-rails 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +0 -1
  3. data/README.md +3 -3
  4. data/lib/rgraph-rails/version.rb +1 -1
  5. data/vendor/assets/javascripts/RGraph.bar.js +239 -3764
  6. data/vendor/assets/javascripts/RGraph.bipolar.js +115 -1986
  7. data/vendor/assets/javascripts/RGraph.common.annotate.js +35 -399
  8. data/vendor/assets/javascripts/RGraph.common.context.js +30 -600
  9. data/vendor/assets/javascripts/RGraph.common.core.js +403 -5187
  10. data/vendor/assets/javascripts/RGraph.common.csv.js +19 -275
  11. data/vendor/assets/javascripts/RGraph.common.deprecated.js +35 -454
  12. data/vendor/assets/javascripts/RGraph.common.dynamic.js +84 -1189
  13. data/vendor/assets/javascripts/RGraph.common.effects.js +90 -1548
  14. data/vendor/assets/javascripts/RGraph.common.key.js +54 -755
  15. data/vendor/assets/javascripts/RGraph.common.resizing.js +37 -567
  16. data/vendor/assets/javascripts/RGraph.common.sheets.js +29 -356
  17. data/vendor/assets/javascripts/RGraph.common.tooltips.js +32 -614
  18. data/vendor/assets/javascripts/RGraph.common.zoom.js +14 -223
  19. data/vendor/assets/javascripts/RGraph.cornergauge.js +71 -0
  20. data/vendor/assets/javascripts/RGraph.drawing.background.js +35 -620
  21. data/vendor/assets/javascripts/RGraph.drawing.circle.js +35 -576
  22. data/vendor/assets/javascripts/RGraph.drawing.image.js +52 -807
  23. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +41 -717
  24. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +37 -668
  25. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +36 -563
  26. data/vendor/assets/javascripts/RGraph.drawing.poly.js +40 -608
  27. data/vendor/assets/javascripts/RGraph.drawing.rect.js +35 -597
  28. data/vendor/assets/javascripts/RGraph.drawing.text.js +34 -642
  29. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +50 -809
  30. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +51 -856
  31. data/vendor/assets/javascripts/RGraph.fuel.js +58 -964
  32. data/vendor/assets/javascripts/RGraph.funnel.js +55 -984
  33. data/vendor/assets/javascripts/RGraph.gantt.js +75 -1241
  34. data/vendor/assets/javascripts/RGraph.gauge.js +87 -1397
  35. data/vendor/assets/javascripts/RGraph.hbar.js +143 -2376
  36. data/vendor/assets/javascripts/RGraph.hprogress.js +80 -1397
  37. data/vendor/assets/javascripts/RGraph.line.js +241 -4162
  38. data/vendor/assets/javascripts/RGraph.meter.js +74 -1278
  39. metadata +3 -30
  40. data/vendor/assets/images/bg.png +0 -0
  41. data/vendor/assets/images/bullet.png +0 -0
  42. data/vendor/assets/images/facebook-large.png +0 -0
  43. data/vendor/assets/images/google-plus-large.png +0 -0
  44. data/vendor/assets/images/logo.png +0 -0
  45. data/vendor/assets/images/meter-image-sd-needle.png +0 -0
  46. data/vendor/assets/images/meter-image-sd.png +0 -0
  47. data/vendor/assets/images/meter-sketch-needle.png +0 -0
  48. data/vendor/assets/images/meter-sketch.png +0 -0
  49. data/vendor/assets/images/odometer-background.png +0 -0
  50. data/vendor/assets/images/rgraph.jpg +0 -0
  51. data/vendor/assets/images/title.png +0 -0
  52. data/vendor/assets/images/twitter-large.png +0 -0
  53. data/vendor/assets/javascripts/RGraph.modaldialog.js +0 -301
  54. data/vendor/assets/javascripts/RGraph.odo.js +0 -1265
  55. data/vendor/assets/javascripts/RGraph.pie.js +0 -2272
  56. data/vendor/assets/javascripts/RGraph.radar.js +0 -1847
  57. data/vendor/assets/javascripts/RGraph.rose.js +0 -1877
  58. data/vendor/assets/javascripts/RGraph.rscatter.js +0 -1425
  59. data/vendor/assets/javascripts/RGraph.scatter.js +0 -2970
  60. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +0 -1015
  61. data/vendor/assets/javascripts/RGraph.thermometer.js +0 -1129
  62. data/vendor/assets/javascripts/RGraph.vprogress.js +0 -1452
  63. data/vendor/assets/javascripts/RGraph.waterfall.js +0 -1252
  64. data/vendor/assets/javascripts/financial-data.js +0 -1067
  65. data/vendor/assets/stylesheets/ModalDialog.css +0 -90
  66. data/vendor/assets/stylesheets/animations.css +0 -3347
  67. data/vendor/assets/stylesheets/website.css +0 -446
@@ -1,2970 +0,0 @@
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
-
16
- RGraph = window.RGraph || {isRGraph: true};
17
-
18
-
19
-
20
-
21
- /**
22
- * The scatter graph constructor
23
- *
24
- * @param object canvas The cxanvas object
25
- * @param array data The chart data
26
- */
27
- RGraph.Scatter = function (conf)
28
- {
29
- /**
30
- * Allow for object config style
31
- */
32
- if ( typeof conf === 'object'
33
- && typeof conf.data === 'object'
34
- && typeof conf.id === 'string') {
35
-
36
- var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
37
-
38
- this.data = new Array(conf.data.length);
39
-
40
- // Store the data set(s)
41
- this.data = RGraph.arrayClone(conf.data);
42
-
43
-
44
- // Account for just one dataset being given
45
- if (typeof conf.data === 'object' && typeof conf.data[0] === 'object' && (typeof conf.data[0][0] === 'number' || typeof conf.data[0][0] === 'string')) {
46
- var tmp = RGraph.arrayClone(conf.data);
47
- conf.data = new Array();
48
- conf.data[0] = RGraph.arrayClone(tmp);
49
-
50
- this.data = RGraph.arrayClone(conf.data);
51
- }
52
-
53
- } else {
54
-
55
- var conf = {id: conf};
56
- conf.data = arguments[1];
57
-
58
-
59
- this.data = [];
60
-
61
- // Handle multiple datasets being given as one argument
62
- if (arguments[1][0] && arguments[1][0][0] && typeof arguments[1][0][0] == 'object') {
63
- // Store the data set(s)
64
- for (var i=0; i<arguments[1].length; ++i) {
65
- this.data[i] = RGraph.arrayClone(arguments[1][i]);
66
- }
67
-
68
- // Handle multiple data sets being supplied as seperate arguments
69
- } else {
70
-
71
- // Store the data set(s)
72
- for (var i=1; i<arguments.length; ++i) {
73
- this.data[i - 1] = RGraph.arrayClone(arguments[i]);
74
- }
75
- }
76
- }
77
-
78
- // If necessary convert X/Y values passed as strings to numbers
79
- for (var i=0,len=this.data.length; i<len; ++i) { // Datasets
80
- for (var j=0,len2=this.data[i].length; j<len2; ++j) { // Points
81
-
82
- // Handle the conversion of X values
83
- if (typeof this.data[i][j] === 'object' && !RGraph.isNull(this.data[i][j]) && typeof this.data[i][j][0] === 'string') {
84
- if (this.data[i][j][0].match(/^[.0-9]+$/)) {
85
- this.data[i][j][0] = parseFloat(this.data[i][j][0]);
86
- } else if (this.data[i][j][0] === '') {
87
- this.data[i][j][0] = 0;
88
- }
89
- }
90
-
91
- // Handle the conversion of Y values
92
- if (typeof this.data[i][j] === 'object' && !RGraph.isNull(this.data[i][j]) && typeof this.data[i][j][1] === 'string') {
93
- if (this.data[i][j][1].match(/[.0-9]+/)) {
94
- this.data[i][j][1] = parseFloat(this.data[i][j][1]);
95
- } else if (this.data[i][j][1] === '') {
96
- this.data[i][j][1] = 0;
97
- }
98
- }
99
- }
100
- }
101
-
102
-
103
- this.id = conf.id;
104
- this.canvas = document.getElementById(this.id);
105
- this.canvas.__object__ = this;
106
- this.context = this.canvas.getContext ? this.canvas.getContext('2d') : null;
107
- this.max = 0;
108
- this.coords = [];
109
- this.type = 'scatter';
110
- this.isRGraph = true;
111
- this.uid = RGraph.CreateUID();
112
- this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
113
- this.colorsParsed = false;
114
- this.coordsText = [];
115
- this.original_colors = [];
116
- this.firstDraw = true; // After the first draw this will be false
117
-
118
-
119
-
120
-
121
- // Handle multiple datasets being given as one argument
122
- //if (arguments[1][0] && arguments[1][0][0] && typeof(arguments[1][0][0]) == 'object') {
123
- // // Store the data set(s)
124
- // for (var i=0; i<arguments[1].length; ++i) {
125
- // this.data[i] = arguments[1][i];
126
- // }
127
-
128
- // Handle multiple data sets being supplied as seperate arguments
129
- //} else {
130
- // Store the data set(s)
131
- //for (var i=1; i<arguments.length; ++i) {
132
- // this.data[i - 1] = arguments[i];
133
- //}
134
- //}
135
-
136
-
137
- // Various config properties
138
- this.properties = {
139
- 'chart.background.barcolor1': 'rgba(0,0,0,0)',
140
- 'chart.background.barcolor2': 'rgba(0,0,0,0)',
141
- 'chart.background.grid': true,
142
- 'chart.background.grid.width': 1,
143
- 'chart.background.grid.color': '#ddd',
144
- 'chart.background.grid.hsize': 20,
145
- 'chart.background.grid.vsize': 20,
146
- 'chart.background.hbars': null,
147
- 'chart.background.vbars': null,
148
- 'chart.background.grid.vlines': true,
149
- 'chart.background.grid.hlines': true,
150
- 'chart.background.grid.border': true,
151
- 'chart.background.grid.autofit':true,
152
- 'chart.background.grid.autofit.align': true,
153
- 'chart.background.grid.autofit.numhlines': 5,
154
- 'chart.background.grid.autofit.numvlines': 20,
155
- 'chart.background.image': null,
156
- 'chart.background.image.stretch': true,
157
- 'chart.background.image.x': null,
158
- 'chart.background.image.y': null,
159
- 'chart.background.image.w': null,
160
- 'chart.background.image.h': null,
161
- 'chart.background.image.align': null,
162
- 'chart.background.color': null,
163
- 'chart.text.size': 12,
164
- 'chart.text.angle': 0,
165
- 'chart.text.color': 'black',
166
- 'chart.text.font': 'Segoe UI, Arial, Verdana, sans-serif',
167
- 'chart.text.accessible': true,
168
- 'chart.text.accessible.overflow': 'visible',
169
- 'chart.text.accessible.pointerevents': false,
170
- 'chart.tooltips': [], // Default must be an empty array
171
- 'chart.tooltips.effect': 'fade',
172
- 'chart.tooltips.event': 'onmousemove',
173
- 'chart.tooltips.hotspot': 3,
174
- 'chart.tooltips.css.class': 'RGraph_tooltip',
175
- 'chart.tooltips.highlight': true,
176
- 'chart.tooltips.coords.page': false,
177
- 'chart.units.pre': '',
178
- 'chart.units.post': '',
179
- 'chart.numyticks': 10,
180
- 'chart.tickmarks': 'cross',
181
- 'chart.tickmarks.image.halign': 'center',
182
- 'chart.tickmarks.image.valign': 'center',
183
- 'chart.tickmarks.image.offsetx': 0,
184
- 'chart.tickmarks.image.offsety': 0,
185
- 'chart.ticksize': 5,
186
- 'chart.numxticks': true,
187
- 'chart.xaxis': true,
188
- 'chart.gutter.left': 25,
189
- 'chart.gutter.right': 25,
190
- 'chart.gutter.top': 25,
191
- 'chart.gutter.bottom': 30,
192
- 'chart.xmin': 0,
193
- 'chart.xmax': 0,
194
- 'chart.ymax': null,
195
- 'chart.ymin': 0,
196
- 'chart.scale.decimals': 0,
197
- 'chart.scale.point': '.',
198
- 'chart.scale.thousand': ',',
199
- 'chart.scale.zerostart': true,
200
- 'chart.title': '',
201
- 'chart.title.background': null,
202
- 'chart.title.hpos': null,
203
- 'chart.title.vpos': null,
204
- 'chart.title.bold': true,
205
- 'chart.title.font': null,
206
- 'chart.title.xaxis': '',
207
- 'chart.title.xaxis.bold': true,
208
- 'chart.title.xaxis.size': null,
209
- 'chart.title.xaxis.font': null,
210
- 'chart.title.yaxis': '',
211
- 'chart.title.yaxis.bold': true,
212
- 'chart.title.yaxis.size': null,
213
- 'chart.title.yaxis.font': null,
214
- 'chart.title.yaxis.color': null,
215
- 'chart.title.xaxis.pos': null,
216
- 'chart.title.yaxis.pos': null,
217
- 'chart.title.yaxis.x': null,
218
- 'chart.title.yaxis.y': null,
219
- 'chart.title.xaxis.x': null,
220
- 'chart.title.xaxis.y': null,
221
- 'chart.title.x': null,
222
- 'chart.title.y': null,
223
- 'chart.title.halign': null,
224
- 'chart.title.valign': null,
225
- 'chart.labels': [],
226
- 'chart.labels.bold': false,
227
- 'chart.labels.color': null,
228
- 'chart.labels.ingraph': null,
229
- 'chart.labels.above': false,
230
- 'chart.labels.above.size': 8,
231
- 'chart.labels.above.decimals': 0,
232
- 'chart.labels.offsetx': 0,
233
- 'chart.labels.offsety': 0,
234
- 'chart.ylabels.offsetx': 0,
235
- 'chart.ylabels.offsety': 0,
236
- 'chart.ylabels': true,
237
- 'chart.ylabels.count': 5,
238
- 'chart.ylabels.invert': false,
239
- 'chart.ylabels.specific': null,
240
- 'chart.ylabels.inside': false,
241
- 'chart.contextmenu': null,
242
- 'chart.defaultcolor': 'black',
243
- 'chart.xaxispos': 'bottom',
244
- 'chart.yaxispos': 'left',
245
- 'chart.crosshairs': false,
246
- 'chart.crosshairs.color': '#333',
247
- 'chart.crosshairs.linewidth': 1,
248
- 'chart.crosshairs.coords': false,
249
- 'chart.crosshairs.coords.fixed':true,
250
- 'chart.crosshairs.coords.fadeout':false,
251
- 'chart.crosshairs.coords.labels.x': 'X',
252
- 'chart.crosshairs.coords.labels.y': 'Y',
253
- 'chart.crosshairs.hline': true,
254
- 'chart.crosshairs.vline': true,
255
- 'chart.annotatable': false,
256
- 'chart.annotate.color': 'black',
257
- 'chart.line': false,
258
- 'chart.line.linewidth': 1,
259
- 'chart.line.colors': ['green', 'red'],
260
- 'chart.line.shadow.color': 'rgba(0,0,0,0)',
261
- 'chart.line.shadow.blur': 2,
262
- 'chart.line.shadow.offsetx': 3,
263
- 'chart.line.shadow.offsety': 3,
264
- 'chart.line.stepped': false,
265
- 'chart.line.visible': true,
266
- 'chart.noaxes': false,
267
- 'chart.noyaxis': false,
268
- 'chart.key': null,
269
- 'chart.key.background': 'white',
270
- 'chart.key.position': 'graph',
271
- 'chart.key.halign': 'right',
272
- 'chart.key.shadow': false,
273
- 'chart.key.shadow.color': '#666',
274
- 'chart.key.shadow.blur': 3,
275
- 'chart.key.shadow.offsetx': 2,
276
- 'chart.key.shadow.offsety': 2,
277
- 'chart.key.position.gutter.boxed': false,
278
- 'chart.key.position.x': null,
279
- 'chart.key.position.y': null,
280
-
281
- 'chart.key.interactive': false,
282
- 'chart.key.interactive.highlight.chart.fill': 'rgba(255,0,0,0.9)',
283
- 'chart.key.interactive.highlight.label': 'rgba(255,0,0,0.2)',
284
-
285
- 'chart.key.color.shape': 'square',
286
- 'chart.key.rounded': true,
287
- 'chart.key.linewidth': 1,
288
- 'chart.key.colors': null,
289
- 'chart.key.text.color': 'black',
290
- 'chart.axis.color': 'black',
291
- 'chart.zoom.factor': 1.5,
292
- 'chart.zoom.fade.in': true,
293
- 'chart.zoom.fade.out': true,
294
- 'chart.zoom.hdir': 'right',
295
- 'chart.zoom.vdir': 'down',
296
- 'chart.zoom.frames': 25,
297
- 'chart.zoom.delay': 16.666,
298
- 'chart.zoom.shadow': true,
299
- 'chart.zoom.background': true,
300
- 'chart.zoom.action': 'zoom',
301
- 'chart.boxplot.width': 1,
302
- 'chart.boxplot.capped': true,
303
- 'chart.resizable': false,
304
- 'chart.resize.handle.background': null,
305
- 'chart.xmin': 0,
306
- 'chart.labels.specific.align': 'left',
307
- 'chart.xscale': false,
308
- 'chart.xscale.units.pre': '',
309
- 'chart.xscale.units.post': '',
310
- 'chart.xscale.numlabels': 10,
311
- 'chart.xscale.formatter': null,
312
- 'chart.xscale.decimals': 0,
313
- 'chart.xscale.thousand': ',',
314
- 'chart.xscale.point': '.',
315
- 'chart.noendxtick': false,
316
- 'chart.noendytick': true,
317
- 'chart.events.mousemove': null,
318
- 'chart.events.click': null,
319
- 'chart.highlight.stroke': 'rgba(0,0,0,0)',
320
- 'chart.highlight.fill': 'rgba(255,255,255,0.7)',
321
- 'chart.clearto': 'rgba(0,0,0,0)',
322
- 'chart.animation.trace': false,
323
- 'chart.animation.trace.clip': 1
324
- }
325
-
326
- /**
327
- * This allows the data points to be given as dates as well as numbers. Formats supported by RGraph.parseDate() are accepted.
328
- *
329
- * ALSO: unrelated but this loop is also used to convert null values to an
330
- * empty array
331
- */
332
- for (var i=0; i<this.data.length; ++i) {
333
- for (var j=0; j<this.data[i].length; ++j) {
334
-
335
- // Convert null data points to an empty erray
336
- if ( RGraph.isNull(this.data[i][j]) ) {
337
- this.data[i][j] = [];
338
- }
339
-
340
- // Allow for the X point to be dates
341
- if (this.data[i][j] && typeof(this.data[i][j][0]) == 'string') {
342
- this.data[i][j][0] = RGraph.parseDate(this.data[i][j][0]);
343
- }
344
- }
345
- }
346
-
347
-
348
- /**
349
- * Now make the data_arr array - all the data as one big array
350
- */
351
- this.data_arr = [];
352
-
353
- for (var i=0; i<this.data.length; ++i) {
354
- for (var j=0; j<this.data[i].length; ++j) {
355
- this.data_arr.push(this.data[i][j]);
356
- }
357
- }
358
-
359
- // Create the $ objects so that they can be used
360
- for (var i=0; i<this.data_arr.length; ++i) {
361
- this['$' + i] = {}
362
- }
363
-
364
-
365
- // Check for support
366
- if (!this.canvas) {
367
- alert('[SCATTER] No canvas support');
368
- return;
369
- }
370
-
371
-
372
- /**
373
- * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
374
- * done already
375
- */
376
- if (!this.canvas.__rgraph_aa_translated__) {
377
- this.context.translate(0.5,0.5);
378
-
379
- this.canvas.__rgraph_aa_translated__ = true;
380
- }
381
-
382
-
383
-
384
- // Short variable names
385
- var RG = RGraph,
386
- ca = this.canvas,
387
- co = ca.getContext('2d'),
388
- prop = this.properties,
389
- pa2 = RG.path2,
390
- win = window,
391
- doc = document,
392
- ma = Math
393
-
394
-
395
-
396
- /**
397
- * "Decorate" the object with the generic effects if the effects library has been included
398
- */
399
- if (RG.Effects && typeof RG.Effects.decorate === 'function') {
400
- RG.Effects.decorate(this);
401
- }
402
-
403
-
404
-
405
-
406
-
407
-
408
-
409
- /**
410
- * A simple setter
411
- *
412
- * @param string name The name of the property to set
413
- * @param string value The value of the property
414
- */
415
- this.set =
416
- this.Set = function (name)
417
- {
418
- var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
419
-
420
- /**
421
- * the number of arguments is only one and it's an
422
- * object - parse it for configuration data and return.
423
- */
424
- if (arguments.length === 1 && typeof name === 'object') {
425
- RG.parseObjectStyleConfig(this, name);
426
- return this;
427
- }
428
-
429
-
430
-
431
- /**
432
- * This should be done first - prepend the propertyy name with "chart." if necessary
433
- */
434
- if (name.substr(0,6) != 'chart.') {
435
- name = 'chart.' + name;
436
- }
437
-
438
-
439
-
440
-
441
- // Convert uppercase letters to dot+lower case letter
442
- while(name.match(/([A-Z])/)) {
443
- name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
444
- }
445
-
446
-
447
-
448
-
449
-
450
-
451
-
452
- /**
453
- * BC for chart.xticks
454
- */
455
- if (name == 'chart.xticks') {
456
- name == 'chart.numxticks';
457
- }
458
-
459
- /**
460
- * This is here because the key expects a name of "chart.colors"
461
- */
462
- if (name == 'chart.line.colors') {
463
- prop['chart.colors'] = value;
464
- }
465
-
466
- /**
467
- * Allow compatibility with older property names
468
- */
469
- if (name == 'chart.tooltip.hotspot') {
470
- name = 'chart.tooltips.hotspot';
471
- }
472
-
473
-
474
- /**
475
- * chart.yaxispos should be left or right
476
- */
477
- if (name == 'chart.yaxispos' && value != 'left' && value != 'right') {
478
- alert("[SCATTER] chart.yaxispos should be left or right. You've set it to: '" + value + "' Changing it to left");
479
- value = 'left';
480
- }
481
-
482
- /**
483
- * Check for xaxispos
484
- */
485
- if (name == 'chart.xaxispos' ) {
486
- if (value != 'bottom' && value != 'center') {
487
- alert('[SCATTER] (' + this.id + ') chart.xaxispos should be center or bottom. Tried to set it to: ' + value + ' Changing it to center');
488
- value = 'center';
489
- }
490
- }
491
-
492
- /**
493
- * Compatibility for chart.noxaxisoption
494
- */
495
- if (name == 'chart.noxaxis' ) {
496
- name = 'chart.xaxis';
497
- value = !value;
498
- }
499
- prop[name.toLowerCase()] = value;
500
-
501
- return this;
502
- };
503
-
504
-
505
-
506
-
507
- /**
508
- * A simple getter
509
- *
510
- * @param string name The name of the property to set
511
- */
512
- this.get =
513
- this.Get = function (name)
514
- {
515
- /**
516
- * This should be done first - prepend the property name with "chart." if necessary
517
- */
518
- if (name.substr(0,6) != 'chart.') {
519
- name = 'chart.' + name;
520
- }
521
-
522
- // Convert uppercase letters to dot+lower case letter
523
- name = name.replace(/([A-Z])/g, function (str)
524
- {
525
- return '.' + String(RegExp.$1).toLowerCase()
526
- });
527
-
528
- return prop[name];
529
- };
530
-
531
-
532
-
533
-
534
- /**
535
- * The function you call to draw the line chart
536
- */
537
- this.draw =
538
- this.Draw = function ()
539
- {
540
- // MUST be the first thing done!
541
- if (typeof prop['chart.background.image'] === 'string') {
542
- RG.DrawBackgroundImage(this);
543
- }
544
-
545
-
546
- /**
547
- * Fire the onbeforedraw event
548
- */
549
- RG.fireCustomEvent(this, 'onbeforedraw');
550
-
551
-
552
- /**
553
- * Parse the colors. This allows for simple gradient syntax
554
- */
555
- if (!this.colorsParsed) {
556
- this.parseColors();
557
-
558
- // Don't want to do this again
559
- this.colorsParsed = true;
560
- }
561
-
562
-
563
-
564
-
565
- /**
566
- * Stop this growing uncontrollably
567
- */
568
- this.coordsText = [];
569
-
570
-
571
-
572
-
573
- /**
574
- * This is new in May 2011 and facilitates indiviual gutter settings,
575
- * eg chart.gutter.left
576
- */
577
- this.gutterLeft = prop['chart.gutter.left'];
578
- this.gutterRight = prop['chart.gutter.right'];
579
- this.gutterTop = prop['chart.gutter.top'];
580
- this.gutterBottom = prop['chart.gutter.bottom'];
581
-
582
- // Go through all the data points and see if a tooltip has been given
583
- this.hasTooltips = false;
584
- var overHotspot = false;
585
-
586
- // Reset the coords array
587
- this.coords = [];
588
-
589
- /**
590
- * This facilitates the xmax, xmin and X values being dates
591
- */
592
- if (typeof(prop['chart.xmin']) == 'string') prop['chart.xmin'] = RG.parseDate(prop['chart.xmin']);
593
- if (typeof(prop['chart.xmax']) == 'string') prop['chart.xmax'] = RG.parseDate(prop['chart.xmax']);
594
-
595
- /**
596
- * Look for tooltips and populate chart.tooltips
597
- *
598
- * NB 26/01/2011 Updated so that chart.tooltips is ALWAYS populated
599
- */
600
- if (!RGraph.ISOLD) {
601
- this.Set('chart.tooltips', []);
602
- for (var i=0,len=this.data.length; i<len; i+=1) {
603
- for (var j =0,len2=this.data[i].length;j<len2; j+=1) {
604
-
605
- if (this.data[i][j] && this.data[i][j][3]) {
606
- prop['chart.tooltips'].push(this.data[i][j][3]);
607
- this.hasTooltips = true;
608
- } else {
609
- prop['chart.tooltips'].push(null);
610
- }
611
- }
612
- }
613
- }
614
-
615
- // Reset the maximum value
616
- this.max = 0;
617
-
618
- // Work out the maximum Y value
619
- //if (prop['chart.ymax'] && prop['chart.ymax'] > 0) {
620
- if (typeof prop['chart.ymax'] === 'number') {
621
-
622
- this.max = prop['chart.ymax'];
623
- this.min = prop['chart.ymin'] ? prop['chart.ymin'] : 0;
624
-
625
-
626
- this.scale2 = RG.getScale2(this, {
627
- 'max':this.max,
628
- 'min':this.min,
629
- 'strict':true,
630
- 'scale.thousand':prop['chart.scale.thousand'],
631
- 'scale.point':prop['chart.scale.point'],
632
- 'scale.decimals':prop['chart.scale.decimals'],
633
- 'ylabels.count':prop['chart.ylabels.count'],
634
- 'scale.round':prop['chart.scale.round'],
635
- 'units.pre': prop['chart.units.pre'],
636
- 'units.post': prop['chart.units.post']
637
- });
638
-
639
- this.max = this.scale2.max;
640
- this.min = this.scale2.min;
641
- var decimals = prop['chart.scale.decimals'];
642
-
643
- } else {
644
-
645
- var i = 0;
646
- var j = 0;
647
-
648
- for (i=0,len=this.data.length; i<len; i+=1) {
649
- for (j=0,len2=this.data[i].length; j<len2; j+=1) {
650
- if (!RG.isNull(this.data[i][j]) && this.data[i][j][1] != null) {
651
- this.max = Math.max(this.max, typeof(this.data[i][j][1]) == 'object' ? RG.array_max(this.data[i][j][1]) : Math.abs(this.data[i][j][1]));
652
- }
653
- }
654
- }
655
-
656
- this.min = prop['chart.ymin'] ? prop['chart.ymin'] : 0;
657
-
658
- this.scale2 = RG.getScale2(this, {
659
- 'max':this.max,
660
- 'min':this.min,
661
- 'scale.thousand':prop['chart.scale.thousand'],
662
- 'scale.point':prop['chart.scale.point'],
663
- 'scale.decimals':prop['chart.scale.decimals'],
664
- 'ylabels.count':prop['chart.ylabels.count'],
665
- 'scale.round':prop['chart.scale.round'],
666
- 'units.pre': prop['chart.units.pre'],
667
- 'units.post': prop['chart.units.post']
668
- });
669
-
670
- this.max = this.scale2.max;
671
- this.min = this.scale2.min;
672
- }
673
-
674
- this.grapharea = ca.height - this.gutterTop - this.gutterBottom;
675
-
676
-
677
-
678
- // Progressively Draw the chart
679
- RG.background.Draw(this);
680
-
681
- /**
682
- * Draw any horizontal bars that have been specified
683
- */
684
- if (prop['chart.background.hbars'] && prop['chart.background.hbars'].length) {
685
- RG.DrawBars(this);
686
- }
687
-
688
- /**
689
- * Draw any vertical bars that have been specified
690
- */
691
- if (prop['chart.background.vbars'] && prop['chart.background.vbars'].length) {
692
- this.DrawVBars();
693
- }
694
-
695
- if (!prop['chart.noaxes']) {
696
- this.DrawAxes();
697
- }
698
-
699
- this.DrawLabels();
700
-
701
- // Clip the canvas so that the trace2 effect is facilitated
702
- if (prop['chart.animation.trace']) {
703
- co.save();
704
- co.beginPath();
705
- co.rect(0, 0, ca.width * prop['chart.animation.trace.clip'], ca.height);
706
- co.clip();
707
- }
708
-
709
- for(i=0; i<this.data.length; ++i) {
710
- this.DrawMarks(i);
711
-
712
- // Set the shadow
713
- co.shadowColor = prop['chart.line.shadow.color'];
714
- co.shadowOffsetX = prop['chart.line.shadow.offsetx'];
715
- co.shadowOffsetY = prop['chart.line.shadow.offsety'];
716
- co.shadowBlur = prop['chart.line.shadow.blur'];
717
-
718
- this.DrawLine(i);
719
-
720
- // Turn the shadow off
721
- RG.NoShadow(this);
722
- }
723
-
724
-
725
- if (prop['chart.line']) {
726
- for (var i=0,len=this.data.length;i<len; i+=1) {
727
- this.DrawMarks(i); // Call this again so the tickmarks appear over the line
728
- }
729
- }
730
-
731
- if (prop['chart.animation.trace']) {
732
- co.restore();
733
- }
734
-
735
-
736
-
737
- /**
738
- * Setup the context menu if required
739
- */
740
- if (prop['chart.contextmenu']) {
741
- RG.ShowContext(this);
742
- }
743
-
744
-
745
-
746
- /**
747
- * Draw the key if necessary
748
- */
749
- if (prop['chart.key'] && prop['chart.key'].length) {
750
- RG.DrawKey(this, prop['chart.key'], prop['chart.line.colors']);
751
- }
752
-
753
-
754
- /**
755
- * Draw " above" labels if enabled
756
- */
757
- if (prop['chart.labels.above']) {
758
- this.DrawAboveLabels();
759
- }
760
-
761
- /**
762
- * Draw the "in graph" labels, using the member function, NOT the shared function in RGraph.common.core.js
763
- */
764
- this.DrawInGraphLabels(this);
765
-
766
-
767
- /**
768
- * This function enables resizing
769
- */
770
- if (prop['chart.resizable']) {
771
- RG.AllowResizing(this);
772
- }
773
-
774
-
775
- /**
776
- * This installs the event listeners
777
- */
778
- RG.InstallEventListeners(this);
779
-
780
-
781
- /**
782
- * Fire the onfirstdraw event
783
- */
784
- if (this.firstDraw) {
785
- RG.fireCustomEvent(this, 'onfirstdraw');
786
- this.firstDraw = false;
787
- this.firstDrawFunc();
788
- }
789
-
790
-
791
-
792
- /**
793
- * Fire the RGraph ondraw event
794
- */
795
- RG.FireCustomEvent(this, 'ondraw');
796
-
797
-
798
- return this;
799
- }
800
-
801
-
802
-
803
-
804
- /**
805
- * Draws the axes of the scatter graph
806
- */
807
- this.drawAxes =
808
- this.DrawAxes = function ()
809
- {
810
- var graphHeight = ca.height - this.gutterTop - this.gutterBottom;
811
-
812
- co.beginPath();
813
- co.strokeStyle = prop['chart.axis.color'];
814
- co.lineWidth = (prop['chart.axis.linewidth'] || 1) + 0.001; // Strange Chrome bug
815
-
816
- // Draw the Y axis
817
- if (prop['chart.noyaxis'] == false) {
818
- if (prop['chart.yaxispos'] == 'left') {
819
- co.moveTo(this.gutterLeft, this.gutterTop);
820
- co.lineTo(this.gutterLeft, ca.height - this.gutterBottom);
821
- } else {
822
- co.moveTo(ca.width - this.gutterRight, this.gutterTop);
823
- co.lineTo(ca.width - this.gutterRight, ca.height - this.gutterBottom);
824
- }
825
- }
826
-
827
-
828
- // Draw the X axis
829
- if (prop['chart.xaxis']) {
830
- if (prop['chart.xaxispos'] == 'center') {
831
- co.moveTo(this.gutterLeft, Math.round(this.gutterTop + ((ca.height - this.gutterTop - this.gutterBottom) / 2)));
832
- co.lineTo(ca.width - this.gutterRight, Math.round(this.gutterTop + ((ca.height - this.gutterTop - this.gutterBottom) / 2)));
833
- } else {
834
- co.moveTo(this.gutterLeft, ca.height - this.gutterBottom);
835
- co.lineTo(ca.width - this.gutterRight, ca.height - this.gutterBottom);
836
- }
837
- }
838
-
839
- // Draw the Y tickmarks
840
- if (prop['chart.noyaxis'] == false) {
841
- var numyticks = prop['chart.numyticks'];
842
-
843
- //for (y=this.gutterTop; y < ca.height - this.gutterBottom + (prop['chart.xaxispos'] == 'center' ? 1 : 0) ; y+=(graphHeight / numyticks)) {
844
- for (i=0; i<numyticks; ++i) {
845
-
846
- var y = ((ca.height - this.gutterTop - this.gutterBottom) / numyticks) * i;
847
- y = y + this.gutterTop;
848
-
849
- if (prop['chart.xaxispos'] == 'center' && i == (numyticks / 2)) {
850
- continue;
851
- }
852
-
853
- if (prop['chart.yaxispos'] == 'left') {
854
- co.moveTo(this.gutterLeft, Math.round(y));
855
- co.lineTo(this.gutterLeft - 3, Math.round(y));
856
- } else {
857
- co.moveTo(ca.width - this.gutterRight +3, Math.round(y));
858
- co.lineTo(ca.width - this.gutterRight, Math.round(y));
859
- }
860
- }
861
-
862
- /**
863
- * Draw the end Y tickmark if the X axis is in the centre
864
- */
865
- if (prop['chart.numyticks'] > 0) {
866
- if (prop['chart.xaxispos'] == 'center' && prop['chart.yaxispos'] == 'left') {
867
- co.moveTo(this.gutterLeft, Math.round(ca.height - this.gutterBottom));
868
- co.lineTo(this.gutterLeft - 3, Math.round(ca.height - this.gutterBottom));
869
- } else if (prop['chart.xaxispos'] == 'center') {
870
- co.moveTo(ca.width - this.gutterRight + 3, Math.round(ca.height - this.gutterBottom));
871
- co.lineTo(ca.width - this.gutterRight, Math.round(ca.height - this.gutterBottom));
872
- }
873
- }
874
-
875
- /**
876
- * Draw an extra tick if the X axis isn't being shown
877
- */
878
- if (prop['chart.xaxis'] == false && prop['chart.yaxispos'] == 'left') {
879
- co.moveTo(this.gutterLeft, Math.round(ca.height - this.gutterBottom));
880
- co.lineTo(this.gutterLeft - 3, Math.round(ca.height - this.gutterBottom));
881
- } else if (prop['chart.xaxis'] == false && prop['chart.yaxispos'] == 'right') {
882
- co.moveTo(ca.width - this.gutterRight, Math.round(ca.height - this.gutterBottom));
883
- co.lineTo(ca.width - this.gutterRight + 3, Math.round(ca.height - this.gutterBottom));
884
- }
885
- }
886
-
887
-
888
- /**
889
- * Draw the X tickmarks
890
- */
891
- if (prop['chart.numxticks'] > 0 && prop['chart.xaxis']) {
892
-
893
- var x = 0;
894
- var y = (prop['chart.xaxispos'] == 'center') ? this.gutterTop + (this.grapharea / 2) : (ca.height - this.gutterBottom);
895
- this.xTickGap = (prop['chart.labels'] && prop['chart.labels'].length) ? ((ca.width - this.gutterLeft - this.gutterRight ) / prop['chart.labels'].length) : (ca.width - this.gutterLeft - this.gutterRight) / 10;
896
-
897
- /**
898
- * This allows the number of X tickmarks to be specified
899
- */
900
- if (typeof(prop['chart.numxticks']) == 'number') {
901
- this.xTickGap = (ca.width - this.gutterLeft - this.gutterRight) / prop['chart.numxticks'];
902
- }
903
-
904
-
905
- for (x=(this.gutterLeft + (prop['chart.yaxispos'] == 'left' && prop['chart.noyaxis'] == false ? this.xTickGap : 0) );
906
- x <= (ca.width - this.gutterRight - (prop['chart.yaxispos'] == 'left' || prop['chart.noyaxis'] == true ? -1 : 1));
907
- x += this.xTickGap) {
908
-
909
- if (prop['chart.yaxispos'] == 'left' && prop['chart.noendxtick'] == true && x == (ca.width - this.gutterRight) ) {
910
- continue;
911
- } else if (prop['chart.yaxispos'] == 'right' && prop['chart.noendxtick'] == true && x == this.gutterLeft) {
912
- continue;
913
- }
914
-
915
- co.moveTo(Math.round(x), y - (prop['chart.xaxispos'] == 'center' ? 3 : 0));
916
- co.lineTo(Math.round(x), y + 3);
917
- }
918
-
919
- }
920
-
921
- co.stroke();
922
-
923
- /**
924
- * Reset the linewidth back to one
925
- */
926
- co.lineWidth = 1;
927
- };
928
-
929
-
930
-
931
-
932
-
933
-
934
-
935
-
936
-
937
-
938
-
939
- /**
940
- * Draws the labels on the scatter graph
941
- */
942
- this.drawLabels =
943
- this.DrawLabels = function ()
944
- {
945
- co.fillStyle = prop['chart.text.color'];
946
-
947
- var font = prop['chart.text.font'],
948
- xMin = prop['chart.xmin'],
949
- xMax = prop['chart.xmax'],
950
- yMax = this.scale2.max,
951
- yMin = prop['chart.ymin'] ? prop['chart.ymin'] : 0,
952
- text_size = prop['chart.text.size'],
953
- units_pre = prop['chart.units.pre'],
954
- units_post = prop['chart.units.post'],
955
- numYLabels = prop['chart.ylabels.count'],
956
- invert = prop['chart.ylabels.invert'],
957
- inside = prop['chart.ylabels.inside'],
958
- context = co,
959
- canvas = ca,
960
- boxed = false,
961
- offsetx = prop['chart.ylabels.offsetx'],
962
- offsety = prop['chart.ylabels.offsety']
963
-
964
- this.halfTextHeight = text_size / 2;
965
-
966
-
967
- this.halfGraphHeight = (ca.height - this.gutterTop - this.gutterBottom) / 2;
968
-
969
- /**
970
- * Draw the Y yaxis labels, be it at the top or center
971
- */
972
- if (prop['chart.ylabels']) {
973
-
974
- var xPos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft - 5 : ca.width - this.gutterRight + 5;
975
- var align = prop['chart.yaxispos'] == 'right' ? 'left' : 'right';
976
-
977
- /**
978
- * Now change the two things above if chart.ylabels.inside is specified
979
- */
980
- if (inside) {
981
- if (prop['chart.yaxispos'] == 'left') {
982
- xPos = prop['chart.gutter.left'] + 5;
983
- align = 'left';
984
- boxed = true;
985
- } else {
986
- xPos = ca.width - prop['chart.gutter.right'] - 5;
987
- align = 'right';
988
- boxed = true;
989
- }
990
- }
991
-
992
- if (prop['chart.xaxispos'] == 'center') {
993
-
994
-
995
- /**
996
- * Specific Y labels
997
- */
998
- if (typeof(prop['chart.ylabels.specific']) == 'object' && prop['chart.ylabels.specific'] != null && prop['chart.ylabels.specific'].length) {
999
-
1000
- var labels = prop['chart.ylabels.specific'];
1001
-
1002
- if (prop['chart.ymin'] > 0) {
1003
- labels = [];
1004
- for (var i=0; i<(prop['chart.ylabels.specific'].length - 1); ++i) {
1005
- labels.push(prop['chart.ylabels.specific'][i]);
1006
- }
1007
- }
1008
-
1009
- for (var i=0; i<labels.length; ++i) {
1010
- var y = this.gutterTop + (i * (this.grapharea / (labels.length * 2) ) );
1011
- RG.Text2(this, {
1012
- 'font':font,
1013
- 'size':text_size,
1014
- 'x':xPos + offsetx,
1015
- 'y':y + offsety,
1016
- 'text':labels[i],
1017
- 'valign':'center',
1018
- 'halign':align,
1019
- 'bounding':boxed,
1020
- 'tag': 'labels.specific'
1021
- });
1022
- }
1023
-
1024
- var reversed_labels = RG.array_reverse(labels);
1025
-
1026
- for (var i=0; i<reversed_labels.length; ++i) {
1027
- var y = this.gutterTop + (this.grapharea / 2) + ((i+1) * (this.grapharea / (labels.length * 2) ) );
1028
- RG.Text2(this, {
1029
- 'font':font,
1030
- 'size':text_size,
1031
- 'x':xPos + offsetx,
1032
- 'y':y + offsety,
1033
- 'text':reversed_labels[i],
1034
- 'valign':'center',
1035
- 'halign':align,
1036
- 'bounding':boxed,
1037
- 'tag': 'labels.specific'
1038
- });
1039
- }
1040
-
1041
- /**
1042
- * Draw the center label if chart.ymin is specified
1043
- */
1044
- if (prop['chart.ymin'] != 0) {
1045
- RG.Text2(this, {
1046
- 'font':font,
1047
- 'size':text_size,
1048
- 'x':xPos + offsetx,
1049
- 'y':(this.grapharea / 2) + this.gutterTop + offsety,
1050
- 'text':prop['chart.ylabels.specific'][prop['chart.ylabels.specific'].length - 1],
1051
- 'valign':'center',
1052
- 'halign':align,
1053
- 'bounding':boxed,
1054
- 'tag': 'labels.specific'
1055
- });
1056
- }
1057
- }
1058
-
1059
-
1060
- if (!prop['chart.ylabels.specific'] && typeof numYLabels == 'number') {
1061
-
1062
- /**
1063
- * Draw the top half
1064
- */
1065
- for (var i=0,len=this.scale2.labels.length; i<len; i+=1) {
1066
-
1067
- //var value = ((this.max - this.min)/ numYLabels) * (i+1);
1068
- //value = (invert ? this.max - value : value);
1069
- //if (!invert) value += this.min;
1070
- //value = value.toFixed(prop['chart.scale.decimals']);
1071
-
1072
- if (!invert) {
1073
- RG.Text2(this, {
1074
- 'font':font,
1075
- 'size': text_size,
1076
- 'x': xPos + offsetx,
1077
- 'y': this.gutterTop + this.halfGraphHeight - (((i + 1)/numYLabels) * this.halfGraphHeight) + offsety,
1078
- 'valign': 'center',
1079
- 'halign':align,
1080
- 'bounding': boxed,
1081
- 'boundingFill': 'white',
1082
- 'text': this.scale2.labels[i],
1083
- 'tag': 'scale'
1084
- });
1085
- } else {
1086
- RG.Text2(this, {
1087
- 'font':font,
1088
- 'size': text_size,
1089
- 'x': xPos + offsetx,
1090
- 'y': this.gutterTop + this.halfGraphHeight - ((i/numYLabels) * this.halfGraphHeight) + offsety,
1091
- 'valign': 'center',
1092
- 'halign':align,
1093
- 'bounding': boxed,
1094
- 'boundingFill': 'white',
1095
- 'text': this.scale2.labels[this.scale2.labels.length - (i + 1)],
1096
- 'tag': 'scale'
1097
- });
1098
- }
1099
- }
1100
-
1101
- /**
1102
- * Draw the bottom half
1103
- */
1104
- for (var i=0,len=this.scale2.labels.length; i<len; i+=1) {
1105
-
1106
- //var value = (((this.max - this.min)/ numYLabels) * i) + this.min;
1107
- // value = (invert ? value : this.max - (value - this.min)).toFixed(prop['chart.scale.decimals']);
1108
-
1109
- if (!invert) {
1110
- RG.Text2(this, {
1111
- 'font':font,
1112
- 'size': text_size,
1113
- 'x': xPos + offsetx,
1114
- 'y': this.gutterTop + this.halfGraphHeight + this.halfGraphHeight - ((i/numYLabels) * this.halfGraphHeight) + offsety,
1115
- 'valign': 'center',
1116
- 'halign':align,
1117
- 'bounding': boxed,
1118
- 'boundingFill': 'white',
1119
- 'text': '-' + this.scale2.labels[len - (i+1)],
1120
- 'tag': 'scale'
1121
- });
1122
- } else {
1123
-
1124
- // This ensures that the center label isn't drawn twice
1125
- if (i == (len - 1)&& invert) {
1126
- continue;
1127
- }
1128
-
1129
- RG.Text2(this, {
1130
- 'font':font,
1131
- 'size': text_size,
1132
- 'x': xPos + offsetx,
1133
- 'y': this.gutterTop + this.halfGraphHeight + this.halfGraphHeight - (((i + 1)/numYLabels) * this.halfGraphHeight) + offsety,
1134
- 'valign': 'center',
1135
- 'halign':align,
1136
- 'bounding': boxed,
1137
- 'boundingFill': 'white',
1138
- 'text': '-' + this.scale2.labels[i],
1139
- 'tag': 'scale'
1140
- });
1141
- }
1142
- }
1143
-
1144
-
1145
-
1146
-
1147
- // If ymin is specified draw that
1148
- if (!invert && (yMin > 0 || prop['chart.scale.zerostart'])) {
1149
- RG.text2(this, {
1150
- 'font':font,
1151
- 'size': text_size,
1152
- 'x': xPos + offsetx,
1153
- 'y': this.gutterTop + this.halfGraphHeight + offsety,
1154
- 'valign': 'center',
1155
- 'halign':align,
1156
- 'bounding': boxed,
1157
- 'boundingFill': 'white',
1158
- 'text': RG.number_format(this, yMin.toFixed(prop['chart.scale.decimals']), units_pre, units_post),
1159
- 'tag': 'scale'
1160
- });
1161
- }
1162
-
1163
- if (invert) {
1164
- RG.text2(this, {
1165
- 'font':font,
1166
- 'size': text_size,
1167
- 'x': xPos + offsetx,
1168
- 'y': this.gutterTop + offsety,
1169
- 'valign': 'center',
1170
- 'halign':align,
1171
- 'bounding': boxed,
1172
- 'boundingFill': 'white',
1173
- 'text': RG.number_format(this, yMin.toFixed(prop['chart.scale.decimals']), units_pre, units_post),
1174
- 'tag': 'scale'
1175
- });
1176
-
1177
- RG.text2(this, {
1178
- 'font':font,
1179
- 'size': text_size,
1180
- 'x': xPos + offsetx,
1181
- 'y': this.gutterTop + (this.halfGraphHeight * 2) + offsety,
1182
- 'valign': 'center',
1183
- 'halign':align,
1184
- 'bounding': boxed,
1185
- 'boundingFill': 'white',
1186
- 'text': '-' + RG.number_format(this, yMin.toFixed(prop['chart.scale.decimals']), units_pre, units_post),
1187
- 'tag': 'scale'
1188
- });
1189
- }
1190
- }
1191
-
1192
- // X axis at the bottom
1193
- } else {
1194
-
1195
- var xPos = prop['chart.yaxispos'] == 'left' ? this.gutterLeft - 5 : ca.width - this.gutterRight + 5;
1196
- var align = prop['chart.yaxispos'] == 'right' ? 'left' : 'right';
1197
-
1198
- if (inside) {
1199
- if (prop['chart.yaxispos'] == 'left') {
1200
- xPos = prop['chart.gutter.left'] + 5;
1201
- align = 'left';
1202
- boxed = true;
1203
- } else {
1204
- xPos = ca.width - obj.gutterRight - 5;
1205
- align = 'right';
1206
- boxed = true;
1207
- }
1208
- }
1209
-
1210
- /**
1211
- * Specific Y labels
1212
- */
1213
- if (typeof prop['chart.ylabels.specific'] == 'object' && prop['chart.ylabels.specific']) {
1214
-
1215
- var labels = prop['chart.ylabels.specific'];
1216
-
1217
- // Lose the last label
1218
- if (prop['chart.ymin'] > 9999) {
1219
- labels = [];
1220
- for (var i=0; i<(prop['chart.ylabels.specific'].length - 1); ++i) {
1221
- labels.push(prop['chart.ylabels.specific'][i]);
1222
- }
1223
- }
1224
-
1225
- for (var i=0,len=labels.length; i<len; i+=1) {
1226
-
1227
- var y = this.gutterTop + (i * (this.grapharea / (len - 1)) );
1228
-
1229
- RG.Text2(this, {
1230
- 'font':font,
1231
- 'size':text_size,
1232
- 'x':xPos + offsetx,
1233
- 'y':y + offsety,
1234
- 'text':labels[i],
1235
- 'halign':align,
1236
- 'valign':'center',
1237
- 'bounding':boxed,
1238
- 'tag': 'scale'
1239
- });
1240
- }
1241
-
1242
- /**
1243
- * X axis at the bottom with a scale
1244
- */
1245
- } else {
1246
-
1247
- if (typeof(numYLabels) == 'number') {
1248
-
1249
- if (invert) {
1250
-
1251
- for (var i=0; i<numYLabels; ++i) {
1252
-
1253
- //var value = ((this.max - this.min)/ numYLabels) * i;
1254
- // value = value.toFixed(prop['chart.scale.decimals']);
1255
- var interval = (ca.height - this.gutterTop - this.gutterBottom) / numYLabels;
1256
-
1257
- RG.Text2(this, {
1258
- 'font':font,
1259
- 'size': text_size,
1260
- 'x': xPos + offsetx,
1261
- 'y': this.gutterTop + ((i+1) * interval) + offsety,
1262
- 'valign': 'center',
1263
- 'halign':align,
1264
- 'bounding': boxed,
1265
- 'boundingFill': 'white',
1266
- 'text': this.scale2.labels[i],
1267
- 'tag': 'scale'
1268
- });
1269
- }
1270
-
1271
-
1272
- // No X axis being shown and there's no ymin. If ymin IS set its added further down
1273
- if (!prop['chart.xaxis'] && !prop['chart.ymin']) {
1274
- RG.Text2(this, {
1275
- 'font':font,
1276
- 'size': text_size,
1277
- 'x': xPos + offsetx,
1278
- 'y': this.gutterTop + offsety,
1279
- 'valign': 'center',
1280
- 'halign':align,
1281
- 'bounding': boxed,
1282
- 'boundingFill': 'white',
1283
- 'text': RG.number_format(this, (this.min).toFixed(prop['chart.scale.decimals']), units_pre, units_post),
1284
- 'tag': 'scale'
1285
- });
1286
- }
1287
-
1288
- } else {
1289
- for (var i=0,len=this.scale2.labels.length; i<len; i+=1) {
1290
-
1291
- //var value = ((this.max - this.min)/ numYLabels) * (i+1);
1292
- // value = (invert ? this.max - value : value);
1293
- // if (!invert) value += this.min;
1294
- // value = value.toFixed(prop['chart.scale.decimals']);
1295
-
1296
- RG.Text2(this, {
1297
- 'font':font,
1298
- 'size': text_size,
1299
- 'x': xPos + offsetx,
1300
- 'y': this.gutterTop + this.grapharea - (((i + 1)/this.scale2.labels.length) * this.grapharea) + offsety,
1301
- 'valign': 'center',
1302
- 'halign':align,
1303
- 'bounding': boxed,
1304
- 'boundingFill': 'white',
1305
- 'text': this.scale2.labels[i],
1306
- 'tag': 'scale'
1307
- });
1308
- }
1309
-
1310
- if (!prop['chart.xaxis'] && prop['chart.ymin'] == 0) {
1311
- RG.Text2(this, {
1312
- 'font':font,
1313
- 'size': text_size,
1314
- 'x': xPos + offsetx,
1315
- 'y': ca.height - this.gutterBottom + offsety,
1316
- 'valign': 'center',
1317
- 'halign':align,
1318
- 'bounding': boxed,
1319
- 'boundingFill': 'white',
1320
- 'text': RG.number_format(this, (0).toFixed(prop['chart.scale.decimals']), units_pre, units_post),
1321
- 'tag': 'scale'
1322
- });
1323
- }
1324
- }
1325
- }
1326
-
1327
- if ( (prop['chart.ymin'] || prop['chart.scale.zerostart']) && !invert) {
1328
- RG.text2(this, {
1329
- 'font':font,
1330
- 'size': text_size,
1331
- 'x': xPos + offsetx,
1332
- 'y': ca.height - this.gutterBottom + offsety,
1333
- 'valign': 'center',
1334
- 'halign':align,
1335
- 'bounding': boxed,
1336
- 'boundingFill': 'white',
1337
- 'text': RG.number_format(this, prop['chart.ymin'].toFixed(prop['chart.scale.decimals']), units_pre, units_post),
1338
- 'tag': 'scale'
1339
- });
1340
- } else if (invert) {
1341
- RG.text2(this, {
1342
- 'font':font,
1343
- 'size': text_size,
1344
- 'x': xPos + offsetx,
1345
- 'y': this.gutterTop + offsety,
1346
- 'valign': 'center',
1347
- 'halign':align,
1348
- 'bounding': boxed,
1349
- 'boundingFill': 'white',
1350
- 'text': RG.number_format(this, prop['chart.ymin'].toFixed(prop['chart.scale.decimals']), units_pre, units_post),
1351
- 'tag': 'scale'
1352
- });
1353
- }
1354
- }
1355
- }
1356
- }
1357
-
1358
-
1359
-
1360
-
1361
- /**
1362
- * Draw an X scale
1363
- */
1364
- if (prop['chart.xscale']) {
1365
-
1366
- var numXLabels = prop['chart.xscale.numlabels'],
1367
- y = ca.height - this.gutterBottom + 5 + (text_size / 2),
1368
- units_pre_x = prop['chart.xscale.units.pre'],
1369
- units_post_x = prop['chart.xscale.units.post'],
1370
- decimals = prop['chart.xscale.decimals'],
1371
- point = prop['chart.xscale.point'],
1372
- thousand = prop['chart.xscale.thousand'],
1373
- color = prop['chart.labels.color'],
1374
- bold = prop['chart.labels.bold'],
1375
- offsetx = prop['chart.labels.offsetx'],
1376
- offsety = prop['chart.labels.offsety']
1377
-
1378
-
1379
- if (!prop['chart.xmax']) {
1380
-
1381
- var xmax = 0;
1382
- var xmin = prop['chart.xmin'];
1383
-
1384
- for (var ds=0,len=this.data.length; ds<len; ds+=1) {
1385
- for (var point=0,len2=this.data[ds].length; point<len2; point+=1) {
1386
- xmax = Math.max(xmax, this.data[ds][point][0]);
1387
- }
1388
- }
1389
- } else {
1390
- xmax = prop['chart.xmax'];
1391
- xmin = prop['chart.xmin']
1392
- }
1393
-
1394
- this.xscale2 = RG.getScale2(this, {
1395
- 'max':xmax,
1396
- 'min': xmin,
1397
- 'scale.decimals': decimals,
1398
- 'scale.point': point,
1399
- 'scale.thousand': thousand,
1400
- 'units.pre': units_pre_x,
1401
- 'units.post': units_post_x,
1402
- 'ylabels.count': numXLabels,
1403
- 'strict': true
1404
- });
1405
-
1406
- this.Set('chart.xmax', this.xscale2.max);
1407
- var interval = (ca.width - this.gutterLeft - this.gutterRight) / this.xscale2.labels.length;
1408
-
1409
- for (var i=0,len=this.xscale2.labels.length; i<len; i+=1) {
1410
-
1411
- var num = ( (prop['chart.xmax'] - prop['chart.xmin']) * ((i+1) / numXLabels)) + (xmin || 0),
1412
- x = this.gutterLeft + ((i+1) * interval),
1413
-
1414
- // Repeated a few lines down
1415
- text = typeof prop['chart.xscale.formatter'] === 'function' ? String(prop['chart.xscale.formatter'](this, num)) : this.xscale2.labels[i];
1416
-
1417
- RG.text2(this, {
1418
- 'color': color,
1419
- 'font':font,
1420
- 'size': text_size,
1421
- 'bold': bold,
1422
- 'x': x + offsetx,
1423
- 'y': y + offsety,
1424
- 'valign': 'center',
1425
- 'halign':'center',
1426
- 'text':text,
1427
- 'tag': 'xscale'
1428
- });
1429
- }
1430
-
1431
- // If the Y axis is on the right hand side - draw the left most X label
1432
- // ** Always added now **
1433
-
1434
- // Repeated a few lines up
1435
- var text = typeof prop['chart.xscale.formatter'] === 'function' ? String(prop['chart.xscale.formatter'](this, prop['chart.xmin'])) : String(prop['chart.xmin']);
1436
-
1437
- RG.text2(this, {
1438
- 'color': color,
1439
- 'font':font,
1440
- 'size': text_size,
1441
- 'bold':bold,
1442
- 'x': this.gutterLeft + offsetx,
1443
- 'y': y + offsety,
1444
- 'valign': 'center',
1445
- 'halign':'center',
1446
- 'text': text,
1447
- 'tag': 'xscale'
1448
- });
1449
-
1450
- /**
1451
- * Draw X labels
1452
- */
1453
- } else {
1454
-
1455
- // Put the text on the X axis
1456
- var graphArea = ca.width - this.gutterLeft - this.gutterRight;
1457
- var xInterval = graphArea / prop['chart.labels'].length;
1458
- var xPos = this.gutterLeft;
1459
- var yPos = (ca.height - this.gutterBottom) + 3;
1460
- var labels = prop['chart.labels'];
1461
- var color = prop['chart.labels.color'];
1462
- var bold = prop['chart.labels.bold'];
1463
- var offsetx = prop['chart.labels.offsetx'];
1464
- var offsety = prop['chart.labels.offsety'];
1465
-
1466
- /**
1467
- * Text angle
1468
- */
1469
- var angle = 0;
1470
- var valign = 'top';
1471
- var halign = 'center';
1472
-
1473
- if (prop['chart.text.angle'] > 0) {
1474
- angle = -1 * prop['chart.text.angle'];
1475
- valign = 'center';
1476
- halign = 'right';
1477
- yPos += 10;
1478
- }
1479
-
1480
- for (i=0; i<labels.length; ++i) {
1481
-
1482
- if (typeof(labels[i]) == 'object') {
1483
-
1484
- if (prop['chart.labels.specific.align'] == 'center') {
1485
- var rightEdge = 0;
1486
-
1487
- if (labels[i+1] && labels[i+1][1]) {
1488
- rightEdge = labels[i+1][1];
1489
- } else {
1490
- rightEdge = prop['chart.xmax'];
1491
- }
1492
-
1493
- var offset = (this.getXCoord(rightEdge) - this.getXCoord(labels[i][1])) / 2;
1494
-
1495
- } else {
1496
- var offset = 5;
1497
- }
1498
-
1499
-
1500
- RG.text2(this, {
1501
- 'color': color,
1502
- 'font':font,
1503
- 'size': prop['chart.text.size'],
1504
- 'bold': bold,
1505
- 'x': this.getXCoord(labels[i][1]) + offset + offsetx,
1506
- 'y': yPos + offsety,
1507
- 'valign': valign,
1508
- 'halign':angle != 0 ? 'right' : (prop['chart.labels.specific.align'] == 'center' ? 'center' : 'left'),
1509
- 'text':String(labels[i][0]),
1510
- 'angle':angle,
1511
- 'marker':false,
1512
- 'tag': 'labels.specific'
1513
- });
1514
-
1515
- /**
1516
- * Draw the gray indicator line
1517
- */
1518
- co.beginPath();
1519
- co.strokeStyle = '#bbb';
1520
- co.moveTo(ma.round(this.gutterLeft + (graphArea * ((labels[i][1] - xMin)/ (prop['chart.xmax'] - xMin)))), ca.height - this.gutterBottom);
1521
- co.lineTo(ma.round(this.gutterLeft + (graphArea * ((labels[i][1] - xMin)/ (prop['chart.xmax'] - xMin)))), ca.height - this.gutterBottom + 20);
1522
- co.stroke();
1523
-
1524
- } else {
1525
-
1526
- RG.text2(this, {
1527
- 'color': color,
1528
- 'font':font,
1529
- 'size': prop['chart.text.size'],
1530
- 'bold': bold,
1531
- 'x': xPos + (xInterval / 2) + offsetx,
1532
- 'y': yPos + offsety,
1533
- 'valign': valign,
1534
- 'halign':halign,
1535
- 'text':String(labels[i]),
1536
- 'angle':angle,
1537
- 'tag': 'labels'
1538
- });
1539
- }
1540
-
1541
- // Do this for the next time around
1542
- xPos += xInterval;
1543
- }
1544
-
1545
- /**
1546
- * Draw the final indicator line
1547
- */
1548
- if (typeof(labels[0]) == 'object') {
1549
- co.beginPath();
1550
- co.strokeStyle = '#bbb';
1551
- co.moveTo(this.gutterLeft + graphArea, ca.height - this.gutterBottom);
1552
- co.lineTo(this.gutterLeft + graphArea, ca.height - this.gutterBottom + 20);
1553
- co.stroke();
1554
- }
1555
- }
1556
- };
1557
-
1558
-
1559
-
1560
-
1561
-
1562
-
1563
-
1564
-
1565
-
1566
-
1567
-
1568
-
1569
-
1570
-
1571
- /**
1572
- * Draws the actual scatter graph marks
1573
- *
1574
- * @param i integer The dataset index
1575
- */
1576
- this.drawMarks =
1577
- this.DrawMarks = function (i)
1578
- {
1579
- /**
1580
- * Reset the coords array
1581
- */
1582
- this.coords[i] = [];
1583
-
1584
- /**
1585
- * Plot the values
1586
- */
1587
- var xmax = prop['chart.xmax'];
1588
- var default_color = prop['chart.defaultcolor'];
1589
-
1590
- for (var j=0,len=this.data[i].length; j<len; j+=1) {
1591
- /**
1592
- * This is here because tooltips are optional
1593
- */
1594
- var data_points = this.data[i];
1595
-
1596
- // Allow for null points
1597
- if (RG.isNull(data_points[j])) {
1598
- continue;
1599
- }
1600
-
1601
- var xCoord = data_points[j][0];
1602
- var yCoord = data_points[j][1];
1603
- var color = data_points[j][2] ? data_points[j][2] : default_color;
1604
- var tooltip = (data_points[j] && data_points[j][3]) ? data_points[j][3] : null;
1605
-
1606
-
1607
- this.DrawMark(
1608
- i,
1609
- xCoord,
1610
- yCoord,
1611
- xmax,
1612
- this.scale2.max,
1613
- color,
1614
- tooltip,
1615
- this.coords[i],
1616
- data_points,
1617
- j
1618
- );
1619
- }
1620
- };
1621
-
1622
-
1623
-
1624
-
1625
- /**
1626
- * Draws a single scatter mark
1627
- */
1628
- this.drawMark =
1629
- this.DrawMark = function (data_set_index, x, y, xMax, yMax, color, tooltip, coords, data, data_index)
1630
- {
1631
- var tickmarks = prop['chart.tickmarks'];
1632
- var tickSize = prop['chart.ticksize'];
1633
- var xMin = prop['chart.xmin'];
1634
- var x = ((x - xMin) / (xMax - xMin)) * (ca.width - this.gutterLeft - this.gutterRight);
1635
- var originalX = x;
1636
- var originalY = y;
1637
-
1638
- /**
1639
- * This allows chart.tickmarks to be an array
1640
- */
1641
- if (tickmarks && typeof(tickmarks) == 'object') {
1642
- tickmarks = tickmarks[data_set_index];
1643
- }
1644
-
1645
-
1646
- /**
1647
- * This allows chart.ticksize to be an array
1648
- */
1649
- if (typeof(tickSize) == 'object') {
1650
- var tickSize = tickSize[data_set_index];
1651
- var halfTickSize = tickSize / 2;
1652
- } else {
1653
- var halfTickSize = tickSize / 2;
1654
- }
1655
-
1656
-
1657
- /**
1658
- * This bit is for boxplots only
1659
- */
1660
- if ( y
1661
- && typeof(y) == 'object'
1662
- && typeof(y[0]) == 'number'
1663
- && typeof(y[1]) == 'number'
1664
- && typeof(y[2]) == 'number'
1665
- && typeof(y[3]) == 'number'
1666
- && typeof(y[4]) == 'number'
1667
- ) {
1668
-
1669
- //var yMin = prop['chart.ymin'] ? prop['chart.ymin'] : 0;
1670
- this.Set('chart.boxplot', true);
1671
- //this.graphheight = ca.height - this.gutterTop - this.gutterBottom;
1672
-
1673
- //if (prop['chart.xaxispos'] == 'center') {
1674
- // this.graphheight /= 2;
1675
- //}
1676
-
1677
-
1678
- var y0 = this.getYCoord(y[0]);//(this.graphheight) - ((y[4] - yMin) / (yMax - yMin)) * (this.graphheight);
1679
- var y1 = this.getYCoord(y[1]);//(this.graphheight) - ((y[3] - yMin) / (yMax - yMin)) * (this.graphheight);
1680
- var y2 = this.getYCoord(y[2]);//(this.graphheight) - ((y[2] - yMin) / (yMax - yMin)) * (this.graphheight);
1681
- var y3 = this.getYCoord(y[3]);//(this.graphheight) - ((y[1] - yMin) / (yMax - yMin)) * (this.graphheight);
1682
- var y4 = this.getYCoord(y[4]);//(this.graphheight) - ((y[0] - yMin) / (yMax - yMin)) * (this.graphheight);
1683
-
1684
-
1685
- var col1 = y[5];
1686
- var col2 = y[6];
1687
-
1688
- var boxWidth = typeof(y[7]) == 'number' ? y[7] : prop['chart.boxplot.width'];
1689
-
1690
- //var y = this.graphheight - y2;
1691
-
1692
- } else {
1693
-
1694
- /**
1695
- * The new way of getting the Y coord. This function (should) handle everything
1696
- */
1697
- var yCoord = this.getYCoord(y);
1698
- }
1699
-
1700
- //if (prop['chart.xaxispos'] == 'center'] {
1701
- // y /= 2;
1702
- // y += this.halfGraphHeight;
1703
- //
1704
- // if (prop['chart.ylabels.invert']) {
1705
- // p(y)
1706
- // }
1707
- //}
1708
-
1709
- /**
1710
- * Account for the X axis being at the centre
1711
- */
1712
- // This is so that points are on the graph, and not the gutter - which helps
1713
- x += this.gutterLeft;
1714
- //y = ca.height - this.gutterBottom - y;
1715
-
1716
-
1717
-
1718
-
1719
- co.beginPath();
1720
-
1721
- // Color
1722
- co.strokeStyle = color;
1723
-
1724
-
1725
-
1726
- /**
1727
- * Boxplots
1728
- */
1729
- if (prop['chart.boxplot']) {
1730
-
1731
- // boxWidth is a scale value, so convert it to a pixel vlue
1732
- boxWidth = (boxWidth / prop['chart.xmax']) * (ca.width -this.gutterLeft - this.gutterRight);
1733
-
1734
- var halfBoxWidth = boxWidth / 2;
1735
-
1736
- if (prop['chart.line.visible']) {
1737
- co.beginPath();
1738
-
1739
- //TODO Make this color configurable
1740
- co.strokeRect(x - halfBoxWidth, y1, boxWidth, y3 - y1);
1741
-
1742
- // Draw the upper coloured box if a value is specified
1743
- if (col1) {
1744
- co.fillStyle = col1;
1745
- co.fillRect(x - halfBoxWidth, y1, boxWidth, y2 - y1);
1746
- }
1747
-
1748
- // Draw the lower coloured box if a value is specified
1749
- if (col2) {
1750
- co.fillStyle = col2;
1751
- co.fillRect(x - halfBoxWidth, y2, boxWidth, y3 - y2);
1752
- }
1753
- co.stroke();
1754
-
1755
- // Now draw the whiskers
1756
- co.beginPath();
1757
- if (prop['chart.boxplot.capped']) {
1758
- co.moveTo(x - halfBoxWidth, Math.round(y0));
1759
- co.lineTo(x + halfBoxWidth, Math.round(y0));
1760
- }
1761
-
1762
- co.moveTo(Math.round(x), y0);
1763
- co.lineTo(Math.round(x ), y1);
1764
-
1765
- if (prop['chart.boxplot.capped']) {
1766
- co.moveTo(x - halfBoxWidth, Math.round(y4));
1767
- co.lineTo(x + halfBoxWidth, Math.round(y4));
1768
- }
1769
-
1770
- co.moveTo(Math.round(x), y4);
1771
- co.lineTo(Math.round(x), y3);
1772
-
1773
- co.stroke();
1774
- }
1775
- }
1776
-
1777
-
1778
- /**
1779
- * Draw the tickmark, but not for boxplots
1780
- */
1781
- if (prop['chart.line.visible'] && typeof(y) == 'number' && !y0 && !y1 && !y2 && !y3 && !y4) {
1782
-
1783
- if (tickmarks == 'circle') {
1784
- co.arc(x, yCoord, halfTickSize, 0, 6.28, 0);
1785
- co.fillStyle = color;
1786
- co.fill();
1787
-
1788
- } else if (tickmarks == 'plus') {
1789
-
1790
- co.moveTo(x, yCoord - halfTickSize);
1791
- co.lineTo(x, yCoord + halfTickSize);
1792
- co.moveTo(x - halfTickSize, yCoord);
1793
- co.lineTo(x + halfTickSize, yCoord);
1794
- co.stroke();
1795
-
1796
- } else if (tickmarks == 'square') {
1797
- co.strokeStyle = color;
1798
- co.fillStyle = color;
1799
- co.fillRect(
1800
- x - halfTickSize,
1801
- yCoord - halfTickSize,
1802
- tickSize,
1803
- tickSize
1804
- );
1805
- //co.fill();
1806
-
1807
- } else if (tickmarks == 'cross') {
1808
-
1809
- co.moveTo(x - halfTickSize, yCoord - halfTickSize);
1810
- co.lineTo(x + halfTickSize, yCoord + halfTickSize);
1811
- co.moveTo(x + halfTickSize, yCoord - halfTickSize);
1812
- co.lineTo(x - halfTickSize, yCoord + halfTickSize);
1813
-
1814
- co.stroke();
1815
-
1816
- /**
1817
- * Diamond shape tickmarks
1818
- */
1819
- } else if (tickmarks == 'diamond') {
1820
- co.fillStyle = co.strokeStyle;
1821
-
1822
- co.moveTo(x, yCoord - halfTickSize);
1823
- co.lineTo(x + halfTickSize, yCoord);
1824
- co.lineTo(x, yCoord + halfTickSize);
1825
- co.lineTo(x - halfTickSize, yCoord);
1826
- co.lineTo(x, yCoord - halfTickSize);
1827
-
1828
- co.fill();
1829
- co.stroke();
1830
-
1831
- /**
1832
- * Custom tickmark style
1833
- */
1834
- } else if (typeof(tickmarks) == 'function') {
1835
-
1836
- var graphWidth = ca.width - this.gutterLeft - this.gutterRight
1837
- var graphheight = ca.height - this.gutterTop - this.gutterBottom;
1838
- var xVal = ((x - this.gutterLeft) / graphWidth) * xMax;
1839
- var yVal = ((graphheight - (yCoord - this.gutterTop)) / graphheight) * yMax;
1840
-
1841
- tickmarks(this, data, x, yCoord, xVal, yVal, xMax, yMax, color, data_set_index, data_index)
1842
-
1843
-
1844
-
1845
-
1846
-
1847
-
1848
-
1849
-
1850
-
1851
-
1852
-
1853
-
1854
-
1855
-
1856
-
1857
-
1858
-
1859
- /**
1860
- * Image based tickmark
1861
- */
1862
- // lineData, xPos, yPos, color, isShadow, prevX, prevY, tickmarks, index
1863
- } else if (
1864
- typeof tickmarks === 'string' &&
1865
- (
1866
- tickmarks.substr(0, 6) === 'image:' ||
1867
- tickmarks.substr(0, 5) === 'data:' ||
1868
- tickmarks.substr(0, 1) === '/' ||
1869
- tickmarks.substr(0, 3) === '../' ||
1870
- tickmarks.substr(0, 7) === 'images/'
1871
- )
1872
- ) {
1873
-
1874
- var img = new Image();
1875
-
1876
- if (tickmarks.substr(0, 6) === 'image:') {
1877
- img.src = tickmarks.substr(6);
1878
- } else {
1879
- img.src = tickmarks;
1880
- }
1881
-
1882
-
1883
- img.onload = function ()
1884
- {
1885
- if (prop['chart.tickmarks.image.halign'] === 'center') x -= (this.width / 2);
1886
- if (prop['chart.tickmarks.image.halign'] === 'right') x -= this.width;
1887
-
1888
- if (prop['chart.tickmarks.image.valign'] === 'center') yCoord -= (this.height / 2);
1889
- if (prop['chart.tickmarks.image.valign'] === 'bottom') yCoord -= this.height;
1890
-
1891
- x += prop['chart.tickmarks.image.offsetx'];
1892
- yCoord += prop['chart.tickmarks.image.offsety'];
1893
-
1894
- co.drawImage(this, x, yCoord);
1895
- }
1896
-
1897
-
1898
-
1899
-
1900
-
1901
- /**
1902
- * No tickmarks
1903
- */
1904
- } else if (tickmarks === null) {
1905
-
1906
- /**
1907
- * Unknown tickmark type
1908
- */
1909
- } else {
1910
- alert('[SCATTER] (' + this.id + ') Unknown tickmark style: ' + tickmarks );
1911
- }
1912
- }
1913
-
1914
- /**
1915
- * Add the tickmark to the coords array
1916
- */
1917
- if ( prop['chart.boxplot']
1918
- && typeof y0 === 'number'
1919
- && typeof y1 === 'number'
1920
- && typeof y2 === 'number'
1921
- && typeof y3 === 'number'
1922
- && typeof y4 === 'number') {
1923
-
1924
- x = [x - halfBoxWidth, x + halfBoxWidth];
1925
- yCoord = [y0, y1, y2, y3, y4];
1926
- }
1927
-
1928
- coords.push([x, yCoord, tooltip]);
1929
- };
1930
-
1931
-
1932
-
1933
-
1934
- /**
1935
- * Draws an optional line connecting the tick marks.
1936
- *
1937
- * @param i The index of the dataset to use
1938
- */
1939
- this.drawLine =
1940
- this.DrawLine = function (i)
1941
- {
1942
- if (typeof(prop['chart.line.visible']) == 'boolean' && prop['chart.line.visible'] == false) {
1943
- return;
1944
- }
1945
-
1946
- if (prop['chart.line'] && this.coords[i].length >= 2) {
1947
-
1948
- if (prop['chart.line.dash'] && typeof co.setLineDash === 'function') {
1949
- co.setLineDash(prop['chart.line.dash']);
1950
- }
1951
-
1952
- co.lineCap = 'round';
1953
- co.lineJoin = 'round';
1954
- co.lineWidth = this.getLineWidth(i);// i is the index of the set of coordinates
1955
- co.strokeStyle = prop['chart.line.colors'][i];
1956
-
1957
- co.beginPath();
1958
-
1959
- var prevY = null;
1960
- var currY = null;
1961
-
1962
- for (var j=0,len=this.coords[i].length; j<len; j+=1) {
1963
-
1964
-
1965
- var xPos = this.coords[i][j][0];
1966
- var yPos = this.coords[i][j][1];
1967
-
1968
- if (j > 0) prevY = this.coords[i][j - 1][1];
1969
- currY = yPos;
1970
-
1971
- if (j == 0 || RG.is_null(prevY) || RG.is_null(currY)) {
1972
- co.moveTo(xPos, yPos);
1973
- } else {
1974
-
1975
- // Stepped?
1976
- var stepped = prop['chart.line.stepped'];
1977
-
1978
- if ( (typeof stepped == 'boolean' && stepped)
1979
- || (typeof stepped == 'object' && stepped[i])
1980
- ) {
1981
- co.lineTo(this.coords[i][j][0], this.coords[i][j - 1][1]);
1982
- }
1983
-
1984
- co.lineTo(xPos, yPos);
1985
- }
1986
- }
1987
- co.stroke();
1988
-
1989
- /**
1990
- * Set the linedash back to the default
1991
- */
1992
- if (prop['chart.line.dash'] && typeof co.setLineDash === 'function') {
1993
- co.setLineDash([1,0]);
1994
- }
1995
- }
1996
-
1997
- /**
1998
- * Set the linewidth back to 1
1999
- */
2000
- co.lineWidth = 1;
2001
- };
2002
-
2003
-
2004
-
2005
-
2006
- /**
2007
- * Returns the linewidth
2008
- *
2009
- * @param number i The index of the "line" (/set of coordinates)
2010
- */
2011
- this.getLineWidth =
2012
- this.GetLineWidth = function (i)
2013
- {
2014
- var linewidth = prop['chart.line.linewidth'];
2015
-
2016
- if (typeof linewidth == 'number') {
2017
- return linewidth;
2018
-
2019
- } else if (typeof linewidth == 'object') {
2020
- if (linewidth[i]) {
2021
- return linewidth[i];
2022
- } else {
2023
- return linewidth[0];
2024
- }
2025
-
2026
- alert('[SCATTER] Error! chart.linewidth should be a single number or an array of one or more numbers');
2027
- }
2028
- };
2029
-
2030
-
2031
-
2032
-
2033
- /**
2034
- * Draws vertical bars. Line chart doesn't use a horizontal scale, hence this function
2035
- * is not common
2036
- */
2037
- this.drawVBars =
2038
- this.DrawVBars = function ()
2039
- {
2040
-
2041
- var vbars = prop['chart.background.vbars'];
2042
- var graphWidth = ca.width - this.gutterLeft - this.gutterRight;
2043
-
2044
- if (vbars) {
2045
-
2046
- var xmax = prop['chart.xmax'];
2047
- var xmin = prop['chart.xmin'];
2048
-
2049
- for (var i=0,len=vbars.length; i<len; i+=1) {
2050
-
2051
- var key = i;
2052
- var value = vbars[key];
2053
-
2054
- /**
2055
- * Accomodate date/time values
2056
- */
2057
- if (typeof value[0] == 'string') value[0] = RG.parseDate(value[0]);
2058
- if (typeof value[1] == 'string') value[1] = RG.parseDate(value[1]) - value[0];
2059
-
2060
- var x = (( (value[0] - xmin) / (xmax - xmin) ) * graphWidth) + this.gutterLeft;
2061
- var width = (value[1] / (xmax - xmin) ) * graphWidth;
2062
-
2063
- co.fillStyle = value[2];
2064
- co.fillRect(x, this.gutterTop, width, (ca.height - this.gutterTop - this.gutterBottom));
2065
- }
2066
- }
2067
- };
2068
-
2069
-
2070
-
2071
-
2072
- /**
2073
- * Draws in-graph labels.
2074
- *
2075
- * @param object obj The graph object
2076
- */
2077
- this.drawInGraphLabels =
2078
- this.DrawInGraphLabels = function (obj)
2079
- {
2080
- var labels = obj.Get('chart.labels.ingraph');
2081
- var labels_processed = [];
2082
-
2083
- if (!labels) {
2084
- return;
2085
- }
2086
-
2087
- // Defaults
2088
- var fgcolor = 'black';
2089
- var bgcolor = 'white';
2090
- var direction = 1;
2091
-
2092
- /**
2093
- * Preprocess the labels array. Numbers are expanded
2094
- */
2095
- for (var i=0,len=labels.length; i<len; i+=1) {
2096
- if (typeof(labels[i]) == 'number') {
2097
- for (var j=0; j<labels[i]; ++j) {
2098
- labels_processed.push(null);
2099
- }
2100
- } else if (typeof(labels[i]) == 'string' || typeof(labels[i]) == 'object') {
2101
- labels_processed.push(labels[i]);
2102
-
2103
- } else {
2104
- labels_processed.push('');
2105
- }
2106
- }
2107
-
2108
- /**
2109
- * Turn off any shadow
2110
- */
2111
- RG.NoShadow(obj);
2112
-
2113
- if (labels_processed && labels_processed.length > 0) {
2114
-
2115
- var i=0;
2116
-
2117
- for (var set=0; set<obj.coords.length; ++set) {
2118
- for (var point = 0; point<obj.coords[set].length; ++point) {
2119
- if (labels_processed[i]) {
2120
- var x = obj.coords[set][point][0];
2121
- var y = obj.coords[set][point][1];
2122
- var length = typeof(labels_processed[i][4]) == 'number' ? labels_processed[i][4] : 25;
2123
-
2124
- var text_x = x;
2125
- var text_y = y - 5 - length;
2126
-
2127
- co.moveTo(x, y - 5);
2128
- co.lineTo(x, y - 5 - length);
2129
-
2130
- co.stroke();
2131
- co.beginPath();
2132
-
2133
- // This draws the arrow
2134
- co.moveTo(x, y - 5);
2135
- co.lineTo(x - 3, y - 10);
2136
- co.lineTo(x + 3, y - 10);
2137
- co.closePath();
2138
-
2139
-
2140
- co.beginPath();
2141
- // Fore ground color
2142
- co.fillStyle = (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][1]) == 'string') ? labels_processed[i][1] : 'black';
2143
- RG.text2(this, {
2144
- 'font':obj.Get('chart.text.font'),
2145
- 'size':obj.Get('chart.text.size'),
2146
- 'x':text_x,
2147
- 'y':text_y,
2148
- 'text':(typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][0]) == 'string') ? labels_processed[i][0] : labels_processed[i],
2149
- 'valign':'bottom',
2150
- 'halign':'center',
2151
- 'bounding':true,
2152
- 'bounding.fill':(typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][2]) == 'string') ? labels_processed[i][2] : 'white',
2153
- 'tag': 'labels.ingraph'
2154
- });
2155
- co.fill();
2156
- }
2157
-
2158
- i++;
2159
- }
2160
- }
2161
- }
2162
- };
2163
-
2164
-
2165
-
2166
-
2167
- /**
2168
- * This function makes it much easier to get the (if any) point that is currently being hovered over.
2169
- *
2170
- * @param object e The event object
2171
- */
2172
- this.getShape =
2173
- this.getPoint = function (e)
2174
- {
2175
- var mouseXY = RG.getMouseXY(e);
2176
- var mouseX = mouseXY[0];
2177
- var mouseY = mouseXY[1];
2178
- var overHotspot = false;
2179
- var offset = prop['chart.tooltips.hotspot']; // This is how far the hotspot extends
2180
-
2181
- for (var set=0,len=this.coords.length; set<len; ++set) {
2182
- for (var i=0,len2=this.coords[set].length; i<len2; ++i) {
2183
-
2184
- var x = this.coords[set][i][0];
2185
- var y = this.coords[set][i][1];
2186
- var tooltip = this.data[set][i][3];
2187
-
2188
- if (typeof(y) == 'number') {
2189
- if (mouseX <= (x + offset) &&
2190
- mouseX >= (x - offset) &&
2191
- mouseY <= (y + offset) &&
2192
- mouseY >= (y - offset)) {
2193
-
2194
- var tooltip = RG.parseTooltipText(this.data[set][i][3], 0);
2195
- var index_adjusted = i;
2196
-
2197
- for (var ds=(set-1); ds >=0; --ds) {
2198
- index_adjusted += this.data[ds].length;
2199
- }
2200
-
2201
- return {
2202
- 0: this, 1: x, 2: y, 3: set, 4: i, 5: this.data[set][i][3],
2203
- 'object': this, 'x': x, 'y': y, 'dataset': set, 'index': i, 'tooltip': tooltip, 'index_adjusted': index_adjusted
2204
- };
2205
- }
2206
- } else if (RG.is_null(y)) {
2207
- // Nothing to see here
2208
-
2209
- } else {
2210
-
2211
- var mark = this.data[set][i];
2212
-
2213
- /**
2214
- * Determine the width
2215
- */
2216
- var width = prop['chart.boxplot.width'];
2217
-
2218
- if (typeof(mark[1][7]) == 'number') {
2219
- width = mark[1][7];
2220
- }
2221
-
2222
- if ( typeof(x) == 'object'
2223
- && mouseX > x[0]
2224
- && mouseX < x[1]
2225
- && mouseY < y[1]
2226
- && mouseY > y[3]
2227
- ) {
2228
-
2229
- var tooltip = RG.parseTooltipText(this.data[set][i][3], 0);
2230
-
2231
- return {
2232
- 0: this, 1: x[0], 2: x[1] - x[0], 3: y[1], 4: y[3] - y[1], 5: set, 6: i, 7: this.data[set][i][3],
2233
- 'object': this, 'x': x[0], 'y': y[1], 'width': x[1] - x[0], 'height': y[3] - y[1], 'dataset': set, 'index': i, 'tooltip': tooltip
2234
- };
2235
- }
2236
- }
2237
- }
2238
- }
2239
- };
2240
-
2241
-
2242
-
2243
-
2244
- /**
2245
- * Draws the above line labels
2246
- */
2247
- this.drawAboveLabels =
2248
- this.DrawAboveLabels = function ()
2249
- {
2250
- var size = prop['chart.labels.above.size'];
2251
- var font = prop['chart.text.font'];
2252
- var units_pre = prop['chart.units.pre'];
2253
- var units_post = prop['chart.units.post'];
2254
-
2255
-
2256
- for (var set=0,len=this.coords.length; set<len; ++set) {
2257
- for (var point=0,len2=this.coords[set].length; point<len2; ++point) {
2258
-
2259
- var x_val = this.data[set][point][0];
2260
- var y_val = this.data[set][point][1];
2261
-
2262
- if (!RG.is_null(y_val)) {
2263
-
2264
- // Use the top most value from a box plot
2265
- if (RG.is_array(y_val)) {
2266
- var max = 0;
2267
- for (var i=0; i<y_val; ++i) {
2268
- max = Math.max(max, y_val[i]);
2269
- }
2270
-
2271
- y_val = max;
2272
- }
2273
-
2274
- var x_pos = this.coords[set][point][0];
2275
- var y_pos = this.coords[set][point][1];
2276
-
2277
- RG.Text2(this, {
2278
- 'font':font,
2279
- 'size':size,
2280
- 'x':x_pos,
2281
- 'y':y_pos - 5 - size,
2282
- 'text':x_val.toFixed(prop['chart.labels.above.decimals']) + ', ' + y_val.toFixed(prop['chart.labels.above.decimals']),
2283
- 'valign':'center',
2284
- 'halign':'center',
2285
- 'bounding':true,
2286
- 'boundingFill':'rgba(255, 255, 255, 0.7)',
2287
- 'tag': 'labels.above'
2288
- });
2289
- }
2290
- }
2291
- }
2292
- };
2293
-
2294
-
2295
-
2296
-
2297
- /**
2298
- * When you click on the chart, this method can return the Y value at that point. It works for any point on the
2299
- * chart (that is inside the gutters) - not just points within the Bars.
2300
- *
2301
- * @param object e The event object
2302
- */
2303
- this.getYValue =
2304
- this.getValue = function (arg)
2305
- {
2306
- if (arg.length == 2) {
2307
- var mouseX = arg[0];
2308
- var mouseY = arg[1];
2309
- } else {
2310
- var mouseCoords = RG.getMouseXY(arg);
2311
- var mouseX = mouseCoords[0];
2312
- var mouseY = mouseCoords[1];
2313
- }
2314
-
2315
- var obj = this;
2316
-
2317
- if ( mouseY < this.gutterTop
2318
- || mouseY > (ca.height - this.gutterBottom)
2319
- || mouseX < this.gutterLeft
2320
- || mouseX > (ca.width - this.gutterRight)
2321
- ) {
2322
- return null;
2323
- }
2324
-
2325
- if (prop['chart.xaxispos'] == 'center') {
2326
- var value = (((this.grapharea / 2) - (mouseY - this.gutterTop)) / this.grapharea) * (this.max - this.min)
2327
- value *= 2;
2328
-
2329
-
2330
- // Account for each side of the X axis
2331
- if (value >= 0) {
2332
- value += this.min
2333
-
2334
- if (prop['chart.ylabels.invert']) {
2335
- value -= this.min;
2336
- value = this.max - value;
2337
- }
2338
-
2339
- } else {
2340
-
2341
- value -= this.min;
2342
- if (prop['chart.ylabels.invert']) {
2343
- value += this.min;
2344
- value = this.max + value;
2345
- value *= -1;
2346
- }
2347
- }
2348
-
2349
- } else {
2350
-
2351
- var value = ((this.grapharea - (mouseY - this.gutterTop)) / this.grapharea) * (this.max - this.min)
2352
- value += this.min;
2353
-
2354
- if (prop['chart.ylabels.invert']) {
2355
- value -= this.min;
2356
- value = this.max - value;
2357
- }
2358
- }
2359
-
2360
- return value;
2361
- };
2362
-
2363
-
2364
-
2365
-
2366
- /**
2367
- * When you click on the chart, this method can return the X value at that point.
2368
- *
2369
- * @param mixed arg This can either be an event object or the X coordinate
2370
- * @param number If specifying the X coord as the first arg then this should be the Y coord
2371
- */
2372
- this.getXValue = function (arg)
2373
- {
2374
- if (arg.length == 2) {
2375
- var mouseX = arg[0];
2376
- var mouseY = arg[1];
2377
- } else {
2378
- var mouseXY = RG.getMouseXY(arg);
2379
- var mouseX = mouseXY[0];
2380
- var mouseY = mouseXY[1];
2381
- }
2382
- var obj = this;
2383
-
2384
- if ( mouseY < this.gutterTop
2385
- || mouseY > (ca.height - this.gutterBottom)
2386
- || mouseX < this.gutterLeft
2387
- || mouseX > (ca.width - this.gutterRight)
2388
- ) {
2389
- return null;
2390
- }
2391
-
2392
- var width = (ca.width - this.gutterLeft - this.gutterRight);
2393
- var value = ((mouseX - this.gutterLeft) / width) * (prop['chart.xmax'] - prop['chart.xmin'])
2394
- value += prop['chart.xmin'];
2395
-
2396
- return value;
2397
- };
2398
-
2399
-
2400
-
2401
-
2402
- /**
2403
- * Each object type has its own Highlight() function which highlights the appropriate shape
2404
- *
2405
- * @param object shape The shape to highlight
2406
- */
2407
- this.highlight =
2408
- this.Highlight = function (shape)
2409
- {
2410
- if (typeof prop['chart.highlight.style'] === 'function') {
2411
- (prop['chart.highlight.style'])(shape);
2412
- } else {
2413
- // Boxplot highlight
2414
- if (shape['height']) {
2415
- RG.Highlight.Rect(this, shape);
2416
-
2417
- // Point highlight
2418
- } else {
2419
- RG.Highlight.Point(this, shape);
2420
- }
2421
- }
2422
- };
2423
-
2424
-
2425
-
2426
-
2427
- /**
2428
- * The getObjectByXY() worker method. Don't call this call:
2429
- *
2430
- * RG.ObjectRegistry.getObjectByXY(e)
2431
- *
2432
- * @param object e The event object
2433
- */
2434
- this.getObjectByXY = function (e)
2435
- {
2436
- var mouseXY = RG.getMouseXY(e);
2437
-
2438
- if (
2439
- mouseXY[0] > (this.gutterLeft - 3)
2440
- && mouseXY[0] < (ca.width - this.gutterRight + 3)
2441
- && mouseXY[1] > (this.gutterTop - 3)
2442
- && mouseXY[1] < ((ca.height - this.gutterBottom) + 3)
2443
- ) {
2444
-
2445
- return this;
2446
- }
2447
- };
2448
-
2449
-
2450
-
2451
-
2452
- /**
2453
- * This function can be used when the canvas is clicked on (or similar - depending on the event)
2454
- * to retrieve the relevant X coordinate for a particular value.
2455
- *
2456
- * @param int value The value to get the X coordinate for
2457
- */
2458
- this.getXCoord = function (value)
2459
- {
2460
- if (typeof value != 'number' && typeof value != 'string') {
2461
- return null;
2462
- }
2463
-
2464
- // Allow for date strings to be passed
2465
- if (typeof value === 'string') {
2466
- value = RG.parseDate(value);
2467
- }
2468
-
2469
- var xmin = prop['chart.xmin'];
2470
- var xmax = prop['chart.xmax'];
2471
- var x;
2472
-
2473
- if (value < xmin) return null;
2474
- if (value > xmax) return null;
2475
-
2476
- var gutterRight = this.gutterRight;
2477
- var gutterLeft = this.gutterLeft;
2478
-
2479
- if (prop['chart.yaxispos'] == 'right') {
2480
- x = ((value - xmin) / (xmax - xmin)) * (ca.width - gutterLeft - gutterRight);
2481
- x = (ca.width - gutterRight - x);
2482
- } else {
2483
- x = ((value - xmin) / (xmax - xmin)) * (ca.width - gutterLeft - gutterRight);
2484
- x = x + gutterLeft;
2485
- }
2486
-
2487
- return x;
2488
- };
2489
-
2490
-
2491
-
2492
-
2493
- /**
2494
- * This function positions a tooltip when it is displayed
2495
- *
2496
- * @param obj object The chart object
2497
- * @param int x The X coordinate specified for the tooltip
2498
- * @param int y The Y coordinate specified for the tooltip
2499
- * @param objec tooltip The tooltips DIV element
2500
- */
2501
- this.positionTooltip = function (obj, x, y, tooltip, idx)
2502
- {
2503
- var shape = RG.Registry.Get('chart.tooltip.shape');
2504
- var dataset = shape['dataset'];
2505
- var index = shape['index'];
2506
- var coordX = obj.coords[dataset][index][0]
2507
- var coordY = obj.coords[dataset][index][1]
2508
- var canvasXY = RG.getCanvasXY(obj.canvas);
2509
- var mouseXY = RG.getMouseXY(window.event);
2510
- var gutterLeft = obj.gutterLeft;
2511
- var gutterTop = obj.gutterTop;
2512
- var width = tooltip.offsetWidth;
2513
- var height = tooltip.offsetHeight;
2514
- tooltip.style.left = 0;
2515
- tooltip.style.top = 0;
2516
-
2517
- // Is the coord a boxplot
2518
- //var isBoxplot = typeof(coordY) == 'object' ? true : false;
2519
-
2520
- // Show any overflow (ie the arrow)
2521
- tooltip.style.overflow = '';
2522
-
2523
-
2524
- // Reposition the tooltip if at the edges:
2525
-
2526
- // LEFT edge //////////////////////////////////////////////////////////////////
2527
- if (canvasXY[0] + mouseXY[0] - (width / 2) < 0) {
2528
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
2529
- tooltip.style.top = window.event.pageY - height - 5 + 'px';
2530
-
2531
- // RIGHT edge //////////////////////////////////////////////////////////////////
2532
- } else if ((canvasXY[0] + (coordX[0] || coordX) + (width / 2)) > doc.body.offsetWidth) {
2533
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
2534
- tooltip.style.top = window.event.pageY - height - 5 + 'px';
2535
-
2536
- // Default positioning - CENTERED //////////////////////////////////////////////////////////////////
2537
- } else {
2538
- tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
2539
- tooltip.style.top = window.event.pageY - height - 5 + 'px';
2540
- }
2541
- };
2542
-
2543
-
2544
-
2545
-
2546
- /**
2547
- * Returns the applicable Y COORDINATE when given a Y value
2548
- *
2549
- * @param int value The value to use
2550
- * @return int The appropriate Y coordinate
2551
- */
2552
- this.getYCoord =
2553
- this.getYCoordFromValue = function (value)
2554
- {
2555
- if (typeof(value) != 'number') {
2556
- return null;
2557
- }
2558
-
2559
- var invert = prop['chart.ylabels.invert'];
2560
- var xaxispos = prop['chart.xaxispos'];
2561
- var graphHeight = ca.height - this.gutterTop - this.gutterBottom;
2562
- var halfGraphHeight = graphHeight / 2;
2563
- var ymax = this.max;
2564
- var ymin = prop['chart.ymin'];
2565
- var coord = 0;
2566
-
2567
- if (value > ymax || (prop['chart.xaxispos'] == 'bottom' && value < ymin) || (prop['chart.xaxispos'] == 'center' && ((value > 0 && value < ymin) || (value < 0 && value > (-1 * ymin))))) {
2568
- return null;
2569
- }
2570
-
2571
- /**
2572
- * This calculates scale values if the X axis is in the center
2573
- */
2574
- if (xaxispos == 'center') {
2575
-
2576
- coord = ((Math.abs(value) - ymin) / (ymax - ymin)) * halfGraphHeight;
2577
-
2578
- if (invert) {
2579
- coord = halfGraphHeight - coord;
2580
- }
2581
-
2582
- if (value < 0) {
2583
- coord += this.gutterTop;
2584
- coord += halfGraphHeight;
2585
- } else {
2586
- coord = halfGraphHeight - coord;
2587
- coord += this.gutterTop;
2588
- }
2589
-
2590
- /**
2591
- * And this calculates scale values when the X axis is at the bottom
2592
- */
2593
- } else {
2594
-
2595
- coord = ((value - ymin) / (ymax - ymin)) * graphHeight;
2596
-
2597
- if (invert) {
2598
- coord = graphHeight - coord;
2599
- }
2600
-
2601
- // Invert the coordinate because the Y scale starts at the top
2602
- coord = graphHeight - coord;
2603
-
2604
- // And add on the top gutter
2605
- coord = this.gutterTop + coord;
2606
- }
2607
-
2608
- return coord;
2609
- };
2610
-
2611
-
2612
-
2613
-
2614
-
2615
-
2616
- /**
2617
- * A helper class that helps facilitatesbubble charts
2618
- */
2619
- RG.Scatter.Bubble = function (scatter, min, max, width, data)
2620
- {
2621
- this.scatter = scatter;
2622
- this.min = min;
2623
- this.max = max;
2624
- this.width = width;
2625
- this.data = data;
2626
-
2627
-
2628
-
2629
- /**
2630
- * A setter for the Bubble chart class - it just acts as a "passthru" to the Scatter object
2631
- */
2632
- this.set =
2633
- this.Set = function (name, value)
2634
- {
2635
- this.scatter.Set(name, value);
2636
-
2637
- return this;
2638
- };
2639
-
2640
-
2641
-
2642
- /**
2643
- * A getter for the Bubble chart class - it just acts as a "passthru" to the Scatter object
2644
- */
2645
- this.get =
2646
- this.Get = function (name)
2647
- {
2648
- this.scatter.Get(name);
2649
- };
2650
-
2651
-
2652
-
2653
-
2654
- /**
2655
- * Tha Bubble chart draw function
2656
- */
2657
- this.draw =
2658
- this.Draw = function ()
2659
- {
2660
- var bubble_min = this.min;
2661
- var bubble_max = this.max;
2662
- var bubble_data = this.data;
2663
- var bubble_max_width = this.width;
2664
-
2665
- // This custom ondraw event listener draws the bubbles
2666
- this.scatter.ondraw = function (obj)
2667
- {
2668
- // Loop through all the points (first dataset)
2669
- for (var i=0; i<obj.coords[0].length; ++i) {
2670
-
2671
- bubble_data[i] = Math.max(bubble_data[i], bubble_min);
2672
- bubble_data[i] = Math.min(bubble_data[i], bubble_max);
2673
-
2674
- var r = ((bubble_data[i] - bubble_min) / (bubble_max - bubble_min) ) * bubble_max_width;
2675
-
2676
- co.beginPath();
2677
- co.fillStyle = RG.RadialGradient(obj,
2678
- obj.coords[0][i][0] + (r / 2.5),
2679
- obj.coords[0][i][1] - (r / 2.5),
2680
- 0,
2681
- obj.coords[0][i][0] + (r / 2.5),
2682
- obj.coords[0][i][1] - (r / 2.5),
2683
- r,
2684
- 'white',
2685
- obj.data[0][i][2] ? obj.data[0][i][2] : obj.properties['chart.defaultcolor']
2686
- );
2687
- co.arc(obj.coords[0][i][0], obj.coords[0][i][1], r, 0, RG.TWOPI, false);
2688
- co.fill();
2689
- }
2690
- }
2691
-
2692
- return this.scatter.Draw();
2693
- };
2694
- };
2695
-
2696
-
2697
-
2698
-
2699
-
2700
- /**
2701
- * This allows for easy specification of gradients
2702
- */
2703
- this.parseColors = function ()
2704
- {
2705
- // Save the original colors so that they can be restored when the canvas is reset
2706
- if (this.original_colors.length === 0) {
2707
- this.original_colors['data'] = RG.array_clone(this.data);
2708
- this.original_colors['chart.background.vbars'] = RG.array_clone(prop['chart.background.vbars']);
2709
- this.original_colors['chart.background.hbars'] = RG.array_clone(prop['chart.background.hbars']);
2710
- this.original_colors['chart.line.colors'] = RG.array_clone(prop['chart.line.colors']);
2711
- this.original_colors['chart.defaultcolor'] = RG.array_clone(prop['chart.defaultcolor']);
2712
- this.original_colors['chart.crosshairs.color'] = RG.array_clone(prop['chart.crosshairs.color']);
2713
- this.original_colors['chart.highlight.stroke'] = RG.array_clone(prop['chart.highlight.stroke']);
2714
- this.original_colors['chart.highlight.fill'] = RG.array_clone(prop['chart.highlight.fill']);
2715
- this.original_colors['chart.background.barcolor1'] = RG.array_clone(prop['chart.background.barcolor1']);
2716
- this.original_colors['chart.background.barcolor2'] = RG.array_clone(prop['chart.background.barcolor2']);
2717
- this.original_colors['chart.background.grid.color'] = RG.array_clone(prop['chart.background.grid.color']);
2718
- this.original_colors['chart.background.color'] = RG.array_clone(prop['chart.background.color']);
2719
- this.original_colors['chart.axis.color'] = RG.array_clone(prop['chart.axis.color']);
2720
- }
2721
-
2722
-
2723
-
2724
-
2725
-
2726
- // Colors
2727
- var data = this.data;
2728
- if (data) {
2729
- for (var dataset=0; dataset<data.length; ++dataset) {
2730
- for (var i=0; i<this.data[dataset].length; ++i) {
2731
-
2732
- // Boxplots
2733
- if (this.data[dataset][i] && typeof(this.data[dataset][i][1]) == 'object' && this.data[dataset][i][1]) {
2734
-
2735
- if (typeof(this.data[dataset][i][1][5]) == 'string') this.data[dataset][i][1][5] = this.parseSingleColorForGradient(this.data[dataset][i][1][5]);
2736
- if (typeof(this.data[dataset][i][1][6]) == 'string') this.data[dataset][i][1][6] = this.parseSingleColorForGradient(this.data[dataset][i][1][6]);
2737
- }
2738
-
2739
- if (!RG.isNull(this.data[dataset][i])) {
2740
- this.data[dataset][i][2] = this.parseSingleColorForGradient(this.data[dataset][i][2]);
2741
- }
2742
- }
2743
- }
2744
- }
2745
-
2746
- // Parse HBars
2747
- var hbars = prop['chart.background.hbars'];
2748
- if (hbars) {
2749
- for (i=0; i<hbars.length; ++i) {
2750
- hbars[i][2] = this.parseSingleColorForGradient(hbars[i][2]);
2751
- }
2752
- }
2753
-
2754
- // Parse HBars
2755
- var vbars = prop['chart.background.vbars'];
2756
- if (vbars) {
2757
- for (i=0; i<vbars.length; ++i) {
2758
- vbars[i][2] = this.parseSingleColorForGradient(vbars[i][2]);
2759
- }
2760
- }
2761
-
2762
- // Parse line colors
2763
- var colors = prop['chart.line.colors'];
2764
- if (colors) {
2765
- for (i=0; i<colors.length; ++i) {
2766
- colors[i] = this.parseSingleColorForGradient(colors[i]);
2767
- }
2768
- }
2769
-
2770
- prop['chart.defaultcolor'] = this.parseSingleColorForGradient(prop['chart.defaultcolor']);
2771
- prop['chart.crosshairs.color'] = this.parseSingleColorForGradient(prop['chart.crosshairs.color']);
2772
- prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
2773
- prop['chart.highlight.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.fill']);
2774
- prop['chart.background.barcolor1'] = this.parseSingleColorForGradient(prop['chart.background.barcolor1']);
2775
- prop['chart.background.barcolor2'] = this.parseSingleColorForGradient(prop['chart.background.barcolor2']);
2776
- prop['chart.background.grid.color'] = this.parseSingleColorForGradient(prop['chart.background.grid.color']);
2777
- prop['chart.background.color'] = this.parseSingleColorForGradient(prop['chart.background.color']);
2778
- prop['chart.axis.color'] = this.parseSingleColorForGradient(prop['chart.axis.color']);
2779
- };
2780
-
2781
-
2782
-
2783
-
2784
- /**
2785
- * Use this function to reset the object to the post-constructor state. Eg reset colors if
2786
- * need be etc
2787
- */
2788
- this.reset = function ()
2789
- {
2790
- };
2791
-
2792
-
2793
-
2794
-
2795
- /**
2796
- * This parses a single color value for a gradient
2797
- */
2798
- this.parseSingleColorForGradient = function (color)
2799
- {
2800
- if (!color || typeof(color) != 'string') {
2801
- return color;
2802
- }
2803
-
2804
- if (color.match(/^gradient\((.*)\)$/i)) {
2805
-
2806
- var parts = RegExp.$1.split(':');
2807
-
2808
- // Create the gradient
2809
- var grad = co.createLinearGradient(0,ca.height - prop['chart.gutter.bottom'], 0, prop['chart.gutter.top']);
2810
-
2811
- var diff = 1 / (parts.length - 1);
2812
-
2813
- grad.addColorStop(0, RG.trim(parts[0]));
2814
-
2815
- for (var j=1; j<parts.length; ++j) {
2816
- grad.addColorStop(j * diff, RG.trim(parts[j]));
2817
- }
2818
- }
2819
-
2820
- return grad ? grad : color;
2821
- };
2822
-
2823
-
2824
-
2825
-
2826
- /**
2827
- * This function handles highlighting an entire data-series for the interactive
2828
- * key
2829
- *
2830
- * @param int index The index of the data series to be highlighted
2831
- */
2832
- this.interactiveKeyHighlight = function (index)
2833
- {
2834
- if (this.coords && this.coords[index] && this.coords[index].length) {
2835
- this.coords[index].forEach(function (value, idx, arr)
2836
- {
2837
- co.beginPath();
2838
- co.fillStyle = prop['chart.key.interactive.highlight.chart.fill'];
2839
- co.arc(value[0], value[1], prop['chart.ticksize'] + 3, 0, RG.TWOPI, false);
2840
- co.fill();
2841
- });
2842
- }
2843
- };
2844
-
2845
-
2846
-
2847
-
2848
- /**
2849
- * Using a function to add events makes it easier to facilitate method chaining
2850
- *
2851
- * @param string type The type of even to add
2852
- * @param function func
2853
- */
2854
- this.on = function (type, func)
2855
- {
2856
- if (type.substr(0,2) !== 'on') {
2857
- type = 'on' + type;
2858
- }
2859
-
2860
- this[type] = func;
2861
-
2862
- return this;
2863
- };
2864
-
2865
-
2866
-
2867
-
2868
- /**
2869
- * This function runs once only
2870
- * (put at the end of the file (before any effects))
2871
- */
2872
- this.firstDrawFunc = function ()
2873
- {
2874
- };
2875
-
2876
-
2877
-
2878
-
2879
- /**
2880
- * Trace2
2881
- *
2882
- * This is a new version of the Trace effect which no longer requires jQuery and is more compatible
2883
- * with other effects (eg Expand). This new effect is considerably simpler and less code.
2884
- *
2885
- * @param object Options for the effect. Currently only "frames" is available.
2886
- * @param int A function that is called when the ffect is complete
2887
- */
2888
- this.trace =
2889
- this.trace2 = function ()
2890
- {
2891
- var obj = this,
2892
- callback = arguments[2],
2893
- opt = arguments[0] || {},
2894
- frames = opt.frames || 30,
2895
- frame = 0,
2896
- callback = arguments[1] || function () {}
2897
-
2898
- obj.Set('animationTrace', true);
2899
- obj.Set('animationTraceClip', 0);
2900
-
2901
- function iterator ()
2902
- {
2903
- RG.clear(obj.canvas);
2904
-
2905
- RG.redrawCanvas(obj.canvas);
2906
-
2907
- if (frame++ < frames) {
2908
- obj.set('animationTraceClip', frame / frames);
2909
- RG.Effects.updateCanvas(iterator);
2910
- } else {
2911
- callback(obj);
2912
- }
2913
- }
2914
-
2915
- iterator();
2916
-
2917
- return this;
2918
- };
2919
-
2920
-
2921
-
2922
-
2923
- /**
2924
- * This helps the Gantt reset colors when the reset function is called.
2925
- * It handles going through the data and resetting the colors.
2926
- */
2927
- this.resetColorsToOriginalValues = function ()
2928
- {
2929
- /**
2930
- * Copy the original colors over for single-event-per-line data
2931
- */
2932
- for (var i=0,len=this.original_colors['data'].length; i<len; ++i) {
2933
- for (var j=0,len2=this.original_colors['data'][i].length; j<len2;++j) {
2934
-
2935
- // The color for the point
2936
- this.data[i][j][2] = RG.array_clone(this.original_colors['data'][i][j][2]);
2937
-
2938
- // Handle boxplots
2939
- if (typeof this.data[i][j][1] === 'object') {
2940
- this.data[i][j][1][5] = RG.array_clone(this.original_colors['data'][i][j][1][5]);
2941
- this.data[i][j][1][6] = RG.array_clone(this.original_colors['data'][i][j][1][6]);
2942
- }
2943
- }
2944
- }
2945
- };
2946
-
2947
-
2948
-
2949
-
2950
- RG.att(ca);
2951
-
2952
-
2953
-
2954
-
2955
- /**
2956
- * Register the object
2957
- */
2958
- RG.Register(this);
2959
-
2960
-
2961
-
2962
-
2963
- /**
2964
- * This is the 'end' of the constructor so if the first argument
2965
- * contains configuration data - handle that.
2966
- */
2967
- if (parseConfObjectForOptions) {
2968
- RG.parseObjectStyleConfig(this, conf.options);
2969
- }
2970
- };