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.
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
- };