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,860 @@
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
+ /**
17
+ * Having this here means that the RGraph libraries can be included in any order, instead of you having
18
+ * to include the common core library first.
19
+ */
20
+
21
+ // Define the RGraph global variable
22
+ RGraph = window.RGraph || {isRGraph: true};
23
+ RGraph.Drawing = RGraph.Drawing || {};
24
+
25
+ /**
26
+ * The constructor. This function sets up the object. It takes the ID (the HTML attribute) of the canvas as the
27
+ * first argument and the X coordinate of the axis as the second
28
+ *
29
+ * @param string id The canvas tag ID
30
+ * @param number x The X coordinate of the Y axis
31
+ */
32
+ RGraph.Drawing.YAxis = function (conf)
33
+ {
34
+
35
+ /**
36
+ * Allow for object config style
37
+ */
38
+ if ( typeof conf === 'object'
39
+ && typeof conf.x === 'number'
40
+ && typeof conf.id === 'string') {
41
+
42
+ var id = conf.id
43
+ var x = conf.x;
44
+
45
+ var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
46
+
47
+ } else {
48
+
49
+ var id = conf;
50
+ var x = arguments[1];
51
+ }
52
+
53
+ this.id = id;
54
+ this.canvas = document.getElementById(this.id);
55
+ this.context = this.canvas.getContext("2d");
56
+ this.canvas.__object__ = this;
57
+ this.x = x;
58
+ this.coords = [];
59
+ this.coordsText = [];
60
+ this.original_colors = [];
61
+ this.maxLabelLength = 0;
62
+ this.firstDraw = true; // After the first draw this will be false
63
+
64
+
65
+ /**
66
+ * This defines the type of this shape
67
+ */
68
+ this.type = 'drawing.yaxis';
69
+
70
+
71
+ /**
72
+ * This facilitates easy object identification, and should always be true
73
+ */
74
+ this.isRGraph = true;
75
+
76
+
77
+ /**
78
+ * This adds a uid to the object that you can use for identification purposes
79
+ */
80
+ this.uid = RGraph.CreateUID();
81
+
82
+
83
+ /**
84
+ * This adds a UID to the canvas for identification purposes
85
+ */
86
+ this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
87
+
88
+
89
+
90
+ /**
91
+ * Some example background properties
92
+ */
93
+ this.properties =
94
+ {
95
+ 'chart.gutter.top': 25,
96
+ 'chart.gutter.bottom': 30,
97
+ 'chart.min': 0,
98
+ 'chart.max': null,
99
+ 'chart.colors': ['black'],
100
+ 'chart.title': '',
101
+ 'chart.title.color': null,
102
+ 'chart.text.color': null,
103
+ 'chart.numticks': 5,
104
+ 'chart.numlabels': 5,
105
+ 'chart.labels.specific': null,
106
+ 'chart.text.font': 'Arial',
107
+ 'chart.text.size': 12,
108
+ 'chart.align': 'left',
109
+ 'hart.scale.formatter': null,
110
+ 'chart.scale.point': '.',
111
+ 'chart.scale.decimals': 0,
112
+ 'chart.scale.decimals': 0,
113
+ 'chart.scale.point': '.',
114
+ 'chart.scale.invert': false,
115
+ 'chart.scale.zerostart': true,
116
+ 'chart.scale.visible': true,
117
+ 'chart.units.pre': '',
118
+ 'chart.units.post': '',
119
+ 'chart.linewidth': 1,
120
+ 'chart.noendtick.top': false,
121
+ 'chart.noendtick.bottom': false,
122
+ 'chart.noyaxis': false,
123
+ 'chart.tooltips': null,
124
+ 'chart.tooltips.effect': 'fade',
125
+ 'chart.tooltips.css.class':'RGraph_tooltip',
126
+ 'chart.tooltips.event': 'onclick',
127
+ 'chart.xaxispos': 'bottom',
128
+ 'chart.events.click': null,
129
+ 'chart.events.mousemove': null
130
+ }
131
+
132
+
133
+ /**
134
+ * A simple check that the browser has canvas support
135
+ */
136
+ if (!this.canvas) {
137
+ alert('[DRAWING.YAXIS] No canvas support');
138
+ return;
139
+ }
140
+
141
+ /**
142
+ * Create the dollar object so that functions can be added to them
143
+ */
144
+ this.$0 = {};
145
+
146
+
147
+ /**
148
+ * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
149
+ * done already
150
+ *
151
+ * ** Could use setTransform() here instead ?
152
+ */
153
+ if (!this.canvas.__rgraph_aa_translated__) {
154
+ this.context.translate(0.5,0.5);
155
+
156
+ this.canvas.__rgraph_aa_translated__ = true;
157
+ }
158
+
159
+
160
+
161
+ // Short variable names
162
+ var RG = RGraph,
163
+ ca = this.canvas,
164
+ co = ca.getContext('2d'),
165
+ prop = this.properties,
166
+ pa = RG.Path,
167
+ pa2 = RG.path2,
168
+ win = window,
169
+ doc = document,
170
+ ma = Math
171
+
172
+
173
+
174
+ /**
175
+ * "Decorate" the object with the generic effects if the effects library has been included
176
+ */
177
+ if (RG.Effects && typeof RG.Effects.decorate === 'function') {
178
+ RG.Effects.decorate(this);
179
+ }
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+ /**
189
+ * A setter method for setting graph properties. It can be used like this: obj.Set('chart.strokestyle', '#666');
190
+ *
191
+ * @param name string The name of the property to set
192
+ * @param value mixed The value of the property
193
+ */
194
+ this.set =
195
+ this.Set = function (name)
196
+ {
197
+ var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
198
+
199
+ /**
200
+ * the number of arguments is only one and it's an
201
+ * object - parse it for configuration data and return.
202
+ */
203
+ if (arguments.length === 1 && typeof name === 'object') {
204
+ RG.parseObjectStyleConfig(this, name);
205
+ return this;
206
+ }
207
+
208
+
209
+
210
+
211
+
212
+ /**
213
+ * This should be done first - prepend the property name with "chart." if necessary
214
+ */
215
+ if (name.substr(0,6) != 'chart.') {
216
+ name = 'chart.' + name;
217
+ }
218
+
219
+
220
+
221
+
222
+ // Convert uppercase letters to dot+lower case letter
223
+ name = name.replace(/([A-Z])/g, function (str)
224
+ {
225
+ return '.' + String(RegExp.$1).toLowerCase();
226
+ });
227
+
228
+
229
+
230
+
231
+
232
+
233
+ prop[name] = value;
234
+
235
+ return this;
236
+ };
237
+
238
+
239
+
240
+
241
+ /**
242
+ * A getter method for retrieving graph properties. It can be used like this: obj.Get('chart.strokestyle');
243
+ *
244
+ * @param name string The name of the property to get
245
+ */
246
+ this.get =
247
+ this.Get = function (name)
248
+ {
249
+ /**
250
+ * This should be done first - prepend the property name with "chart." if necessary
251
+ */
252
+ if (name.substr(0,6) != 'chart.') {
253
+ name = 'chart.' + name;
254
+ }
255
+
256
+ // Convert uppercase letters to dot+lower case letter
257
+ name = name.replace(/([A-Z])/g, function (str)
258
+ {
259
+ return '.' + String(RegExp.$1).toLowerCase()
260
+ });
261
+
262
+ return prop[name.toLowerCase()];
263
+ };
264
+
265
+
266
+
267
+
268
+ /**
269
+ * Draws the axes
270
+ */
271
+ this.draw =
272
+ this.Draw = function ()
273
+ {
274
+ /**
275
+ * Fire the onbeforedraw event
276
+ */
277
+ RG.fireCustomEvent(this, 'onbeforedraw');
278
+
279
+ /**
280
+ * Some defaults
281
+ */
282
+ this.gutterTop = prop['chart.gutter.top'];
283
+ this.gutterBottom = prop['chart.gutter.bottom'];
284
+
285
+
286
+ /**
287
+ * Stop this growing uncntrollably
288
+ */
289
+ this.coordsText = [];
290
+
291
+
292
+
293
+ if (!prop['chart.text.color']) prop['chart.text.color'] = prop['chart.colors'][0];
294
+ if (!prop['chart.title.color']) prop['chart.title.color'] = prop['chart.colors'][0];
295
+
296
+ /**
297
+ * Parse the colors. This allows for simple gradient syntax
298
+ */
299
+ if (!this.colorsParsed) {
300
+
301
+ this.parseColors();
302
+
303
+ // Don't want to do this again
304
+ this.colorsParsed = true;
305
+ }
306
+
307
+
308
+
309
+ // DRAW Y AXIS HERE
310
+ this.drawYAxis();
311
+
312
+
313
+ /**
314
+ * This installs the event listeners
315
+ */
316
+ RG.InstallEventListeners(this);
317
+
318
+
319
+
320
+ /**
321
+ * Fire the onfirstdraw event
322
+ */
323
+ if (this.firstDraw) {
324
+ RG.fireCustomEvent(this, 'onfirstdraw');
325
+ this.firstDraw = false;
326
+ this.firstDrawFunc();
327
+ }
328
+
329
+
330
+
331
+
332
+ /**
333
+ * Fire the ondraw event
334
+ */
335
+ RG.FireCustomEvent(this, 'ondraw');
336
+
337
+ return this;
338
+ };
339
+
340
+
341
+
342
+ /**
343
+ * Used in chaining. Runs a function there and then - not waiting for
344
+ * the events to fire (eg the onbeforedraw event)
345
+ *
346
+ * @param function func The function to execute
347
+ */
348
+ this.exec = function (func)
349
+ {
350
+ func(this);
351
+
352
+ return this;
353
+ };
354
+
355
+
356
+
357
+
358
+ /**
359
+ * The getObjectByXY() worker method
360
+ */
361
+ this.getObjectByXY = function (e)
362
+ {
363
+ if (this.getShape(e)) {
364
+ return this;
365
+ }
366
+ };
367
+
368
+
369
+
370
+
371
+ /**
372
+ * Not used by the class during creating the axis, but is used by event handlers
373
+ * to get the coordinates (if any) of the selected shape
374
+ *
375
+ * @param object e The event object
376
+ */
377
+ this.getShape = function (e)
378
+ {
379
+ var mouseXY = RG.getMouseXY(e);
380
+ var mouseX = mouseXY[0];
381
+ var mouseY = mouseXY[1];
382
+
383
+ if ( mouseX >= this.x - (prop['chart.align'] == 'right' ? 0 : this.getWidth())
384
+ && mouseX <= this.x + (prop['chart.align'] == 'right' ? this.getWidth() : 0)
385
+ && mouseY >= this.gutterTop
386
+ && mouseY <= (ca.height - this.gutterBottom)
387
+ ) {
388
+
389
+ var x = this.x;
390
+ var y = this.gutterTop;
391
+ var w = 15;;
392
+ var h = ca.height - this.gutterTop - this.gutterBottom;
393
+
394
+ return {
395
+ 0: this, 1: x, 2: y, 3: w, 4: h, 5: 0,
396
+ 'object': this, 'x': x, 'y': y, 'width': w, 'height': h, 'index': 0, 'tooltip': prop['chart.tooltips'] ? prop['chart.tooltips'][0] : null
397
+ };
398
+ }
399
+
400
+ return null;
401
+ };
402
+
403
+
404
+
405
+
406
+ /**
407
+ * This function positions a tooltip when it is displayed
408
+ *
409
+ * @param obj object The chart object
410
+ * @param int x The X coordinate specified for the tooltip
411
+ * @param int y The Y coordinate specified for the tooltip
412
+ * @param objec tooltip The tooltips DIV element
413
+ */
414
+ this.positionTooltip = function (obj, x, y, tooltip, idx)
415
+ {
416
+ // If there's multiple charts on the canvas they leave unknown font settings
417
+ co.font = prop['chart.text.size'] + ' ' + prop['chart.text.font'];
418
+
419
+ var coordW = co.measureText(prop['chart.max'].toFixed(prop['chart.scale.decimals'])).width;
420
+ var coordX = obj.x - coordW;
421
+ var coordY = obj.gutterTop;
422
+ var coordH = ca.height - obj.gutterTop - obj.gutterBottom;
423
+ var canvasXY = RG.getCanvasXY(ca);
424
+
425
+ var width = tooltip.offsetWidth;
426
+ var height = tooltip.offsetHeight;
427
+
428
+ // Set the top position
429
+ tooltip.style.left = 0;
430
+ tooltip.style.top = canvasXY[1] + ((ca.height - this.gutterTop - this.gutterBottom) / 2) + 'px';
431
+
432
+ // By default any overflow is hidden
433
+ tooltip.style.overflow = '';
434
+
435
+ // The arrow
436
+ var img = new Image();
437
+ img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC';
438
+ img.style.position = 'absolute';
439
+ img.id = '__rgraph_tooltip_pointer__';
440
+ img.style.top = (tooltip.offsetHeight - 2) + 'px';
441
+ tooltip.appendChild(img);
442
+
443
+ // Reposition the tooltip if at the edges:
444
+
445
+ // LEFT edge
446
+ if ((canvasXY[0] + coordX + (coordW / 2) - (width / 2)) < 10) {
447
+ tooltip.style.left = prop['chart.align'] == 'right' ? canvasXY[0] + obj.x - (width * 0.1) + (coordW / 2) + 'px'
448
+ : (canvasXY[0] + coordX - (width * 0.1)) + (coordW / 2) + 'px';
449
+ img.style.left = (width * 0.1) - 8.5 + 'px';
450
+
451
+ // RIGHT edge
452
+ } else if ((canvasXY[0] + coordX + (width / 2)) > document.body.offsetWidth) {
453
+ tooltip.style.left = prop['chart.align'] == 'right' ? canvasXY[0] + obj.x - (width * 0.9) + (coordW / 2) + 'px'
454
+ : canvasXY[0] + coordX - (width * 0.9) + (coordW / 2) + 'px';
455
+ img.style.left = ((width * 0.9) - 8.5) + 'px';
456
+
457
+ // Default positioning - CENTERED
458
+ } else {
459
+ tooltip.style.left = prop['chart.align'] == 'right' ? canvasXY[0] + obj.x - (width / 2) + (coordW / 2) + 'px'
460
+ : canvasXY[0] + obj.x - (width / 2) - (coordW / 2) + 'px';
461
+ img.style.left = ((width * 0.5) - 8.5) + 'px';
462
+ }
463
+ };
464
+
465
+
466
+
467
+
468
+ /**
469
+ * Each object type has its own Highlight() function which highlights the appropriate shape
470
+ *
471
+ * @param object shape The shape to highlight
472
+ */
473
+ this.highlight =
474
+ this.Highlight = function (shape)
475
+ {
476
+ // When showing tooltips, this method can be used to highlight the X axis
477
+ };
478
+
479
+
480
+
481
+
482
+ /**
483
+ * This allows for easy specification of gradients
484
+ */
485
+ this.parseColors = function ()
486
+ {
487
+
488
+ // Save the original colors so that they can be restored when the canvas is reset
489
+ if (this.original_colors.length === 0) {
490
+ this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
491
+ }
492
+
493
+
494
+
495
+
496
+ /**
497
+ * Parse various properties for colors
498
+ */
499
+ //prop['chart.title.color'] = this.parseSingleColorForGradient(prop['chart.title.color']);
500
+ //prop['chart.text.color'] = this.parseSingleColorForGradient(prop['chart.text.color']);
501
+ prop['chart.colors'][0] = this.parseSingleColorForGradient(prop['chart.colors'][0]);
502
+ };
503
+
504
+
505
+
506
+
507
+ /**
508
+ * Use this function to reset the object to the post-constructor state. Eg reset colors if
509
+ * need be etc
510
+ */
511
+ this.reset = function ()
512
+ {
513
+ };
514
+
515
+
516
+
517
+
518
+ /**
519
+ * This parses a single color value
520
+ */
521
+ this.parseSingleColorForGradient = function (color)
522
+ {
523
+ if (!color) {
524
+ return color;
525
+ }
526
+
527
+ if (typeof color === 'string' && color.match(/^gradient\((.*)\)$/i)) {
528
+
529
+ var parts = RegExp.$1.split(':');
530
+
531
+ // Create the gradient
532
+ var grad = co.createLinearGradient(0,prop['chart.gutter.top'],0,ca.height - this.gutterBottom);
533
+
534
+ var diff = 1 / (parts.length - 1);
535
+
536
+ grad.addColorStop(0, RG.trim(parts[0]));
537
+
538
+ for (var j=1; j<parts.length; ++j) {
539
+ grad.addColorStop(j * diff, RG.trim(parts[j]));
540
+ }
541
+ }
542
+
543
+ return grad ? grad : color;
544
+ };
545
+
546
+
547
+
548
+
549
+ /**
550
+ * The function that draws the Y axis
551
+ */
552
+ this.drawYAxis =
553
+ this.DrawYAxis = function ()
554
+ {
555
+ // Allow both axis.xxx and chart.xxx to prevent any confusion that may arise
556
+ for (i in prop) {
557
+ if (typeof(i) == 'string') {
558
+ var key = i.replace(/^chart\./, 'axis.');
559
+
560
+ prop[key] = prop[i];
561
+ }
562
+ }
563
+
564
+ var x = this.x,
565
+ y = this.gutterTop,
566
+ height = ca.height - this.gutterBottom - this.gutterTop,
567
+ min = +prop['chart.min'] ? +prop['chart.min'] : 0,
568
+ max = +prop['chart.max'],
569
+ title = prop['chart.title'] ? prop['chart.title'] : '',
570
+ color = prop['chart.colors'] ? prop['chart.colors'][0] : 'black',
571
+ title_color = prop['chart.title.color'] ? prop['chart.title.color'] : color,
572
+ label_color = prop['chart.text.color'] ? prop['chart.text.color'] : color,
573
+ numticks = typeof(prop['chart.numticks']) == 'number' ? prop['chart.numticks'] : 10,
574
+ labels_specific = prop['chart.labels.specific'],
575
+ numlabels = prop['chart.numlabels'] ? prop['chart.numlabels'] : 5,
576
+ font = prop['chart.text.font'] ? prop['chart.text.font'] : 'Arial',
577
+ size = prop['chart.text.size'] ? prop['chart.text.size'] : 10
578
+ align = typeof(prop['chart.align']) == 'string'? prop['chart.align'] : 'left',
579
+ formatter = prop['chart.scale.formatter'],
580
+ decimals = prop['chart.scale.decimals'],
581
+ invert = prop['chart.scale.invert'],
582
+ scale_visible = prop['chart.scale.visible'],
583
+ units_pre = prop['chart.units.pre'],
584
+ units_post = prop['chart.units.post'],
585
+ linewidth = prop['chart.linewidth'] ? prop['chart.linewidth'] : 1,
586
+ notopendtick = prop['chart.noendtick.top'],
587
+ nobottomendtick = prop['chart.noendtick.bottom'],
588
+ noyaxis = prop['chart.noyaxis'],
589
+ xaxispos = prop['chart.xaxispos']
590
+
591
+
592
+ // This fixes missing corner pixels in Chrome
593
+ co.lineWidth = linewidth + 0.001;
594
+
595
+
596
+ /**
597
+ * Set the color
598
+ */
599
+ co.strokeStyle = color;
600
+
601
+ if (!noyaxis) {
602
+ /**
603
+ * Draw the main vertical line
604
+ */
605
+ pa(co,['b','m',Math.round(x), y,'l',Math.round(x), y + height,'s',color]);
606
+
607
+ /**
608
+ * Draw the axes tickmarks
609
+ */
610
+ if (numticks) {
611
+
612
+ var gap = (xaxispos == 'center' ? height / 2 : height) / numticks;
613
+ var halfheight = height / 2;
614
+
615
+ co.beginPath();
616
+ for (var i=(notopendtick ? 1 : 0); i<=(numticks - (nobottomendtick || xaxispos == 'center'? 1 : 0)); ++i) {
617
+ pa(co, ['m',align == 'right' ? x + 3 : x - 3, Math.round(y + (gap *i)),'l',x, Math.round(y + (gap *i))]);
618
+ }
619
+
620
+ // Draw the bottom halves ticks if the X axis is in the center
621
+ if (xaxispos == 'center') {
622
+ for (var i=1; i<=numticks; ++i) {
623
+ pa(co, ['m',align == 'right' ? x + 3 : x - 3, Math.round(y + halfheight + (gap *i)),'l',x, Math.round(y + halfheight + (gap *i))]);
624
+ }
625
+ }
626
+ co.stroke();
627
+ }
628
+ }
629
+
630
+
631
+ /**
632
+ * Draw the scale for the axes
633
+ */
634
+ co.fillStyle = label_color;
635
+ //co.beginPath();
636
+ var text_len = 0;
637
+ if (scale_visible) {
638
+ if (labels_specific && labels_specific.length) {
639
+
640
+ var text_len = 0;
641
+
642
+ // First - gp through the labels to find the longest
643
+ for (var i=0,len=labels_specific.length; i<len; i+=1) {
644
+ text_len = Math.max(text_len, co.measureText(labels_specific[i]).width);
645
+ }
646
+
647
+ for (var i=0,len=labels_specific.length; i<len; ++i) {
648
+
649
+ var gap = (len-1) > 0 ? (height / (len-1)) : 0;
650
+
651
+ if (xaxispos == 'center') {
652
+ gap /= 2;
653
+ }
654
+
655
+ RG.Text2(this, {'font':font,
656
+ 'size':size,
657
+ 'x':x - (align == 'right' ? -5 : 5),
658
+ 'y':(i * gap) + this.gutterTop,
659
+ 'text':labels_specific[i],
660
+ 'valign':'center',
661
+ 'halign':align == 'right' ? 'left' : 'right',
662
+ 'tag': 'scale'
663
+ });
664
+
665
+ /**
666
+ * Store the max length so that it can be used if necessary to determine
667
+ * whether the mouse is over the axis.
668
+ */
669
+ this.maxLabelLength = ma.max(this.maxLabelLength, co.measureText(labels_specific[i]).width);
670
+ }
671
+
672
+ if (xaxispos == 'center') {
673
+
674
+ // It's "-2" so that the center label isn't added twice
675
+ for (var i=(labels_specific.length-2); i>=0; --i) {
676
+
677
+ RG.Text2(this, {'font':font,
678
+ 'size':size,
679
+ 'x':x - (align == 'right' ? -5 : 5),
680
+ 'y':ca.height - this.gutterBottom - (i * gap),
681
+ 'text':labels_specific[i],
682
+ 'valign':'center',
683
+ 'halign':align == 'right' ? 'left' : 'right',
684
+ 'tag': 'scale'
685
+ });
686
+ }
687
+ }
688
+
689
+ } else {
690
+
691
+ for (var i=0; i<=numlabels; ++i) {
692
+
693
+ var original = ((max - min) * ((numlabels-i) / numlabels)) + min;
694
+
695
+ if (original == 0 && prop['chart.scale.zerostart'] == false) {
696
+ continue;
697
+ }
698
+
699
+ var text = RG.number_format(this, original.toFixed(decimals), units_pre, units_post);
700
+ var text = String(typeof(formatter) == 'function' ? formatter(this, original) : text);
701
+
702
+ // text_len is used below for positioning the title
703
+ var text_len = Math.max(text_len, co.measureText(text).width);
704
+ this.maxLabelLength = text_len;
705
+
706
+ if (invert) {
707
+ var y = height - ((height / numlabels)*i);
708
+ } else {
709
+ var y = (height / numlabels)*i;
710
+ }
711
+
712
+ if (prop['chart.xaxispos'] == 'center') {
713
+ y = y / 2;
714
+ }
715
+
716
+ // This fixes a bug, Replace this: -,400 with this: -400
717
+ text = text.replace(/^-,([0-9])/, '-$1');
718
+
719
+
720
+ /**
721
+ * Now - draw the labels
722
+ */
723
+ RG.Text2(this, {'font':font,
724
+ 'size':size,
725
+ 'x':x - (align == 'right' ? -5 : 5),
726
+ 'y':y + this.gutterTop,
727
+ 'text':text,
728
+ 'valign':'center',
729
+ 'halign':align == 'right' ? 'left' : 'right',
730
+ 'tag': 'scale'
731
+ });
732
+
733
+
734
+
735
+ /**
736
+ * Draw the bottom half of the labels if the X axis is in the center
737
+ */
738
+ if (prop['chart.xaxispos'] == 'center' && i < numlabels) {
739
+ RG.Text2(this, {'font':font,
740
+ 'size':size,
741
+ 'x':x - (align == 'right' ? -5 : 5),
742
+ 'y':ca.height - this.gutterBottom - y,
743
+ 'text':'-' + text,
744
+ 'valign':'center',
745
+ 'halign':align == 'right' ? 'left' : 'right',
746
+ 'tag': 'scale'
747
+ });
748
+ }
749
+ }
750
+ }
751
+ }
752
+ //co.stroke();
753
+
754
+ /**
755
+ * Draw the title for the axes
756
+ */
757
+ if (title) {
758
+ co.beginPath();
759
+
760
+ co.fillStyle = title_color;
761
+ if (labels_specific) {
762
+
763
+ var width = 0;
764
+ for (var i=0,len=labels_specific.length; i<len; i+=1) {
765
+ width = Math.max(width, co.measureText(labels_specific[i]).width);
766
+ }
767
+
768
+ } else {
769
+ var width = co.measureText(prop['chart.units.pre'] + prop['chart.max'].toFixed(prop['chart.scale.decimals']) + prop['chart.units.post']).width;
770
+ }
771
+
772
+
773
+ RG.Text2(this, {'font':font,
774
+ 'size':size + 2,
775
+ 'x':align == 'right' ? x + width + 8 : x - width - 8,
776
+ 'y':height / 2 + this.gutterTop,
777
+ 'text':title,
778
+ 'valign':'bottom',
779
+ 'halign':'center',
780
+ 'angle':align == 'right' ? 90 : -90});
781
+ co.stroke();
782
+ }
783
+ };
784
+
785
+
786
+
787
+
788
+ /**
789
+ * This detemines the maximum text width of either the scale or text
790
+ * labels - whichever is given
791
+ *
792
+ * @return number The maximum text width
793
+ */
794
+ this.getWidth = function ()
795
+ {
796
+ var width = this.maxLabelLength;
797
+
798
+ // Add the title width if it's specified
799
+ if (prop['chart.title'] && prop['chart.title'].length) {
800
+ width += (prop['chart.text.size'] * 1.5);
801
+ }
802
+
803
+ this.width = width;
804
+
805
+ return width;
806
+ };
807
+
808
+
809
+
810
+
811
+ /**
812
+ * Using a function to add events makes it easier to facilitate method chaining
813
+ *
814
+ * @param string type The type of even to add
815
+ * @param function func
816
+ */
817
+ this.on = function (type, func)
818
+ {
819
+ if (type.substr(0,2) !== 'on') {
820
+ type = 'on' + type;
821
+ }
822
+
823
+ this[type] = func;
824
+
825
+ return this;
826
+ };
827
+
828
+
829
+
830
+
831
+ /**
832
+ * This function runs once only
833
+ * (put at the end of the file (before any effects))
834
+ */
835
+ this.firstDrawFunc = function ()
836
+ {
837
+ };
838
+
839
+
840
+ RG.att(ca);
841
+
842
+
843
+
844
+
845
+ /**
846
+ * Objects are now always registered so that the chart is redrawn if need be.
847
+ */
848
+ RG.Register(this);
849
+
850
+
851
+
852
+
853
+ /**
854
+ * This is the 'end' of the constructor so if the first argument
855
+ * contains configuration data - handle that.
856
+ */
857
+ if (parseConfObjectForOptions) {
858
+ RG.parseObjectStyleConfig(this, conf.options);
859
+ }
860
+ };