rgraph-rails 1.0.1

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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +4 -0
  7. data/README.md +73 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/lib/rgraph-rails/version.rb +3 -0
  12. data/lib/rgraph-rails.rb +8 -0
  13. data/license.txt +19 -0
  14. data/rgraph-rails.gemspec +26 -0
  15. data/vendor/assets/images/bg.png +0 -0
  16. data/vendor/assets/images/bullet.png +0 -0
  17. data/vendor/assets/images/facebook-large.png +0 -0
  18. data/vendor/assets/images/google-plus-large.png +0 -0
  19. data/vendor/assets/images/logo.png +0 -0
  20. data/vendor/assets/images/meter-image-sd-needle.png +0 -0
  21. data/vendor/assets/images/meter-image-sd.png +0 -0
  22. data/vendor/assets/images/meter-sketch-needle.png +0 -0
  23. data/vendor/assets/images/meter-sketch.png +0 -0
  24. data/vendor/assets/images/odometer-background.png +0 -0
  25. data/vendor/assets/images/rgraph.jpg +0 -0
  26. data/vendor/assets/images/title.png +0 -0
  27. data/vendor/assets/images/twitter-large.png +0 -0
  28. data/vendor/assets/javascripts/RGraph.bar.js +3246 -0
  29. data/vendor/assets/javascripts/RGraph.bipolar.js +2003 -0
  30. data/vendor/assets/javascripts/RGraph.common.annotate.js +399 -0
  31. data/vendor/assets/javascripts/RGraph.common.context.js +600 -0
  32. data/vendor/assets/javascripts/RGraph.common.core.js +4751 -0
  33. data/vendor/assets/javascripts/RGraph.common.csv.js +275 -0
  34. data/vendor/assets/javascripts/RGraph.common.deprecated.js +454 -0
  35. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1194 -0
  36. data/vendor/assets/javascripts/RGraph.common.effects.js +1524 -0
  37. data/vendor/assets/javascripts/RGraph.common.key.js +735 -0
  38. data/vendor/assets/javascripts/RGraph.common.resizing.js +550 -0
  39. data/vendor/assets/javascripts/RGraph.common.tooltips.js +605 -0
  40. data/vendor/assets/javascripts/RGraph.common.zoom.js +223 -0
  41. data/vendor/assets/javascripts/RGraph.drawing.background.js +636 -0
  42. data/vendor/assets/javascripts/RGraph.drawing.circle.js +579 -0
  43. data/vendor/assets/javascripts/RGraph.drawing.image.js +810 -0
  44. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +710 -0
  45. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +672 -0
  46. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +568 -0
  47. data/vendor/assets/javascripts/RGraph.drawing.poly.js +623 -0
  48. data/vendor/assets/javascripts/RGraph.drawing.rect.js +603 -0
  49. data/vendor/assets/javascripts/RGraph.drawing.text.js +648 -0
  50. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +815 -0
  51. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +860 -0
  52. data/vendor/assets/javascripts/RGraph.fuel.js +965 -0
  53. data/vendor/assets/javascripts/RGraph.funnel.js +988 -0
  54. data/vendor/assets/javascripts/RGraph.gantt.js +1242 -0
  55. data/vendor/assets/javascripts/RGraph.gauge.js +1391 -0
  56. data/vendor/assets/javascripts/RGraph.hbar.js +1794 -0
  57. data/vendor/assets/javascripts/RGraph.hprogress.js +1307 -0
  58. data/vendor/assets/javascripts/RGraph.line.js +3940 -0
  59. data/vendor/assets/javascripts/RGraph.meter.js +1242 -0
  60. data/vendor/assets/javascripts/RGraph.modaldialog.js +292 -0
  61. data/vendor/assets/javascripts/RGraph.odo.js +1265 -0
  62. data/vendor/assets/javascripts/RGraph.pie.js +1979 -0
  63. data/vendor/assets/javascripts/RGraph.radar.js +1840 -0
  64. data/vendor/assets/javascripts/RGraph.rose.js +1860 -0
  65. data/vendor/assets/javascripts/RGraph.rscatter.js +1332 -0
  66. data/vendor/assets/javascripts/RGraph.scatter.js +3029 -0
  67. data/vendor/assets/javascripts/RGraph.thermometer.js +1131 -0
  68. data/vendor/assets/javascripts/RGraph.vprogress.js +1326 -0
  69. data/vendor/assets/javascripts/RGraph.waterfall.js +1252 -0
  70. data/vendor/assets/javascripts/financial-data.js +1067 -0
  71. data/vendor/assets/stylesheets/ModalDialog.css +90 -0
  72. data/vendor/assets/stylesheets/animations.css +3347 -0
  73. data/vendor/assets/stylesheets/website.css +402 -0
  74. metadata +175 -0
@@ -0,0 +1,1131 @@
1
+ // version: 2015-11-02
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 chart constructor. This function sets up the object. It takes the ID (the HTML attribute) of the canvas as the
23
+ * first argument and the data as the second. If you need to change this, you can.
24
+ *
25
+ * NB: If tooltips are ever implemented they must go below the use event listeners!!
26
+ *
27
+ * @param string id The canvas tag ID
28
+ * @param number min The minimum value
29
+ * @param number max The maximum value
30
+ * @param number value The value reported by the thermometer
31
+ */
32
+ RGraph.Thermometer = function (conf)
33
+ {
34
+ /**
35
+ * Allow for object config style
36
+ */
37
+ if ( typeof conf === 'object'
38
+ && typeof conf.min === 'number'
39
+ && typeof conf.max === 'number'
40
+ && typeof conf.id === 'string') {
41
+
42
+ var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
43
+
44
+ } else {
45
+
46
+ var conf = {
47
+ id: arguments[0],
48
+ min: arguments[1],
49
+ max: arguments[2],
50
+ value: arguments[3]
51
+ }
52
+ }
53
+
54
+
55
+
56
+
57
+ this.id = conf.id;
58
+ this.canvas = document.getElementById(this.id);
59
+ this.context = this.canvas.getContext ? this.canvas.getContext('2d') : null;
60
+ this.canvas.__object__ = this;
61
+ this.uid = RGraph.CreateUID();
62
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
63
+ this.colorsParsed = false;
64
+ this.type = 'thermometer';
65
+ this.isRGraph = true;
66
+ this.min = conf.min;
67
+ this.max = conf.max;
68
+ this.value = RGraph.stringsToNumbers(conf.value);
69
+ this.coords = [];
70
+ this.graphArea = [];
71
+ this.currentValue = null;
72
+ this.bulbRadius = 0;
73
+ this.bulbTopRadius = 0;
74
+ this.bulbTopCenterX = 0
75
+ this.bulbTopCenterY = 0;
76
+ this.coordsText = [];
77
+ this.original_colors = [];
78
+ this.firstDraw = true; // After the first draw this will be false
79
+
80
+
81
+
82
+
83
+ this.properties =
84
+ {
85
+ 'chart.strokestyle': 'black',
86
+ 'chart.colors': ['Gradient(#c00:red:#f66:#fcc)'],
87
+ 'chart.gutter.left': 15,
88
+ 'chart.gutter.right': 15,
89
+ 'chart.gutter.top': 15,
90
+ 'chart.gutter.bottom': 15,
91
+ 'chart.ticksize': 3,
92
+ 'chart.text.color': 'black',
93
+ 'chart.text.font': 'Arial',
94
+ 'chart.text.size': 12,
95
+ 'chart.units.pre': '',
96
+ 'chart.units.post': '',
97
+ 'chart.zoom.factor': 1.5,
98
+ 'chart.zoom.fade.in': true,
99
+ 'chart.zoom.fade.out': true,
100
+ 'chart.zoom.hdir': 'right',
101
+ 'chart.zoom.vdir': 'down',
102
+ 'chart.zoom.frames': 25,
103
+ 'chart.zoom.delay': 16.666,
104
+ 'chart.zoom.shadow': true,
105
+ 'chart.zoom.background': true,
106
+ 'chart.title': '',
107
+ 'chart.title.side': '',
108
+ 'chart.title.side.bold': true,
109
+ 'chart.title.side.font': null,
110
+ 'chart.shadow': true,
111
+ 'chart.shadow.offsetx': 0,
112
+ 'chart.shadow.offsety': 0,
113
+ 'chart.shadow.blur': 15,
114
+ 'chart.shadow.color': 'gray',
115
+ 'chart.resizable': false,
116
+ 'chart.contextmenu': null,
117
+ 'chart.adjustable': false,
118
+ 'chart.value.label': true,
119
+ 'chart.value.label.decimals': null,
120
+ 'chart.value.label.thousand': ',',
121
+ 'chart.value.label.point': '.',
122
+ 'chart.labels.count': 5,
123
+ 'chart.scale.visible': false,
124
+ 'chart.scale.decimals': 0,
125
+ 'chart.annotatable': false,
126
+ 'chart.annotate.color': 'black',
127
+ 'chart.scale.decimals': 0,
128
+ 'chart.scale.point': '.',
129
+ 'chart.scale.thousand': ',',
130
+ 'chart.tooltips': null,
131
+ 'chart.tooltips.highlight': true,
132
+ 'chart.tooltips.effect': 'fade',
133
+ 'chart.tooltips.event': 'onclick',
134
+ 'chart.highlight.stroke': 'rgba(0,0,0,0)',
135
+ 'chart.highlight.fill': 'rgba(255,255,255,0.7)'
136
+ }
137
+
138
+
139
+
140
+ /**
141
+ * A simple check that the browser has canvas support
142
+ */
143
+ if (!this.canvas) {
144
+ alert('[THERMOMETER] No canvas support');
145
+ return;
146
+ }
147
+
148
+ /**
149
+ * The thermometer can only have one data point so only this.$0 needs to be created
150
+ */
151
+ this.$0 = {}
152
+
153
+
154
+ /**
155
+ * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
156
+ * done already
157
+ */
158
+ if (!this.canvas.__rgraph_aa_translated__) {
159
+ this.context.translate(0.5,0.5);
160
+
161
+ this.canvas.__rgraph_aa_translated__ = true;
162
+ }
163
+
164
+
165
+
166
+
167
+ // Short variable names
168
+ var RG = RGraph,
169
+ ca = this.canvas,
170
+ co = ca.getContext('2d'),
171
+ prop = this.properties,
172
+ pa = RG.Path,
173
+ pa2 = RG.path2,
174
+ win = window,
175
+ doc = document,
176
+ ma = Math
177
+
178
+
179
+
180
+ /**
181
+ * "Decorate" the object with the generic effects if the effects library has been included
182
+ */
183
+ if (RG.Effects && typeof RG.Effects.decorate === 'function') {
184
+ RG.Effects.decorate(this);
185
+ }
186
+
187
+
188
+
189
+
190
+ /**
191
+ * A setter.
192
+ *
193
+ * @param name string The name of the property to set
194
+ * @param value mixed The value of the property
195
+ */
196
+ this.set =
197
+ this.Set = function (name)
198
+ {
199
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
200
+
201
+ /**
202
+ * the number of arguments is only one and it's an
203
+ * object - parse it for configuration data and return.
204
+ */
205
+ if (arguments.length === 1 && typeof name === 'object') {
206
+ RG.parseObjectStyleConfig(this, name);
207
+ return this;
208
+ }
209
+
210
+
211
+
212
+
213
+ /**
214
+ * This should be done first - prepend the property name with "chart." if necessary
215
+ */
216
+ if (name.substr(0,6) != 'chart.') {
217
+ name = 'chart.' + name;
218
+ }
219
+
220
+
221
+
222
+
223
+ // Convert uppercase letters to dot+lower case letter
224
+ name = name.replace(/([A-Z])/g, function (str)
225
+ {
226
+ return '.' + String(RegExp.$1).toLowerCase();
227
+ });
228
+
229
+
230
+
231
+
232
+
233
+
234
+ /**
235
+ * Change of name
236
+ */
237
+ if (name == 'chart.ylabels.count') {
238
+ name = 'chart.labels.count';
239
+ }
240
+ prop[name.toLowerCase()] = value;
241
+
242
+ return this;
243
+ };
244
+
245
+
246
+
247
+
248
+ /**
249
+ * A getter.
250
+ *
251
+ * @param name string The name of the property to get
252
+ */
253
+ this.get =
254
+ this.Get = function (name)
255
+ {
256
+ /**
257
+ * This should be done first - prepend the property name with "chart." if necessary
258
+ */
259
+ if (name.substr(0,6) != 'chart.') {
260
+ name = 'chart.' + name;
261
+ }
262
+
263
+ // Convert uppercase letters to dot+lower case letter
264
+ name = name.replace(/([A-Z])/g, function (str)
265
+ {
266
+ return '.' + String(RegExp.$1).toLowerCase()
267
+ });
268
+
269
+ return prop[name];
270
+ };
271
+
272
+
273
+
274
+
275
+ /**
276
+ * Draws the thermometer
277
+ */
278
+ this.draw =
279
+ this.Draw = function ()
280
+ {
281
+ // Fire the custom RGraph onbeforedraw event (which should be fired before the chart is drawn)
282
+ RG.fireCustomEvent(this, 'onbeforedraw');
283
+
284
+ /**
285
+ * Parse the colors. This allows for simple gradient syntax
286
+ */
287
+ if (!this.colorsParsed) {
288
+ this.parseColors();
289
+
290
+ // Don't want to do this again
291
+ this.colorsParsed = true;
292
+ }
293
+
294
+ /**
295
+ * Set the current value
296
+ */
297
+ this.currentValue = this.value;
298
+
299
+
300
+
301
+ /**
302
+ * Stop this growing uncontrollably
303
+ */
304
+ this.coordsText = [];
305
+
306
+
307
+
308
+
309
+
310
+ // This is new in May 2011 and facilitates indiviual gutter settings,
311
+ // eg chart.gutter.left
312
+ this.gutterLeft = prop['chart.gutter.left'];
313
+ this.gutterRight = prop['chart.gutter.right'];
314
+ this.gutterTop = prop['chart.gutter.top'];
315
+ this.gutterBottom = prop['chart.gutter.bottom'];
316
+
317
+
318
+ // Get the scale
319
+ this.scale2 = RG.getScale2(
320
+ this, {
321
+ 'max':this.max,
322
+ 'min':this.min,
323
+ 'strict':true,
324
+ 'scale.thousand':prop['chart.scale.thousand'],
325
+ 'scale.point':prop['chart.scale.point'],
326
+ 'scale.decimals':prop['chart.scale.decimals'],
327
+ 'ylabels.count':prop['chart.labels.count'],
328
+ 'scale.round':prop['chart.scale.round'],
329
+ 'units.pre': prop['chart.units.pre'],
330
+ 'units.post': prop['chart.units.post']
331
+ }
332
+ );
333
+
334
+
335
+ // Draw the background
336
+ this.drawBackground();
337
+
338
+ // Draw the bar that represents the value
339
+ this.drawBar();
340
+
341
+
342
+
343
+
344
+ // Draw the tickmarks
345
+ this.drawTickMarks();
346
+
347
+
348
+
349
+ /**
350
+ * Draw the label
351
+ */
352
+ this.DrawLabels();
353
+
354
+
355
+
356
+ /**
357
+ * Draw the title
358
+ */
359
+ if (prop['chart.title']) {
360
+ this.DrawTitle();
361
+ }
362
+
363
+ /**
364
+ * Draw the side title
365
+ */
366
+ if (prop['chart.title.side']) {
367
+ this.DrawSideTitle();
368
+ }
369
+
370
+ /**
371
+ * This function enables resizing
372
+ */
373
+ if (prop['chart.resizable']) {
374
+ RG.AllowResizing(this);
375
+ }
376
+
377
+
378
+
379
+
380
+ /**
381
+ * Setup the context menu if required
382
+ */
383
+ if (prop['chart.contextmenu']) {
384
+ RG.ShowContext(this);
385
+ }
386
+
387
+
388
+
389
+
390
+ /**
391
+ * This installs the event listeners
392
+ */
393
+ RG.InstallEventListeners(this);
394
+
395
+
396
+ /**
397
+ * Fire the onfirstdraw event
398
+ */
399
+ if (this.firstDraw) {
400
+ RG.fireCustomEvent(this, 'onfirstdraw');
401
+ this.firstDraw = false;
402
+ this.firstDrawFunc();
403
+ }
404
+
405
+
406
+
407
+ /**
408
+ * Fire the custom RGraph ondraw event (which should be fired when you have drawn the chart)
409
+ */
410
+ RG.FireCustomEvent(this, 'ondraw');
411
+
412
+ return this;
413
+ };
414
+
415
+
416
+
417
+
418
+
419
+ /**
420
+ * Draws the thermometer itself
421
+ */
422
+ this.drawBackground =
423
+ this.DrawBackground = function ()
424
+ {
425
+ var bulbRadius = (ca.width - this.gutterLeft - this.gutterRight) / 2;
426
+
427
+ // This is the radius/x/y of the top "semi-circle"
428
+ this.bulbTopRadius = (ca.width - this.gutterLeft - this.gutterRight - 24)/ 2
429
+ this.bulbTopCenterX = this.gutterLeft + bulbRadius;
430
+ this.bulbTopCenterY = this.gutterTop + bulbRadius;
431
+
432
+ //This is the radius/x/y of the bottom bulb
433
+ this.bulbBottomRadius = bulbRadius;
434
+ this.bulbBottomCenterX = this.gutterLeft + bulbRadius;
435
+ this.bulbBottomCenterY = ca.height - this.gutterBottom - bulbRadius;
436
+
437
+ // Save the bulbRadius as an object variable
438
+ this.bulbRadius = bulbRadius;
439
+
440
+ // Draw the black background that becomes the border
441
+ co.beginPath();
442
+ co.fillStyle = prop['chart.strokestyle'];
443
+
444
+ if (prop['chart.shadow']) {
445
+ RG.setShadow(
446
+ this,
447
+ prop['chart.shadow.color'],
448
+ prop['chart.shadow.offsetx'],
449
+ prop['chart.shadow.offsety'],
450
+ prop['chart.shadow.blur']
451
+ );
452
+ }
453
+
454
+ co.fillRect(this.gutterLeft + 12,this.gutterTop + bulbRadius,ca.width - this.gutterLeft - this.gutterRight - 24, ca.height - this.gutterTop - this.gutterBottom - bulbRadius - bulbRadius);
455
+
456
+ // Bottom bulb
457
+ co.arc(this.bulbBottomCenterX, this.bulbBottomCenterY, bulbRadius, 0, RG.TWOPI, 0);
458
+
459
+ // Top bulb (which is actually a semi-circle)
460
+ co.arc(this.bulbTopCenterX,this.bulbTopCenterY,this.bulbTopRadius,0,RG.TWOPI,0);
461
+ co.fill();
462
+
463
+ // Save the radius of the top semi circle
464
+
465
+
466
+ RG.NoShadow(this);
467
+
468
+ // Draw the white inner content background that creates the border
469
+ co.beginPath();
470
+ co.fillStyle = 'white';
471
+ co.fillRect(this.gutterLeft + 12 + 1,this.gutterTop + bulbRadius,ca.width - this.gutterLeft - this.gutterRight - 24 - 2,ca.height - this.gutterTop - this.gutterBottom - bulbRadius - bulbRadius);
472
+ co.arc(this.gutterLeft + bulbRadius, ca.height - this.gutterBottom - bulbRadius, bulbRadius - 1, 0, RG.TWOPI, 0);
473
+ co.arc(this.gutterLeft + bulbRadius,this.gutterTop + bulbRadius,((ca.width - this.gutterLeft - this.gutterRight - 24)/ 2) - 1,0,RG.TWOPI,0);
474
+ co.fill();
475
+
476
+ // Draw the bottom content of the thermometer
477
+ co.beginPath();
478
+ co.fillStyle = prop['chart.colors'][0];
479
+ co.arc(this.gutterLeft + bulbRadius, ca.height - this.gutterBottom - bulbRadius, bulbRadius - 1, 0, RG.TWOPI, 0);
480
+ co.rect(this.gutterLeft + 12 + 1, ca.height - this.gutterBottom - bulbRadius - bulbRadius,ca.width - this.gutterLeft - this.gutterRight - 24 - 2, bulbRadius);
481
+ co.fill();
482
+
483
+
484
+ // Save the X/Y/width/height
485
+ this.graphArea[0] = this.gutterLeft + 12 + 1;
486
+ this.graphArea[1] = this.gutterTop + bulbRadius;
487
+ this.graphArea[2] = ca.width - this.gutterLeft - this.gutterRight - 24 - 2;
488
+ this.graphArea[3] = (ca.height - this.gutterBottom - bulbRadius - bulbRadius) - (this.graphArea[1]);
489
+ };
490
+
491
+
492
+
493
+
494
+ /**
495
+ * This draws the bar that indicates the value of the thermometer
496
+ */
497
+ this.drawBar =
498
+ this.DrawBar = function ()
499
+ {
500
+ var barHeight = ((this.value - this.min) / (this.max - this.min)) * this.graphArea[3];
501
+
502
+ // Draw the actual bar that indicates the value
503
+ co.beginPath();
504
+ co.fillStyle = prop['chart.colors'][0];
505
+
506
+ // This solves an issue with ExCanvas showing a whiite cutout in the chart
507
+ if (RGraph.ISOLD) {
508
+ co.arc(this.bulbBottomCenterX, this.bulbBottomCenterY, this.bulbBottomRadius - 1, 0, RG.TWOPI, false)
509
+ }
510
+
511
+
512
+ co.rect(this.graphArea[0],
513
+ this.graphArea[1] + this.graphArea[3] - barHeight,
514
+ this.graphArea[2],
515
+ barHeight + 2);
516
+ co.fill();
517
+
518
+ this.coords[0] = [this.graphArea[0],this.graphArea[1] + this.graphArea[3] - barHeight,this.graphArea[2],barHeight];
519
+ };
520
+
521
+
522
+
523
+
524
+ /**
525
+ * Draws the tickmarks of the thermometer
526
+ */
527
+ this.drawTickMarks =
528
+ this.DrawTickMarks = function ()
529
+ {
530
+ co.strokeStyle = prop['chart.strokestyle']
531
+ var ticksize = prop['chart.ticksize'];
532
+
533
+ // Left hand side tickmarks
534
+ co.beginPath();
535
+ for (var i=this.graphArea[1]; i<=(this.graphArea[1] + this.graphArea[3]); i += (this.graphArea[3] / 10)) {
536
+ co.moveTo(this.gutterLeft + 12, Math.round(i));
537
+ co.lineTo(this.gutterLeft + 12 + ticksize, Math.round(i));
538
+ }
539
+ co.stroke();
540
+
541
+ // Right hand side tickmarks
542
+ co.beginPath();
543
+ for (var i=this.graphArea[1]; i<=(this.graphArea[1] + this.graphArea[3]); i += (this.graphArea[3] / 10)) {
544
+ co.moveTo(ca.width - (this.gutterRight + 12), Math.round(i));
545
+ co.lineTo(ca.width - (this.gutterRight + 12 + ticksize), Math.round(i));
546
+ }
547
+ co.stroke();
548
+ };
549
+
550
+
551
+
552
+
553
+ /**
554
+ * Draws the labels of the thermometer. Now (4th August 2011) draws
555
+ * the scale too
556
+ */
557
+ this.drawLabels =
558
+ this.DrawLabels = function ()
559
+ {
560
+ /**
561
+ * This draws draws the label that sits at the top of the chart
562
+ */
563
+ if (prop['chart.value.label']) {
564
+ co.fillStyle = prop['chart.text.color'];
565
+
566
+ // Weird...
567
+ var text = prop['chart.scale.visible'] ? RG.number_format(this,
568
+ this.value.toFixed(typeof prop['chart.value.label.decimals'] == 'number' ? prop['chart.value.label.decimals'] : prop['chart.scale.decimals'])
569
+ )
570
+ :
571
+ RG.number_format(this,
572
+ this.value.toFixed(typeof prop['chart.value.label.decimals'] == 'number' ? prop['chart.value.label.decimals'] : prop['chart.scale.decimals']),
573
+ prop['chart.units.pre'],
574
+ prop['chart.units.post']
575
+ );
576
+
577
+ RG.Text2(this, {'font': prop['chart.text.font'],
578
+ 'size': prop['chart.text.size'],
579
+ 'x':this.gutterLeft + this.bulbRadius,
580
+ 'y': this.coords[0][1] + 7,
581
+ 'text': text,
582
+ 'valign':'top',
583
+ 'halign':'center',
584
+ 'bounding':true,
585
+ 'boundingFill':'white',
586
+ 'tag': 'value.label'
587
+ });
588
+ }
589
+
590
+
591
+ /**
592
+ * Draw the scale if requested
593
+ */
594
+ if (prop['chart.scale.visible']) {
595
+ this.DrawScale();
596
+ }
597
+ };
598
+
599
+
600
+
601
+
602
+ /**
603
+ * Draws the title
604
+ */
605
+ this.drawTitle =
606
+ this.DrawTitle = function ()
607
+ {
608
+ co.fillStyle = prop['chart.text.color'];
609
+ RG.Text2(this, {'font': prop['chart.text.font'],
610
+ 'size': prop['chart.text.size'] + 2,
611
+ 'x':this.gutterLeft + ((ca.width - this.gutterLeft - this.gutterRight) / 2),
612
+ 'y': this.gutterTop,
613
+ 'text': String(prop['chart.title']),
614
+ 'valign':'center',
615
+ 'halign':'center',
616
+ 'bold':true,
617
+ 'tag': 'title'
618
+ });
619
+ };
620
+
621
+
622
+
623
+
624
+ /**
625
+ * Draws the title
626
+ */
627
+ this.drawSideTitle =
628
+ this.DrawSideTitle = function ()
629
+ {
630
+ var font = prop['chart.title.side.font'] ? prop['chart.title.side.font'] : prop['chart.text.font'];
631
+ var size = prop['chart.title.side.size'] ? prop['chart.title.side.size'] : prop['chart.text.size'] + 2;
632
+
633
+ co.fillStyle = prop['chart.text.color'];
634
+ RG.Text2(this, {'font': font,
635
+ 'size': size + 2,
636
+ 'x':this.gutterLeft - 3,
637
+ 'y': ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop,
638
+ 'text': String(prop['chart.title.side']),
639
+ 'valign':'center',
640
+ 'halign':'center',
641
+ 'angle':270,
642
+ 'bold':prop['chart.title.side.bold'],
643
+ 'tag': 'title.side'
644
+ });
645
+ };
646
+
647
+
648
+
649
+
650
+ /**
651
+ * Draw the scale if requested
652
+ */
653
+ this.drawScale =
654
+ this.DrawScale = function ()
655
+ {
656
+ var numLabels = prop['chart.labels.count']; // The -1 is so that the number of labels tallies with what is displayed
657
+ var step = (this.max - this.min) / numLabels;
658
+
659
+ co.fillStyle = prop['chart.text.color'];
660
+
661
+ var font = prop['chart.text.font'];
662
+ var size = prop['chart.text.size'];
663
+ var units_pre = prop['chart.units.pre'];
664
+ var units_post = prop['chart.units.post'];
665
+ var decimals = prop['chart.scale.decimals'];
666
+
667
+ for (var i=1; i<=numLabels; ++i) {
668
+
669
+ var x = ca.width - this.gutterRight;
670
+ var y = ca.height - this.gutterBottom - (2 * this.bulbRadius) - ((this.graphArea[3] / numLabels) * i);
671
+ var text = RG.number_format(this, String((this.min + (i * step)).toFixed(decimals)), units_pre, units_post);
672
+
673
+ RG.Text2(this, {'font':font,
674
+ 'size':size,
675
+ 'x':x-6,
676
+ 'y':y,
677
+ 'text':text,
678
+ 'valign':'center',
679
+ 'tag': 'scale'
680
+ });
681
+ }
682
+
683
+ // Draw zero
684
+ RG.Text2(this, {'font':font,
685
+ 'size':size,
686
+ 'x':x-6,
687
+ 'y':ca.height - this.gutterBottom - (2 * this.bulbRadius),
688
+ 'text':RG.number_format(this, (this.min).toFixed(decimals),units_pre,units_post),
689
+ 'valign':'center',
690
+ 'tag': 'scale'
691
+ });
692
+ };
693
+
694
+
695
+
696
+
697
+ /**
698
+ * Returns the focused/clicked bar
699
+ *
700
+ * @param event e The event object
701
+ */
702
+ this.getShape =
703
+ this.getBar = function (e)
704
+ {
705
+ for (var i=0; i<this.coords.length; i++) {
706
+
707
+ var mouseCoords = RGraph.getMouseXY(e);
708
+ var mouseX = mouseCoords[0];
709
+ var mouseY = mouseCoords[1];
710
+
711
+ var left = this.coords[i][0];
712
+ var top = this.coords[i][1];
713
+ var width = this.coords[i][2];
714
+ var height = this.coords[i][3];
715
+
716
+ if ( (mouseX >= left && mouseX <= (left + width) && mouseY >= top && mouseY <= (top + height + this.bulbBottomRadius)) // The bulbBottomRadius is added as the rect and the bulb don't fully cover the red bit
717
+ || RG.getHypLength(this.bulbBottomCenterX, this.bulbBottomCenterY, mouseX, mouseY) <= this.bulbBottomRadius) {
718
+
719
+
720
+ var tooltip = RG.parseTooltipText ? RG.parseTooltipText(prop['chart.tooltips'], i) : '';
721
+
722
+
723
+ return {0: this, 'object': this,
724
+ 1: left, 'x': left,
725
+ 2: top, 'y': top,
726
+ 3: width, 'width': width,
727
+ 4: height, 'height': height,
728
+ 5: i, 'index': i,
729
+ 'tooltip': tooltip
730
+ };
731
+ }
732
+ }
733
+
734
+ return null;
735
+ };
736
+
737
+
738
+
739
+
740
+ /**
741
+ * This function returns the value that the mouse is positioned t, regardless of
742
+ * the actual indicated value.
743
+ *
744
+ * @param object e The event object (or it can also be an two element array containing the X/Y coords)
745
+ */
746
+ this.getValue = function (arg)
747
+ {
748
+ if (arg.length == 2) {
749
+ var mouseX = arg[0];
750
+ var mouseY = arg[1];
751
+ } else {
752
+ var mouseCoords = RGraph.getMouseXY(arg);
753
+ var mouseX = mouseCoords[0];
754
+ var mouseY = mouseCoords[1];
755
+ }
756
+
757
+
758
+
759
+ var value = this.graphArea[3] - (mouseY - this.graphArea[1]);
760
+ value = (value / this.graphArea[3]) * (this.max - this.min);
761
+ value = value + this.min;
762
+
763
+ value = Math.max(value, this.min);
764
+ value = Math.min(value, this.max);
765
+
766
+ return value;
767
+ };
768
+
769
+
770
+
771
+
772
+ /**
773
+ * Each object type has its own Highlight() function which highlights the appropriate shape
774
+ *
775
+ * @param object shape The shape to highlight
776
+ */
777
+ this.highlight =
778
+ this.Highlight = function (shape)
779
+ {
780
+ if (prop['chart.tooltips.highlight']) {
781
+
782
+ // Add the new highlight
783
+ //RGraph.Highlight.Rect(this, shape);
784
+
785
+ co.beginPath();
786
+ co.strokeStyle = prop['chart.highlight.stroke'];
787
+ co.fillStyle = prop['chart.highlight.fill'];
788
+ co.rect(shape['x'],shape['y'],shape['width'],shape['height'] + this.bulbBottomRadius);
789
+ co.arc(this.bulbBottomCenterX, this.bulbBottomCenterY, this.bulbBottomRadius - 1, 0, RG.TWOPI, false);
790
+ co.stroke;
791
+ co.fill();
792
+ }
793
+ };
794
+
795
+
796
+
797
+
798
+ /**
799
+ * The getObjectByXY() worker method. Don't call this - call:
800
+ *
801
+ * RGraph.ObjectRegistry.getObjectByXY(e)
802
+ *
803
+ * @param object e The event object
804
+ */
805
+ this.getObjectByXY = function (e)
806
+ {
807
+ var mouseXY = RGraph.getMouseXY(e);
808
+
809
+ if (
810
+ mouseXY[0] > this.gutterLeft
811
+ && mouseXY[0] < (ca.width - this.gutterRight)
812
+ && mouseXY[1] >= this.gutterTop
813
+ && mouseXY[1] <= (ca.height - this.gutterBottom)
814
+ ) {
815
+
816
+ return this;
817
+ }
818
+ };
819
+
820
+
821
+
822
+
823
+ /**
824
+ * This method handles the adjusting calculation for when the mouse is moved
825
+ *
826
+ * @param object e The event object
827
+ */
828
+ this.adjusting_mousemove =
829
+ this.Adjusting_mousemove = function (e)
830
+ {
831
+ /**
832
+ * Handle adjusting for the Thermometer
833
+ */
834
+ if (prop['chart.adjustable'] && RG.Registry.Get('chart.adjusting') && RG.Registry.Get('chart.adjusting').uid == this.uid) {
835
+
836
+ var mouseXY = RGraph.getMouseXY(e);
837
+ var value = this.getValue(e);
838
+
839
+ if (typeof(value) == 'number') {
840
+
841
+ // Fire the onadjust event
842
+ RG.FireCustomEvent(this, 'onadjust');
843
+
844
+ this.value = Number(value.toFixed(prop['chart.scale.decimals']));
845
+
846
+ RG.redrawCanvas(ca);
847
+ }
848
+ }
849
+ };
850
+
851
+
852
+
853
+
854
+ /**
855
+ * This function positions a tooltip when it is displayed
856
+ *
857
+ * @param obj object The chart object
858
+ * @param int x The X coordinate specified for the tooltip
859
+ * @param int y The Y coordinate specified for the tooltip
860
+ * @param objec tooltip The tooltips DIV element
861
+ */
862
+ this.positionTooltip = function (obj, x, y, tooltip, idx)
863
+ {
864
+ var coordX = obj.coords[tooltip.__index__][0];
865
+ var coordY = obj.coords[tooltip.__index__][1];
866
+ var coordW = obj.coords[tooltip.__index__][2];
867
+ var coordH = obj.coords[tooltip.__index__][3];
868
+ var canvasXY = RGraph.getCanvasXY(ca);
869
+ var gutterLeft = obj.gutterLeft;
870
+ var gutterTop = obj.gutterTop;
871
+ var width = tooltip.offsetWidth;
872
+ var height = tooltip.offsetHeight;
873
+
874
+ // Set the top position
875
+ tooltip.style.left = 0;
876
+ tooltip.style.top = canvasXY[1] + coordY - height - 7 + 'px';
877
+
878
+ // By default any overflow is hidden
879
+ tooltip.style.overflow = '';
880
+
881
+ // The arrow
882
+ var img = new Image();
883
+ img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC';
884
+ img.style.position = 'absolute';
885
+ img.id = '__rgraph_tooltip_pointer__';
886
+ img.style.top = (tooltip.offsetHeight - 2) + 'px';
887
+ tooltip.appendChild(img);
888
+
889
+ // Reposition the tooltip if at the edges:
890
+
891
+ // LEFT edge
892
+ if ((canvasXY[0] + coordX - (width / 2)) < 10) {
893
+ tooltip.style.left = (canvasXY[0] + coordX - (width * 0.1)) + (coordW / 2) + 'px';
894
+ img.style.left = ((width * 0.1) - 8.5) + 'px';
895
+
896
+ // RIGHT edge
897
+ } else if ((canvasXY[0] + coordX + (width / 2)) > doc.body.offsetWidth) {
898
+ tooltip.style.left = canvasXY[0] + coordX - (width * 0.9) + (coordW / 2) + 'px';
899
+ img.style.left = ((width * 0.9) - 8.5) + 'px';
900
+
901
+ // Default positioning - CENTERED
902
+ } else {
903
+ tooltip.style.left = (canvasXY[0] + coordX + (coordW / 2) - (width * 0.5)) + 'px';
904
+ img.style.left = ((width * 0.5) - 8.5) + 'px';
905
+ }
906
+ };
907
+
908
+
909
+
910
+
911
+ /**
912
+ * Returns the appropriate Y coord for a value
913
+ *
914
+ * @param number value The value to return the coord for
915
+ */
916
+ this.getYCoord = function (value)
917
+ {
918
+ if (value > this.max || value < this.min) {
919
+ return null;
920
+ }
921
+
922
+ var y = (this.graphArea[1] + this.graphArea[3]) - (((value - this.min) / (this.max - this.min)) * this.graphArea[3]);
923
+
924
+ return y;
925
+ };
926
+
927
+
928
+
929
+
930
+ /**
931
+ * This returns true/false as to whether the cursor is over the chart area.
932
+ * The cursor does not necessarily have to be over the bar itself.
933
+ */
934
+ this.overChartArea = function (e)
935
+ {
936
+ var mouseXY = RG.getMouseXY(e);
937
+ var mouseX = mouseXY[0];
938
+ var mouseY = mouseXY[1];
939
+
940
+ // Is the mouse in the "graphArea"?
941
+ // ( with a little extra height added)
942
+ if ( mouseX >= this.graphArea[0]
943
+ && mouseX <= (this.graphArea[0] + this.graphArea[2])
944
+ && mouseY >= this.graphArea[1]
945
+ && mouseY <= (this.graphArea[1] + this.graphArea[3] + this.bulbRadius)
946
+ ) {
947
+
948
+ return true;
949
+ }
950
+
951
+ // Is the mouse over the bottom bulb?
952
+ if (RG.getHypLength(this.bulbBottomCenterX, this.bulbBottomCenterY, mouseX, mouseY) <= this.bulbRadius) {
953
+ return true;
954
+ }
955
+
956
+ // Is the mouse over the semi-circle at the top?
957
+ if (RG.getHypLength(this.bulbTopCenterX, this.bulbTopCenterY, mouseX, mouseY) <= this.bulbTopRadius) {
958
+ return true;
959
+ }
960
+
961
+ return false;
962
+ };
963
+
964
+
965
+
966
+
967
+ /**
968
+ * This allows for easy specification of gradients
969
+ */
970
+ this.parseColors = function ()
971
+ {
972
+ // Save the original colors so that they can be restored when the canvas is reset
973
+ if (this.original_colors.length === 0) {
974
+ this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
975
+ }
976
+
977
+
978
+
979
+
980
+
981
+ var colors = prop['chart.colors'];
982
+
983
+ for (var i=0; i<colors.length; ++i) {
984
+ colors[i] = this.parseSingleColorForGradient(colors[i]);
985
+ }
986
+ };
987
+
988
+
989
+
990
+
991
+ /**
992
+ * Use this function to reset the object to the post-constructor state. Eg reset colors if
993
+ * need be etc
994
+ */
995
+ this.reset = function ()
996
+ {
997
+ };
998
+
999
+
1000
+
1001
+
1002
+ /**
1003
+ * This parses a single color value
1004
+ */
1005
+ this.parseSingleColorForGradient = function (color)
1006
+ {
1007
+ if (!color) {
1008
+ return color;
1009
+ }
1010
+
1011
+ if (typeof color === 'string' && color.match(/^gradient\((.*)\)$/i)) {
1012
+
1013
+ var parts = RegExp.$1.split(':');
1014
+
1015
+ // Create the gradient
1016
+ var grad = co.createLinearGradient(prop['chart.gutter.left'], 0, ca.width - prop['chart.gutter.right'],0);
1017
+
1018
+ var diff = 1 / (parts.length - 1);
1019
+
1020
+ grad.addColorStop(0, RG.trim(parts[0]));
1021
+
1022
+ for (var j=1; j<parts.length; ++j) {
1023
+ grad.addColorStop(j * diff, RG.trim(parts[j]));
1024
+ }
1025
+ }
1026
+
1027
+ return grad ? grad : color;
1028
+ };
1029
+
1030
+
1031
+
1032
+
1033
+ /**
1034
+ * Using a function to add events makes it easier to facilitate method chaining
1035
+ *
1036
+ * @param string type The type of even to add
1037
+ * @param function func
1038
+ */
1039
+ this.on = function (type, func)
1040
+ {
1041
+ if (type.substr(0,2) !== 'on') {
1042
+ type = 'on' + type;
1043
+ }
1044
+
1045
+ this[type] = func;
1046
+
1047
+ return this;
1048
+ };
1049
+
1050
+
1051
+
1052
+
1053
+ /**
1054
+ * This function runs once only
1055
+ * (put at the end of the file (before any effects))
1056
+ */
1057
+ this.firstDrawFunc = function ()
1058
+ {
1059
+ };
1060
+
1061
+
1062
+
1063
+
1064
+ /**
1065
+ * Gauge Grow
1066
+ *
1067
+ * This effect gradually increases the represented value
1068
+ *
1069
+ * @param object obj The chart object
1070
+ * @param Not used - pass null
1071
+ * @param function An optional callback function
1072
+ */
1073
+ this.grow = function ()
1074
+ {
1075
+ var obj = this;
1076
+ var callback = arguments[1] || function () {};
1077
+ var opt = arguments[0] || {};
1078
+ var frames = opt.frames ? opt.frames : 30;
1079
+ var origValue = Number(obj.currentValue);
1080
+ var newValue = obj.value;
1081
+ newValue = ma.min(newValue, this.max);
1082
+ newValue = ma.max(newValue, this.min);
1083
+ var diff = newValue - origValue;
1084
+ var step = (diff / frames);
1085
+ var frame = 0;
1086
+
1087
+
1088
+ function iterate ()
1089
+ {
1090
+ // Set the new value
1091
+ obj.value = (step * frame) + origValue;
1092
+
1093
+ RGraph.clear(obj.canvas);
1094
+ RGraph.redrawCanvas(obj.canvas);
1095
+
1096
+ if (frame < frames) {
1097
+ frame++;
1098
+ RGraph.Effects.updateCanvas(iterate);
1099
+ } else {
1100
+ callback(obj);
1101
+ }
1102
+ }
1103
+
1104
+ iterate();
1105
+
1106
+ return this;
1107
+ };
1108
+
1109
+
1110
+
1111
+ RG.att(ca);
1112
+
1113
+
1114
+
1115
+
1116
+ /**
1117
+ * Now, because canvases can support multiple charts, canvases must always be registered
1118
+ */
1119
+ RG.Register(this);
1120
+
1121
+
1122
+
1123
+
1124
+ /**
1125
+ * This is the 'end' of the constructor so if the first argument
1126
+ * contains configuration data - handle that.
1127
+ */
1128
+ if (parseConfObjectForOptions) {
1129
+ RG.parseObjectStyleConfig(this, conf.options);
1130
+ }
1131
+ };