initial commit
[home-automation.git] / libraries / RGraph.odo.js
1     /**
2     * o------------------------------------------------------------------------------o
3     * | This file is part of the RGraph package - you can learn more at:             |
4     * |                                                                              |
5     * |                          http://www.rgraph.net                               |
6     * |                                                                              |
7     * | This package is licensed under the RGraph license. For all kinds of business |
8     * | purposes there is a small one-time licensing fee to pay and for non          |
9     * | commercial  purposes it is free to use. You can read the full license here:  |
10     * |                                                                              |
11     * |                      http://www.rgraph.net/LICENSE.txt                       |
12     * o------------------------------------------------------------------------------o
13     */
14     
15     if (typeof(RGraph) == 'undefined') RGraph = {};
16
17     /**
18     * The odometer constructor. Pass it the ID of the canvas tag, the start value of the odo,
19     * the end value, and the value that the pointer should point to.
20     * 
21     * @param string id    The ID of the canvas tag
22     * @param int    start The start value of the Odo
23     * @param int    end   The end value of the odo
24     * @param int    value The indicated value (what the needle points to)
25     */
26     RGraph.Odometer = function (id, start, end, value)
27     {
28         this.id                = id
29         this.canvas            = document.getElementById(id);
30         this.context           = this.canvas.getContext('2d');
31         this.canvas.__object__ = this;
32         this.type              = 'odo';
33         this.isRGraph          = true;
34         this.start             = start;
35         this.end               = end;
36         this.value             = value;
37
38
39         /**
40         * Compatibility with older browsers
41         */
42         RGraph.OldBrowserCompat(this.context);
43
44
45         this.properties = {
46             'chart.value.text':             false,
47             'chart.needle.color':           'black',
48             'chart.needle.width':           2,
49             'chart.needle.head':            true,
50             'chart.needle.tail':            true,
51             'chart.needle.type':            'pointer',
52             'chart.needle.extra':            [],
53             'chart.text.size':              10,
54             'chart.text.color':             'black',
55             'chart.text.font':              'Verdana',
56             'chart.green.max':              end * 0.75,
57             'chart.red.min':                end * 0.9,
58             'chart.green.color':            'green',
59             'chart.yellow.color':           'yellow',
60             'chart.red.color':              'red',
61             'chart.label.area':             35,
62             'chart.gutter':                 25,
63             'chart.title':                  '',
64             'chart.title.background':       null,
65             'chart.title.hpos':             null,
66             'chart.title.vpos':             null,
67             'chart.contextmenu':            null,
68             'chart.linewidth':              1,
69             'chart.shadow.inner':           false,
70             'chart.shadow.inner.color':     'black',
71             'chart.shadow.inner.offsetx':   3,
72             'chart.shadow.inner.offsety':   3,
73             'chart.shadow.inner.blur':      6,
74             'chart.shadow.outer':           false,
75             'chart.shadow.outer.color':     '#666',
76             'chart.shadow.outer.offsetx':   0,
77             'chart.shadow.outer.offsety':   0,
78             'chart.shadow.outer.blur':      15,
79             'chart.annotatable':            false,
80             'chart.annotate.color':         'black',
81             'chart.scale.decimals':         0,
82             'chart.zoom.factor':            1.5,
83             'chart.zoom.fade.in':           true,
84             'chart.zoom.fade.out':          true,
85             'chart.zoom.hdir':              'right',
86             'chart.zoom.vdir':              'down',
87             'chart.zoom.frames':            10,
88             'chart.zoom.delay':             50,
89             'chart.zoom.shadow':            true,
90             'chart.zoom.mode':              'canvas',
91             'chart.zoom.thumbnail.width':   75,
92             'chart.zoom.thumbnail.height':  75,
93             'chart.zoom.background':        true,
94             'chart.zoom.action':            'zoom',
95             'chart.resizable':              false,
96             'chart.units.pre':              '',
97             'chart.units.post':             '',
98             'chart.border':                 false,
99             'chart.tickmarks.highlighted':  false,
100             'chart.zerostart':              false,
101             'chart.labels':                 null,
102             'chart.units.pre':              '',
103             'chart.units.post':             '',
104             'chart.value.units.pre':        '',
105             'chart.value.units.post':       ''
106         }
107
108         // Check the common library has been included
109         if (typeof(RGraph) == 'undefined') {
110             alert('[ODO] Fatal error: The common library does not appear to have been included');
111         }
112     }
113
114
115     /**
116     * A peudo setter
117     * 
118     * @param name  string The name of the property to set
119     * @param value mixed  The value of the property
120     */
121     RGraph.Odometer.prototype.Set = function (name, value)
122     {
123         if (name == 'chart.needle.style') {
124             alert('[RGRAPH] The RGraph property chart.needle.style has changed to chart.needle.color');
125         }
126
127         if (name == 'chart.needle.thickness') {
128             name = 'chart.needle.width';
129         }
130
131         this.properties[name.toLowerCase()] = value;
132     }
133
134
135     /**
136     * A getter
137     * 
138     * @param name  string The name of the property to get
139     */
140     RGraph.Odometer.prototype.Get = function (name)
141     {
142         return this.properties[name.toLowerCase()];
143     }
144
145
146     /**
147     * Draws the odometer
148     */
149     RGraph.Odometer.prototype.Draw = function ()
150     {
151         /**
152         * Fire the onbeforedraw event
153         */
154         RGraph.FireCustomEvent(this, 'onbeforedraw');
155
156         // Work out a few things
157         this.radius   = Math.min(this.canvas.width / 2, this.canvas.height / 2) - this.Get('chart.gutter') - (this.Get('chart.border') ? 25 : 0);
158         this.diameter = 2 * this.radius;
159         this.centerx  = this.canvas.width / 2;
160         this.centery  = this.canvas.height / 2;
161         this.range    = this.end - this.start;
162
163         this.context.lineWidth = this.Get('chart.linewidth');
164
165         // Draw the background
166         this.DrawBackground();
167
168         // And lastly, draw the labels
169         this.DrawLabels();
170
171         // Draw the needle
172         this.DrawNeedle(this.value, this.Get('chart.needle.color'));
173         
174         /**
175         * Draw any extra needles
176         */
177         if (this.Get('chart.needle.extra').length > 0) {
178             for (var i=0; i<this.Get('chart.needle.extra').length; ++i) {
179                 var needle = this.Get('chart.needle.extra')[i];
180                 this.DrawNeedle(needle[0], needle[1]);
181             }
182         }
183         
184         
185         /**
186         * Setup the context menu if required
187         */
188         if (this.Get('chart.contextmenu')) {
189             RGraph.ShowContext(this);
190         }
191         
192         /**
193         * If the canvas is annotatable, do install the event handlers
194         */
195         if (this.Get('chart.annotatable')) {
196             RGraph.Annotate(this);
197         }
198         
199         /**
200         * This bit shows the mini zoom window if requested
201         */
202         if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') {
203             RGraph.ShowZoomWindow(this);
204         }
205
206         
207         /**
208         * This function enables resizing
209         */
210         if (this.Get('chart.resizable')) {
211             RGraph.AllowResizing(this);
212         }
213         
214         /**
215         * Fire the RGraph ondraw event
216         */
217         RGraph.FireCustomEvent(this, 'ondraw');
218     }
219
220     /**
221     * Draws the background
222     */
223     RGraph.Odometer.prototype.DrawBackground = function ()
224     {
225         this.context.beginPath();
226
227         /**
228         * Turn on the shadow if need be
229         */
230         if (this.Get('chart.shadow.outer')) {
231             RGraph.SetShadow(this, this.Get('chart.shadow.outer.color'), this.Get('chart.shadow.outer.offsetx'), this.Get('chart.shadow.outer.offsety'), this.Get('chart.shadow.outer.blur'));
232         }
233
234         var backgroundColor = '#eee';
235
236         // Draw the grey border
237         this.context.fillStyle = backgroundColor;
238         this.context.arc(this.centerx, this.centery, this.radius, 0.0001, 6.28, false);
239         this.context.fill();
240
241         /**
242         * Turn off the shadow
243         */
244         RGraph.NoShadow(this);
245
246
247         // Draw a circle
248         this.context.strokeStyle = '#666';
249         this.context.arc(this.centerx, this.centery, this.radius, 0, 6.28, false);
250
251         // Now draw a big white circle to make the lines appear as tick marks
252         // This is solely for Chrome
253         this.context.fillStyle = backgroundColor;
254         this.context.arc(this.centerx, this.centery, this.radius, 0, 6.28, false);
255         this.context.fill();
256
257         /**
258         * Draw more tickmarks
259         */
260         this.context.beginPath();
261         this.context.strokeStyle = '#bbb';
262         
263         for (var i=0; i<=360; i+=3) {
264             this.context.arc(this.centerx, this.centery, this.radius, 0, RGraph.degrees2Radians(i), false);
265             this.context.lineTo(this.centerx, this.centery);
266         }
267         this.context.stroke();
268
269         this.context.beginPath();
270         this.context.lineWidth = 1;
271         this.context.strokeStyle = 'black';
272
273         // Now draw a big white circle to make the lines appear as tick marks
274         this.context.fillStyle = backgroundColor;
275         this.context.strokeStyle = backgroundColor;
276         this.context.arc(this.centerx, this.centery, this.radius - 5, 0, 6.28, false);
277         this.context.fill();
278         this.context.stroke();
279
280         // Gray lines at 18 degree intervals
281         this.context.beginPath();
282         this.context.strokeStyle = '#ddd';
283         for (var i=0; i<360; i+=18) {
284             this.context.arc(this.centerx, this.centery, this.radius, 0, RGraph.degrees2Radians(i), false);
285             this.context.lineTo(this.centerx, this.centery);
286         }
287         this.context.stroke();
288         
289         // Redraw the outer circle
290         this.context.beginPath();
291         this.context.strokeStyle = 'black';
292         this.context.arc(this.centerx, this.centery, this.radius, 0, 6.2830, false);
293         this.context.stroke();
294
295         /**
296         * Now draw the center bits shadow if need be
297         */
298         if (this.Get('chart.shadow.inner')) {
299             this.context.beginPath();
300             RGraph.SetShadow(this, this.Get('chart.shadow.inner.color'), this.Get('chart.shadow.inner.offsetx'), this.Get('chart.shadow.inner.offsety'), this.Get('chart.shadow.inner.blur'));
301             this.context.arc(this.centerx, this.centery, this.radius - this.Get('chart.label.area'), 0, 6.28, 0);
302             this.context.fill();
303             this.context.stroke();
304     
305             /**
306             * Turn off the shadow
307             */
308             RGraph.NoShadow(this);
309         }
310
311         // Now draw the green area
312         var greengrad = this.canvas.getContext('2d').createRadialGradient(this.canvas.width / 2, this.canvas.height / 2, 0, this.canvas.width / 2, this.canvas.height / 2, this.canvas.width / 2, this.canvas.width / 2);
313         greengrad.addColorStop(0, 'white');
314         greengrad.addColorStop(1, this.Get('chart.green.color'));
315
316         // Draw the "tick highlight"
317         if (this.Get('chart.tickmarks.highlighted')) {
318             this.context.beginPath();
319             this.context.lineWidth = 5;
320             this.context.strokeStyle = greengrad;
321             this.context.arc(this.centerx, this.centery, this.radius - 2.5,
322             
323                 -1.57,
324                 ((this.Get('chart.green.max') / this.end) * 6.2830) - 1.57,
325                 0);
326
327             this.context.stroke();
328             
329             this.context.lineWidth = 1;
330         }
331
332         this.context.beginPath();
333             this.context.fillStyle = greengrad;
334             this.context.arc(
335                              this.centerx,
336                              this.centery,
337                              this.radius - this.Get('chart.label.area'),
338                              -1.57,
339                              ( (this.Get('chart.green.max') / this.end) * 6.2830) - 1.57,
340                              false
341                             );
342             this.context.lineTo(this.centerx, this.centery);
343         this.context.closePath();
344         this.context.fill();
345
346
347         // Now draw the yellow area
348         var yellowgrad = this.canvas.getContext('2d').createRadialGradient(this.canvas.width / 2, this.canvas.height / 2, 0, this.canvas.width / 2, this.canvas.height / 2, this.canvas.width / 2, this.canvas.width / 2);
349         yellowgrad.addColorStop(0, 'white');
350         yellowgrad.addColorStop(1, this.Get('chart.yellow.color'));
351
352         // Draw the "tick highlight"
353         if (this.Get('chart.tickmarks.highlighted')) {
354             this.context.beginPath();
355             this.context.lineWidth = 5;
356             this.context.strokeStyle = yellowgrad;
357             this.context.arc(this.centerx, this.centery, this.radius - 2.5, (
358             
359                 (this.Get('chart.green.max') / this.end) * 6.2830) - 1.57,
360                 ((this.Get('chart.red.min') / this.end) * 6.2830) - 1.57,
361                 0);
362
363             this.context.stroke();
364             
365             this.context.lineWidth = 1;
366         }
367
368         this.context.beginPath();
369             this.context.fillStyle = yellowgrad;
370             this.context.arc(
371                              this.centerx,
372                              this.centery,
373                              this.radius - this.Get('chart.label.area'),
374                              ( (this.Get('chart.green.max') / this.end) * 6.2830) - 1.57,
375                              ( (this.Get('chart.red.min') / this.end) * 6.2830) - 1.57,
376                              false
377                             );
378             this.context.lineTo(this.centerx, this.centery);
379         this.context.closePath();
380         this.context.fill();
381
382         
383         // Now draw the red area if they're defined
384         var redgrad = this.canvas.getContext('2d').createRadialGradient(this.canvas.width / 2, this.canvas.height / 2, 0, this.canvas.width / 2, this.canvas.height / 2, this.canvas.width / 2, this.canvas.width / 2);
385         redgrad.addColorStop(0, 'white');
386         redgrad.addColorStop(1, this.Get('chart.red.color'));
387
388
389         // Draw the "tick highlight"
390         if (this.Get('chart.tickmarks.highlighted')) {
391             this.context.beginPath();
392             this.context.lineWidth = 5;
393             this.context.strokeStyle = redgrad;
394             this.context.arc(this.centerx, this.centery, this.radius - 2.5, ( (this.Get('chart.red.min') / this.end) * 6.2830) - 1.57,(2 * Math.PI) - (0.5 * Math.PI),0);
395             this.context.stroke();
396             
397             this.context.lineWidth = 1;
398         }
399
400         this.context.beginPath();
401             this.context.fillStyle = redgrad;
402             this.context.strokeStyle = redgrad;
403             this.context.arc(
404                              this.centerx,
405                              this.centery,
406                              this.radius - this.Get('chart.label.area'),
407                              ( (this.Get('chart.red.min') / this.end) * 6.2830) - 1.57,
408                              6.2830 - (0.25 * 6.2830),
409                              false
410                             );
411             this.context.lineTo(this.centerx, this.centery);
412         this.context.closePath();
413         this.context.fill();
414
415
416         /**
417         * Draw the thick border
418         */
419         if (this.Get('chart.border')) {
420             var grad = this.context.createRadialGradient(this.centerx, this.centery, this.radius, this.centerx, this.centery, this.radius + 15);
421             grad.addColorStop(1, '#BEBCB0');
422             grad.addColorStop(0.5, '#F0EFEA');
423             grad.addColorStop(0, '#BEBCB0');
424             
425             this.context.beginPath();
426                 this.context.fillStyle = grad;
427                 this.context.strokeStyle = grad;
428                 this.context.lineWidth = 22;
429                 this.context.arc(this.centerx, this.centery, this.radius + 9, 0, 2 * Math.PI, 0);
430             this.context.stroke();
431         }
432         
433         // Put the linewidth back to what it was
434         this.context.lineWidth = this.Get('chart.linewidth');
435
436
437         /**
438         * Draw the title if specified
439         */
440         if (this.Get('chart.title')) {
441             RGraph.DrawTitle(this.canvas, this.Get('chart.title'), this.Get('chart.gutter'), null, this.Get('chart.text.size') + 2);
442         }
443
444
445         // Draw the big tick marks
446         for (var i=18; i<=360; i+=36) {
447         this.context.beginPath();
448             this.context.strokeStyle = '#999';
449             this.context.lineWidth = 2;
450             this.context.arc(this.centerx, this.centery, this.radius - 1, RGraph.degrees2Radians(i), RGraph.degrees2Radians(i+0.01), false);
451             this.context.arc(this.centerx, this.centery, this.radius - 7, RGraph.degrees2Radians(i), RGraph.degrees2Radians(i+0.01), false);
452             this.context.stroke();
453         }
454
455     }
456
457
458     /**
459     * Draws the needle of the odometer
460     */
461     RGraph.Odometer.prototype.DrawNeedle = function (value, color)
462     {
463         // ===== First draw a grey background circle =====
464         
465         this.context.fillStyle = '#999';
466
467         this.context.beginPath();
468             this.context.moveTo(this.centerx, this.centery);
469             this.context.arc(this.centerx, this.centery, 10, 0, 6.28, false);
470             this.context.fill();
471         this.context.closePath();
472
473         this.context.fill();
474
475         // ===============================================
476         
477         this.context.fillStyle = color
478         this.context.strokeStyle = '#666';
479
480         // Draw the centre bit
481         this.context.beginPath();
482             this.context.moveTo(this.centerx, this.centery);
483             this.context.arc(this.centerx, this.centery, 8, 0, 6.28, false);
484             this.context.fill();
485         this.context.closePath();
486         
487         this.context.stroke();
488         this.context.fill();
489
490         if (this.Get('chart.needle.type') == 'pointer') {
491
492             this.context.strokeStyle = color;
493             this.context.lineWidth   = this.Get('chart.needle.width');
494             this.context.lineCap     = 'round';
495             this.context.lineJoin    = 'round';
496             
497             // Draw the needle
498             this.context.beginPath();
499                 // The trailing bit on the opposite side of the dial
500                 this.context.beginPath();
501                     this.context.moveTo(this.centerx, this.centery);
502                     
503                     if (this.Get('chart.needle.tail')) {
504                         this.context.arc(this.centerx,
505                                          this.centery,
506                                          20,
507                                           (((value / this.range) * 360) + 90) / 57.3,
508                                          (((value / this.range) * 360) + 90 + 0.01) / 57.3, // The 0.01 avoids a bug in ExCanvas and Chrome 6
509                                          false
510                                         );
511                     }
512     
513                 // Draw the long bit on the opposite side
514                 this.context.arc(this.centerx,
515                                  this.centery,
516                                  this.radius - this.Get('chart.label.area') - 10,
517                                  (((value / this.range) * 360) - 90) / 57.3,
518                                  (((value / this.range) * 360) - 90 + 0.1 ) / 57.3, // The 0.1 avoids a bug in ExCanvas and Chrome 6
519                                  false
520                                 );
521             this.context.closePath();
522             
523             //this.context.stroke();
524             //this.context.fill();
525         
526
527         } else if (this.Get('chart.needle.type') == 'triangle') {
528
529             this.context.lineWidth = 0.01;
530             this.context.lineEnd  = 'square';
531             this.context.lineJoin = 'miter';
532
533             this.context.beginPath();
534                 this.context.strokeStyle = 'black';
535                 this.context.fillStyle = color;
536                 this.context.arc(this.centerx, this.centery, 7, (((value / this.range) * 360)) / 57.3, ((((value / this.range) * 360)) + 0.01) / 57.3, 0);
537                 this.context.arc(this.centerx, this.centery, 7, (((value / this.range) * 360) + 180) / 57.3, ((((value / this.range) * 360) + 180) + 0.01)/ 57.3, 0);
538                 this.context.arc(this.centerx, this.centery, this.radius - this.Get('chart.label.area') - 10, (((value / this.range) * 360) - 90) / 57.3, ((((value / this.range) * 360) - 90) / 57.3) + 0.01, 0);
539             this.context.closePath();
540             this.context.stroke();
541             this.context.fill();
542
543             /**
544             * This is here to accomodate the MSIE/ExCanvas combo
545             */
546             this.context.beginPath();
547                 this.context.arc(this.centerx, this.centery, 7, 0, 6.28, 0);
548             this.context.closePath();
549             this.context.fill();
550         }
551
552
553         this.context.stroke();
554         this.context.fill();
555             
556         // Draw the mini center circle
557         this.context.beginPath();
558         this.context.fillStyle = color;
559             this.context.arc(this.centerx, this.centery, this.Get('chart.needle.type') == 'pointer' ? 7 : 12, 0.01, 6.2830, false);
560         this.context.fill();
561
562         // This draws the arrow at the end of the line
563         if (this.Get('chart.needle.head') && this.Get('chart.needle.type') == 'pointer') {
564             this.context.lineWidth = 1;
565             this.context.fillStyle = color;
566
567             // round, bevel, miter
568             this.context.lineJoin = 'miter';
569             this.context.lineCap  = 'butt';
570
571             this.context.beginPath();
572                 this.context.arc(this.centerx, this.centery, this.radius - this.Get('chart.label.area')-5, (((value / this.range) * 360) - 90) / 57.3, (((value / this.range) * 360) - 90 + 0.1) / 57.3, false);
573                 this.context.arc(this.centerx, this.centery, this.radius - this.Get('chart.label.area') - 20, RGraph.degrees2Radians( ((value / this.range) * 360) - 85), RGraph.degrees2Radians( ((value / this.range) * 360) - 95), 1);
574             this.context.closePath();
575     
576             this.context.fill();
577             //this.context.stroke();
578         }
579         
580         /**
581         * Draw a white circle at the centre
582         */
583         this.context.beginPath();
584         this.context.fillStyle = 'gray';
585             this.context.moveTo(this.centerx, this.centery);
586             this.context.arc(this.centerx,this.centery,2,0,6.2795,false);
587         this.context.closePath();
588
589         this.context.fill();
590     }
591     
592     /**
593     * Draws the labels for the Odo
594     */
595     RGraph.Odometer.prototype.DrawLabels = function ()
596     {
597         var context   = this.context;
598         var size      = this.Get('chart.text.size');
599         var font      = this.Get('chart.text.font');
600         var centerx   = this.centerx;
601         var centery   = this.centery;
602         var r         = this.radius - (this.Get('chart.label.area') / 2);
603         var end       = this.end;
604         var decimals  = this.Get('chart.scale.decimals');
605         var labels    = this.Get('chart.labels');
606         var units_pre = this.Get('chart.units.pre');
607         var units_post = this.Get('chart.units.post');
608
609         context.beginPath();
610         context.fillStyle = this.Get('chart.text.color');
611
612         /**
613         * If label are specified, use those
614         */
615         if (labels) {
616             for (var i=0; i<labels.length; ++i) {
617
618                 RGraph.Text(context,
619                             font,
620                             size,
621                             centerx + (Math.cos(((i / labels.length) * 6.28) - 1.57) * (this.radius - (this.Get('chart.label.area') / 2) ) ), // Sin A = Opp / Hyp
622                             centery + (Math.sin(((i / labels.length) * 6.28) - 1.57) * (this.radius - (this.Get('chart.label.area') / 2) ) ), // Cos A = Adj / Hyp
623                             String(units_pre + labels[i] + units_post),
624                             'center',
625                             'center');
626             }
627
628         /**
629         * If not, use the maximum value
630         */
631         } else {
632             RGraph.Text(context, font, size, centerx + (0.588 * r ), centery - (0.809 * r ), String(units_pre + (end * (1/10)).toFixed(decimals) + units_post), 'center', 'center', false, 36);
633             RGraph.Text(context, font, size, centerx + (0.951 * r ), centery - (0.309 * r), String(units_pre + (end * (2/10)).toFixed(decimals) + units_post), 'center', 'center', false, 72);
634             RGraph.Text(context, font, size, centerx + (0.949 * r), centery + (0.287 * r), String(units_pre + (end * (3/10)).toFixed(decimals) + units_post), 'center', 'center', false, 108);
635             RGraph.Text(context, font, size, centerx + (0.588 * r ), centery + (0.809 * r ), String(units_pre + (end * (4/10)).toFixed(decimals) + units_post), 'center', 'center', false, 144);
636             RGraph.Text(context, font, size, centerx, centery + r, String(units_pre + (end * (5/10)).toFixed(decimals) + units_post), 'center', 'center', false, 180);
637             RGraph.Text(context, font, size, centerx - (0.588 * r ), centery + (0.809 * r ), String(units_pre + (end * (6/10)).toFixed(decimals) + units_post), 'center', 'center', false, 216);
638             RGraph.Text(context, font, size, centerx - (0.949 * r), centery + (0.300 * r), a = String(units_pre + (end * (7/10)).toFixed(decimals) + units_post), 'center', 'center', false, 252);
639             RGraph.Text(context, font, size, centerx - (0.951 * r), centery - (0.309 * r), String(units_pre + (end * (8/10)).toFixed(decimals) + units_post), 'center', 'center', false, 288);
640             RGraph.Text(context, font, size, centerx - (0.588 * r ), centery - (0.809 * r ), String(units_pre + (end * (9/10)).toFixed(decimals) + units_post), 'center', 'center', false, 324);
641             RGraph.Text(context, font, size, centerx, centery - r, this.Get('chart.zerostart') ? units_pre + '0' : String(units_pre + (end * (10/10)).toFixed(decimals) + units_post), 'center', 'center', false, 360);
642         }
643         
644         this.context.fill();
645         
646         /**
647         * Draw the text label below the center point
648         */
649         if (this.Get('chart.value.text')) {
650             context.strokeStyle = 'black';
651             RGraph.Text(context, font, size + 2, centerx, centery + size + 2 + 10, String(this.Get('chart.value.units.pre') + this.value + this.Get('chart.value.units.post')), 'center', 'center', true,  null, 'white');
652         }
653     }