initial commit
[home-automation.git] / libraries / RGraph.meter.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 bar chart constructor
19     * 
20     * @param string canvas The canvas ID
21     * @param min    integer The minimum value
22     * @param max    integer The maximum value
23     * @param value  integer The indicated value
24     */
25     RGraph.Meter = function (id, min, max, value)
26     {
27         // Get the canvas and context objects
28         this.id                = id;
29         this.canvas            = document.getElementById(id);
30         this.context           = this.canvas.getContext ? this.canvas.getContext("2d") : null;
31         this.canvas.__object__ = this;
32         this.type              = 'meter';
33         this.min               = min;
34         this.max               = max;
35         this.value             = value;
36         this.centerx           = null;
37         this.centery           = null;
38         this.radius            = null;
39         this.isRGraph          = true;
40
41
42         /**
43         * Compatibility with older browsers
44         */
45         RGraph.OldBrowserCompat(this.context);
46
47
48         // Various config type stuff
49         this.properties = {
50             'chart.gutter':                 25,
51             'chart.linewidth':              2,
52             'chart.border.color':           'black',
53             'chart.text.font':              'Verdana',
54             'chart.text.size':              10,
55             'chart.text.color':             'black',
56             'chart.title':                  '',
57             'chart.title.background':       null,
58             'chart.title.hpos':             null,
59             'chart.title.vpos':             null,
60             'chart.title.color':            'black',
61             'chart.green.start':            ((this.max - this.min) * 0.35) + this.min,
62             'chart.green.end':              this.max,
63             'chart.green.color':            '#207A20',
64             'chart.yellow.start':           ((this.max - this.min) * 0.1) + this.min,
65             'chart.yellow.end':             ((this.max - this.min) * 0.35) + this.min,
66             'chart.yellow.color':           '#D0AC41',
67             'chart.red.start':              this.min,
68             'chart.red.end':                ((this.max - this.min) * 0.1) + this.min,
69             'chart.red.color':              '#9E1E1E',
70             'chart.units.pre':              '',
71             'chart.units.post':             '',
72             'chart.contextmenu':            null,
73             'chart.zoom.factor':            1.5,
74             'chart.zoom.fade.in':           true,
75             'chart.zoom.fade.out':          true,
76             'chart.zoom.hdir':              'right',
77             'chart.zoom.vdir':              'down',
78             'chart.zoom.frames':            15,
79             'chart.zoom.delay':             33,
80             'chart.zoom.shadow':            true,
81             'chart.zoom.mode':              'canvas',
82             'chart.zoom.thumbnail.width':   75,
83             'chart.zoom.thumbnail.height':  75,
84             'chart.zoom.background':        true,
85             'chart.zoom.action':            'zoom',
86             'chart.annotatable':            false,
87             'chart.annotate.color':         'black',
88             'chart.shadow':                 false,
89             'chart.shadow.color':           'rgba(0,0,0,0.5)',
90             'chart.shadow.blur':            3,
91             'chart.shadow.offsetx':         3,
92             'chart.shadow.offsety':         3,
93             'chart.reszable':               false
94         }
95
96
97         // Check for support
98         if (!this.canvas) {
99             alert('[METER] No canvas support');
100             return;
101         }
102         
103         // Check the canvasText library has been included
104         if (typeof(RGraph) == 'undefined') {
105             alert('[METER] Fatal error: The common library does not appear to have been included');
106         }
107         
108         /**
109         * Constrain the value to be within the min and max
110         */
111         if (this.value > this.max) this.value = this.max;
112         if (this.value < this.min) this.value = this.min;
113     }
114
115
116     /**
117     * A setter
118     * 
119     * @param name  string The name of the property to set
120     * @param value mixed  The value of the property
121     */
122     RGraph.Meter.prototype.Set = function (name, value)
123     {
124         this.properties[name.toLowerCase()] = value;
125     }
126
127
128     /**
129     * A getter
130     * 
131     * @param name  string The name of the property to get
132     */
133     RGraph.Meter.prototype.Get = function (name)
134     {
135         return this.properties[name];
136     }
137
138
139     /**
140     * The function you call to draw the bar chart
141     */
142     RGraph.Meter.prototype.Draw = function ()
143     {
144         /**
145         * Fire the onbeforedraw event
146         */
147         RGraph.FireCustomEvent(this, 'onbeforedraw');
148
149
150         // Cache the gutter as a object variable because it's used a lot
151         this.gutter  = this.Get('chart.gutter');
152
153         this.centerx = this.canvas.width / 2;
154         this.centery = this.canvas.height - this.gutter;
155         this.radius  = Math.min(this.canvas.width - (2 * this.gutter), this.canvas.height - (2 * this.gutter));
156
157         this.DrawBackground();
158         this.DrawNeedle();
159         this.DrawLabels();
160         
161         /**
162         * Draw the title
163         */
164         RGraph.DrawTitle(this.canvas, this.Get('chart.title'), this.gutter);
165
166         /**
167         * Setup the context menu if required
168         */
169         if (this.Get('chart.contextmenu')) {
170             RGraph.ShowContext(this);
171         }
172         
173         /**
174         * If the canvas is annotatable, do install the event handlers
175         */
176         if (this.Get('chart.annotatable')) {
177             RGraph.Annotate(this);
178         }
179         
180         /**
181         * This bit shows the mini zoom window if requested
182         */
183         if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') {
184             RGraph.ShowZoomWindow(this);
185         }
186
187         
188         /**
189         * This function enables resizing
190         */
191         if (this.Get('chart.resizable')) {
192             RGraph.AllowResizing(this);
193         }
194
195         
196         /**
197         * For MSIE only, to cover the spurious lower ends of the circle
198         */
199         if (document.all) {
200             // Cover the left tail
201             this.context.beginPath();
202             this.context.moveTo(this.gutter, this.canvas.height - this.gutter);
203             this.context.fillStyle = 'white';
204             this.context.fillRect(this.centerx - this.radius - 5, this.canvas.height - this.gutter + 1, 10, this.gutter);
205             this.context.fill();
206
207             // Cover the right tail
208             this.context.beginPath();
209             this.context.moveTo(this.canvas.width - this.gutter, this.canvas.height - this.gutter);
210             this.context.fillStyle = 'white';
211             this.context.fillRect(this.centerx + this.radius - 5, this.canvas.height - this.gutter + 1, 10, this.gutter);
212             this.context.fill();
213         }
214         
215         /**
216         * Fire the RGraph ondraw event
217         */
218         RGraph.FireCustomEvent(this, 'ondraw');
219     }
220
221
222     /**
223     * Draws the background of the chart
224     */
225     RGraph.Meter.prototype.DrawBackground = function ()
226     {
227         // Draw the shadow
228         if (this.Get('chart.shadow')) {
229             this.context.beginPath();
230                 this.context.fillStyle = 'white';
231                 this.context.shadowColor   = this.Get('chart.shadow.color');
232                 this.context.shadowBlur    = this.Get('chart.shadow.blur');
233                 this.context.shadowOffsetX = this.Get('chart.shadow.offsetx');
234                 this.context.shadowOffsetY = this.Get('chart.shadow.offsety');
235                 
236                 this.context.arc(this.centerx, this.centery, this.radius, 3.14, 6.28, false);
237                 //this.context.arc(this.centerx, this.centery, , 0, 6.28, false);
238             this.context.fill();
239
240
241             this.context.beginPath();
242                 var r = (this.radius * 0.06) > 40 ? 40 : (this.radius * 0.06);
243                 this.context.arc(this.centerx, this.centery, r, 0, 6.28, 0);
244             this.context.fill();
245
246             RGraph.NoShadow(this);
247         }
248
249         // First, draw the grey tickmarks
250         this.context.beginPath();
251         this.context.strokeStyle = '#bbb'
252         for (var i=0; i<3.14; i+=(0.13/3)) {
253             this.context.arc(this.centerx, this.centery, this.radius, 3.14 + i, 3.1415 + i, 0);
254             this.context.lineTo(this.centerx, this.centery);
255         }
256         this.context.stroke();
257
258
259         // First, draw the tickmarks
260         for (var i=0; i<3.14; i+=0.13) {
261             this.context.beginPath();
262             this.context.strokeStyle = this.Get('chart.border.color');
263             this.context.arc(this.centerx, this.centery, this.radius, 3.14 + i, 3.1415 + i, 0);
264             this.context.lineTo(this.centerx, this.centery)
265             this.context.stroke();
266         }
267
268         // Draw the white circle that makes the tickmarks
269         this.context.beginPath();
270         this.context.fillStyle = 'white'
271         this.context.arc(this.centerx, this.centery, this.radius - 4, 3.1415927, 6.28, false);
272         this.context.closePath();
273         this.context.fill();
274
275         // Draw the green area
276         this.context.strokeStyle = this.Get('chart.green.color');
277         this.context.fillStyle = this.Get('chart.green.color');
278         this.context.beginPath();
279         this.context.arc(this.centerx,this.centery,this.radius * 0.85,(((this.Get('chart.green.start') - this.min) / (this.max - this.min)) * 3.1415927) + 3.1415927,(((this.Get('chart.green.end') - this.min) / (this.max - this.min)) * 3.1415927) + 3.1415927,false);
280         this.context.lineTo(this.centerx, this.centery);
281         this.context.closePath();
282         this.context.stroke();
283         this.context.fill();
284         
285         // Draw the yellow area
286         this.context.strokeStyle = this.Get('chart.yellow.color');
287         this.context.fillStyle = this.Get('chart.yellow.color');
288         this.context.beginPath();        this.context.arc(this.centerx,this.centery,this.radius * 0.85,(((this.Get('chart.yellow.start') - this.min) / (this.max - this.min)) * 3.1415927) + 3.1415927,(((this.Get('chart.yellow.end') - this.min) / (this.max - this.min)) * 3.1415927) + 3.1415927,false)
289         this.context.lineTo(this.centerx, this.centery);
290         this.context.closePath();
291         this.context.stroke();
292         this.context.fill();
293         
294         // Draw the yellow area
295         this.context.strokeStyle = this.Get('chart.red.color');
296         this.context.fillStyle = this.Get('chart.red.color');
297         this.context.beginPath();
298         this.context.arc(this.centerx,this.centery,this.radius * 0.85,(((this.Get('chart.red.start') - this.min) / (this.max - this.min)) * 3.1415927) + 3.1415927,(((this.Get('chart.red.end') - this.min) / (this.max - this.min)) * 3.1415927) + 3.1415927,false);
299         this.context.lineTo(this.centerx, this.centery);
300         this.context.closePath();
301         this.context.stroke();
302         this.context.fill();
303
304         // Draw the outline
305         this.context.strokeStyle = this.Get('chart.border.color');
306         this.context.lineWidth   = this.Get('chart.linewidth');
307
308         this.context.beginPath();
309         this.context.moveTo(this.centerx, this.centery);
310         this.context.arc(this.centerx, this.centery, this.radius, 3.1415927, 6.2831854, false);
311         this.context.closePath();
312
313         this.context.stroke();
314         
315         // Reset the linewidth back to 1
316         this.context.lineWidth = 1;
317     }
318
319
320     /**
321     * Draws the pointer
322     */
323     RGraph.Meter.prototype.DrawNeedle = function ()
324     {
325         // First draw the circle at the bottom
326         this.context.fillStyle = 'black';
327         this.context.lineWidth = this.radius >= 200 ? 7 : 3;
328         this.context.lineCap = 'round';
329
330         // Now, draw the pointer
331         this.context.beginPath();
332         this.context.strokeStyle = 'black';
333         var a = (((this.value - this.min) / (this.max - this.min)) * 3.14) + 3.14;
334         this.context.arc(this.centerx, this.centery, this.radius * 0.7, a, a + 0.001, false);
335         this.context.lineTo(this.centerx, this.centery);
336         this.context.stroke();
337         
338         // Draw the triangular needle head
339         this.context.beginPath();
340             this.context.lineWidth = 1;
341             //this.context.moveTo(this.centerx, this.centery);
342             this.context.arc(this.centerx, this.centery, (this.radius * 0.7) + 15, a, a + 0.001, 0);
343             this.context.arc(this.centerx, this.centery, (this.radius * 0.7) - 15, a + 0.087, a + 0.087999, 0);
344             this.context.arc(this.centerx, this.centery, (this.radius * 0.7) - 15, a - 0.087, a - 0.087999, 1);
345         this.context.fill();
346
347         // Draw the center circle
348         var r = (this.radius * 0.06) > 40 ? 40 : (this.radius * 0.06);
349
350         this.context.beginPath();
351         this.context.arc(this.centerx, this.centery, r, 0, 6.28, 0);
352         this.context.fill();
353         
354         // Draw the centre bit of the circle
355         this.context.fillStyle = 'white';
356         this.context.beginPath();
357         this.context.arc(this.centerx, this.centery, r - 2, 0, 6.28, 0);
358         this.context.fill();
359     }
360
361
362     /**
363     * Draws the labels
364     */
365     RGraph.Meter.prototype.DrawLabels = function ()
366     {
367         var context    = this.context;
368         var radius     = this.radius;
369         var text_size  = this.Get('chart.text.size');
370         var text_font  = this.Get('chart.text.font');
371         var units_post = this.Get('chart.units.post');
372         var units_pre  = this.Get('chart.units.pre');
373         var centerx    = this.centerx;
374         var centery    = this.centery;
375         var min        = this.min;
376         var max        = this.max;
377
378         context.fillStyle = this.Get('chart.text.color');
379         context.lineWidth = 1;
380
381         context.beginPath();
382
383
384         RGraph.Text(context, text_font, text_size, centerx - radius + (0.075 * radius), centery - 10, units_pre + min + units_post, 'center', 'left', false, 270);
385         RGraph.Text(context,text_font,text_size,centerx - (Math.cos(0.62819 / 2) * (radius - (0.085 * radius)) ),centery - (Math.sin(0.682819 / 2) * (radius - (0.085 * radius)) ),units_pre + (((max - min) * (1/10)) + min) + units_post,'center','center', false, 288);
386         RGraph.Text(context,text_font,text_size,centerx - (Math.cos(0.62819) * (radius - (0.085 * radius)) ),centery - (Math.sin(0.682819) * (radius - (0.085 * radius)) ),units_pre + (((max - min) * (2/10)) + min) + units_post,'center','center', false, 306);
387         RGraph.Text(context, text_font, text_size,centerx - (Math.cos(0.95) * (radius - (0.085 * radius)) ),centery - (Math.sin(0.95) * (radius - (0.0785 * radius)) ),units_pre + (((max - min) * (3/10)) + min) + units_post,'center', 'center', false, 320);
388         RGraph.Text(context, text_font, text_size,centerx - (Math.cos(1.2566) * (radius - (0.085 * radius)) ),centery - (Math.sin(1.2566) * (radius - (0.0785 * radius)) ),units_pre + (((max - min) * (4/10)) + min) + units_post,'center', 'center', false, 342);
389         RGraph.Text(context,text_font,text_size,centerx - (Math.cos(1.57) * (radius - (0.075 * radius)) ),centery - (Math.sin(1.57) * (radius - (0.075 * radius)) ),units_pre + (((max - min) * (5/10)) + min) + units_post,'center','center', false, 0);
390         RGraph.Text(context,text_font,text_size,centerx - (Math.cos(1.88495562) * (radius - (0.075 * radius)) ),centery - (Math.sin(1.88495562) * (radius - (0.075 * radius)) ),units_pre + (((max - min)* (6/10)) + min) + units_post,'center','center', false, 18);
391         RGraph.Text(context,text_font,text_size,centerx - (Math.cos(2.1989) * (radius - (0.075 * radius)) ),centery - (Math.sin(2.1989) * (radius - (0.075 * radius)) ),units_pre + (((max - min)* (7/10)) + min) + units_post,'center','center', false, 36);
392         RGraph.Text(context,text_font,text_size,centerx - (Math.cos(2.51327416) * (radius - (0.075 * radius)) ),centery - (Math.sin(2.51327416) * (radius - (0.075 * radius)) ), units_pre + (((max - min) * (8/10)) + min) + units_post,'center','center', false, 54);
393         RGraph.Text(context,text_font,text_size,centerx - (Math.cos(2.82764832) * (radius - (0.075 * radius)) ),centery - (Math.sin(2.82764832) * (radius - (0.075 * radius)) ),units_pre + (((max - min) * (9/10)) + min) + units_post,'center','center', false, 72);
394         RGraph.Text(context, text_font, text_size,centerx + radius - (0.075 * radius),centery - 10,units_pre + (max) + units_post, 'center', 'right', false, 90);
395
396         context.fill();
397         context.stroke();
398     }