4 * Copyright 2016 RIFT.IO Inc
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
22 * HTML5 Canvas Gauge implementation
24 * This code is subject to MIT license.
26 * Copyright (c) 2012 Mykhailo Stadnyk <mikhus@gmail.com>
28 * Permission is hereby granted, free of charge, to any person obtaining a copy of
29 * this software and associated documentation files (the "Software"), to deal in
30 * the Software without restriction, including without limitation the rights to use,
31 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
32 * Software, and to permit persons to whom the Software is furnished to do so,
33 * subject to the following conditions:
35 * The above copyright notice and this permission notice shall be included in all
36 * copies or substantial portions of the Software.
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
40 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
41 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
42 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
43 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45 * @authors: Mykhailo Stadnyk <mikhus@gmail.com>
46 * Chris Poile <poile@edwards.usask.ca>
47 * Luca Invernizzi <http://www.lucainvernizzi.net>
48 * Robert Blackburn <http://www.rwblackburn.com>
52 * @param {Object} config
55 var Gauge = function (config
) {
56 Gauge
.Collection
.push(this);
59 * Default gauge configuration
74 valueFormat
: { "int": 3, "dec": 2 },
75 majorTicksFormat
: { "int": 1, "dec": 0 },
89 needle
: { start
: 'rgba(240, 128, 128, 1)', end
: 'rgba(255, 160, 122, .9)' }
119 * Sets a new value to gauge and updates the gauge view
121 * @param {number} val - the new value to set to the gauge
122 * @return {Gauge} this - returns self
124 this.setValue = function (val
) {
126 fromValue
= config
.animation
? value
: val
;
128 var dv
= (config
.maxValue
- config
.minValue
) / 100;
130 toValue
= val
> config
.maxValue
?
131 config
.maxValue
+ dv
:
132 val
< config
.minValue
?
133 config
.minValue
- dv
:
139 if (toValue
>= fromValue
) {
142 config
.arrow
= 'down';
145 config
.animation
? animate() : this.draw();
151 * Sets a new value to gauge and updates the gauge view without
152 * any animation (even if configured)
154 * @param {number} val - the new value to set to the gauge
155 * @return {Gauge} this - returns self
157 this.setRawValue = function (val
) {
158 fromValue
= value
= val
;
164 * Clears the value of the gauge
167 this.clear = function () {
168 value
= fromValue
= toValue
= this.config
.minValue
;
175 * Returns the current value been set to the gauge
177 * @return {number} value - current gauge's value
179 this.getValue = function () {
184 * Ready event for the gauge. Use it whenever you
185 * initialize the gauge to be assured it was fully drawn
186 * before you start the update on it
188 * @event {Function} onready
190 this.onready = function () {
193 function applyRecursive(dst
, src
) {
195 // modification by Chris Poile, Oct 08, 2012. More correct check of an Array instance
196 if (typeof src
[i
] == "object" && !(Object
.prototype.toString
.call(src
[i
]) === '[object Array]') && i
!= 'renderTo') {
197 if (typeof dst
[i
] != "object") {
201 applyRecursive(dst
[i
], src
[i
]);
208 applyRecursive(this.config
, config
);
210 this.config
.minValue
= parseFloat(this.config
.minValue
);
211 this.config
.maxValue
= parseFloat(this.config
.maxValue
);
213 config
= this.config
;
214 fromValue
= value
= config
.minValue
;
216 if (!config
.renderTo
) {
217 throw Error("Canvas element was not specified when creating the Gauge object!");
221 canvas
= config
.renderTo
.tagName
? config
.renderTo
: document
.getElementById(config
.renderTo
),
222 ctx
= canvas
.getContext('2d'),
223 cache
, CW
, CH
, CX
, CY
, max
, cctx
226 function baseInit() {
227 canvas
.width
= config
.width
;
228 canvas
.height
= config
.height
;
230 cache
= canvas
.cloneNode(true);
231 cctx
= cache
.getContext('2d');
236 max
= CX
< CY
? CX
: CY
;
240 // translate cache to have 0, 0 in center
241 cctx
.translate(CX
, CY
);
244 // translate canvas to have 0,0 in center
245 ctx
.translate(CX
, CY
);
249 // do basic initialization
253 * Updates the gauge config
255 * @param {Object} config
258 this.updateConfig = function (config
) {
259 applyRecursive(this.config
, config
);
266 linear: function (p
) {
270 return Math
.pow(p
, 2);
272 quint: function (p
) {
273 return Math
.pow(p
, 5);
275 cycle: function (p
) {
276 return 1 - Math
.sin(Math
.acos(p
));
278 bounce: function (p
) {
279 return 1 - (function (p
) {
280 for (var a
= 0, b
= 1; 1; a
+= b
, b
/= 2) {
281 if (p
>= (7 - 4 * a
) / 11) {
282 return -Math
.pow((11 - 6 * a
- 11 * p
) / 4, 2) + Math
.pow(b
, 2);
287 elastic: function (p
) {
288 return 1 - (function (p
) {
290 return Math
.pow(2, 10 * (p
- 1)) * Math
.cos(20 * Math
.PI
* x
/ 3 * p
);
295 var animateInterval
= null;
297 function _animate(opts
) {
298 var start
= new Date
;
300 animateInterval
= setInterval(function () {
302 timePassed
= new Date
- start
,
303 progress
= timePassed
/ opts
.duration
310 var animateFn
= typeof opts
.delta
== "function" ?
312 animateFx
[opts
.delta
]
315 var delta
= animateFn(progress
);
319 clearInterval(animateInterval
);
321 }, opts
.delay
|| 10);
325 animateInterval
&& clearInterval(animateInterval
); // stop previous animation
327 path
= (toValue
- fromValue
),
329 cfg
= config
.animation
334 duration
: cfg
.duration
,
336 step: function (delta
) {
337 fromValue
= parseFloat(from) + path
* delta
;
344 ctx
.lineCap
= "round";
347 * Drows the gauge. Normally this function should be used to
348 * initally draw the gauge
350 * @return {Gauge} this - returns the self Gauge object
352 this.draw = function () {
355 cctx
.clearRect(-CX
, -CY
, CW
, CH
);
358 var tmp
= {ctx
: ctx
};
375 ctx
.clearRect(-CX
, -CY
, CW
, CH
);
378 ctx
.drawImage(cache
, -CX
, -CY
, CW
, CH
);
380 if (!Gauge
.initialized
) {
381 var iv
= setInterval(function () {
382 if (!Gauge
.initialized
) {
393 self
.onready
&& self
.onready();
403 self
.onready
&& self
.onready();
412 * Transforms degrees to radians
414 function radians(degrees
) {
415 return degrees
* Math
.PI
/ 180;
421 function lgrad(clrFrom
, clrTo
, len
) {
422 var grad
= ctx
.createLinearGradient(0, 0, 0, len
);
423 grad
.addColorStop(0, clrFrom
);
424 grad
.addColorStop(1, clrTo
);
429 function drawPlate() {
443 ctx
.shadowColor
= 'rgba(0, 0, 0, 0.5)';
447 ctx
.arc(0, 0, r0
, 0, Math
.PI
* 2, true);
448 // ctx.fillStyle = lgrad( '#ddd', '#aaa', r0);
449 ctx
.fillStyle
= lgrad('hsla(0, 0%, 17%, 1)', 'hsla(0, 0%, 0%, 1)', r0
);
455 ctx
.arc(0, 0, r1
, 0, Math
.PI
* 2, true);
456 // ctx.fillStyle = lgrad( '#fafafa', '#ccc', r1);
457 ctx
.fillStyle
= lgrad('hsla(0, 0%, 47%, 1)', 'hsla(0, 0%, 33%, 1)', r1
);
461 ctx
.arc(0, 0, r2
, 0, Math
.PI
* 2, true);
462 // ctx.fillStyle = lgrad( '#eee', '#f0f0f0', r2);
463 ctx
.fillStyle
= lgrad('hsla(0, 0%, 33%, 1)', 'hsla(0, 0%, 43%, 1)', r2
);
467 ctx
.arc(0, 0, r3
, 0, Math
.PI
* 2, true);
468 ctx
.fillStyle
= config
.colors
.plate
;
475 * Formats a number for display on the dial's plate using the majorTicksFormat config option.
477 * @param {number} num The number to format
478 * @returns {string} The formatted number
480 function formatMajorTickNumber(num
) {
481 var r
, isDec
= false;
483 // First, force the correct number of digits right of the decimal.
484 if (config
.majorTicksFormat
.dec
=== 0) {
485 r
= Math
.round(num
).toString();
487 r
= num
.toFixed(config
.majorTicksFormat
.dec
);
490 // Second, force the correct number of digits left of the decimal.
491 if (config
.majorTicksFormat
["int"] > 1) {
492 // Does this number have a decimal?
493 isDec
= (r
.indexOf('.') > -1);
495 // Is this number a negative number?
496 if (r
.indexOf('-') > -1) {
498 config
.majorTicksFormat
["int"] + config
.majorTicksFormat
.dec
+ 2 + (isDec
? 1 : 0) - r
.length
499 ].join('0') + r
.replace('-', '');
502 config
.majorTicksFormat
["int"] + config
.majorTicksFormat
.dec
+ 1 + (isDec
? 1 : 0) - r
.length
511 function drawMajorTicks() {
512 var r
= max
/ 100 * 81;
515 ctx
.strokeStyle
= config
.colors
.majorTicks
;
518 if (config
.majorTicks
.length
=== 0) {
519 var numberOfDefaultTicks
= 5;
520 var tickSize
= (config
.maxValue
- config
.minValue
) / numberOfDefaultTicks
;
522 for (var i
= 0; i
< numberOfDefaultTicks
; i
++) {
523 config
.majorTicks
.push(formatMajorTickNumber(config
.minValue
+ (tickSize
* i
)));
525 config
.majorTicks
.push(formatMajorTickNumber(config
.maxValue
));
528 for (var i
= 0; i
< config
.majorTicks
.length
; ++i
) {
529 var a
= 45 + i
* (270 / (config
.majorTicks
.length
- 1));
530 ctx
.rotate(radians(a
));
534 ctx
.lineTo(0, r
- max
/ 100 * 15);
541 if (config
.strokeTicks
) {
542 ctx
.rotate(radians(90));
545 ctx
.arc(0, 0, r
, radians(45), radians(315), false);
554 function drawMinorTicks() {
555 var r
= max
/ 100 * 81;
558 ctx
.strokeStyle
= config
.colors
.minorTicks
;
562 var len
= config
.minorTicks
* (config
.majorTicks
.length
- 1);
564 for (var i
= 0; i
< len
; ++i
) {
565 var a
= 45 + i
* (270 / len
);
566 ctx
.rotate(radians(a
));
570 ctx
.lineTo(0, r
- max
/ 100 * 7.5);
579 function drawNumbers() {
580 //var r = max / 100 * 55;
582 //for (var i = 0; i < config.majorTicks.length; ++i) {
584 // a = 45 + i * (270 / (config.majorTicks.length - 1)),
585 // p = rpoint(r, radians(a))
588 // ctx.font = 20 * (max / 200) + "px Arial";
589 // ctx.fillStyle = config.colors.numbers;
590 // ctx.lineWidth = 0;
591 // ctx.textAlign = "center";
592 // ctx.fillText(config.majorTicks[i], p.x, p.y + 3);
597 function drawTitle() {
603 ctx
.font
= 24 * (max
/ 200) + "px Arial";
604 ctx
.fillStyle
= config
.colors
.title
;
605 ctx
.textAlign
= "center";
606 ctx
.fillText(config
.title
, 0, -max
/ 4.25);
611 function drawUnits() {
617 ctx
.font
= 22 * (max
/ 200) + "px Arial";
618 ctx
.fillStyle
= config
.colors
.units
;
619 ctx
.textAlign
= "center";
620 ctx
.fillText(config
.units
, 0, max
/ 3.25);
625 function drawArrow() {
627 if (config
.arrow
!= "false") {
629 if (config
.arrow
== "up") {
630 var r
= max
/ 100 * 2.0;
636 arrow_color
= "rgba(107, 184, 20, 1)";
638 var x0
= max
/ 100 * -8
639 var x1
= max
/ 100 * -6
640 var x2
= max
/ 100 * -1.5
641 var x3
= max
/ 100 * 0
642 var x4
= max
/ 100 * 1.5
643 var x5
= max
/ 100 * 6
644 var x6
= max
/ 100 * 8
648 ctx
.lineTo(x3
- r
, y4
+ r
);
649 ctx
.arcTo(x3
, y4
- r
, x3
+ r
, y4
+ r
, r
* 1.09);
651 ctx
.arcTo(x6
+ r
/2.0, y2 + r/1.0, x5
, y1
, r
*.9)
654 ctx
.arcTo(x3
, y0
+ r
, x2
, y0
, r
*.9);
657 ctx
.arcTo(x1
- r
, y1
- r
/2.0, x0
, y2
, r
*1.09)
661 ctx
.fillStyle
= arrow_color
;
664 var r
= max
/ 100 * 2.0;
665 var y0
= max
/ 100 * 45;
666 var y1
= max
/ 100 * 54;
667 var y2
= max
/ 100 * 56;
668 var y3
= max
/ 100 * 59;
669 var y4
= max
/ 100 * 64;
670 var arrow_color
= "rgba(252, 38, 50, 1)";
672 var x0
= max
/ 100 * -8
673 var x1
= max
/ 100 * -6
674 var x2
= max
/ 100 * -1.5
675 var x3
= max
/ 100 * 0
676 var x4
= max
/ 100 * 1.5
677 var x5
= max
/ 100 * 6
678 var x6
= max
/ 100 * 8
682 ctx
.lineTo(x3
- r
, y4
- r
);
683 ctx
.arcTo(x3
, y4
+ r
, x3
+ r
, y4
- r
, r
* 1.09);
685 ctx
.arcTo(x6
+ r
/2.0, y2 - r/1.0, x5
, y1
, r
*.9)
688 ctx
.arcTo(x3
, y0
- r
, x2
, y0
, r
*.9);
691 ctx
.arcTo(x1
- r
, y1
+ r
/2.0, x0
, y2
, r
*1.09)
695 ctx
.fillStyle
= arrow_color
;
703 function padValue(val
) {
704 var cdec
= config
.valueFormat
['dec']
705 var cint
= config
.valueFormat
['int']
707 val
= parseFloat(val
);
713 val
= val
.toFixed(cdec
).toString().split('.');
715 for (var i
= 0, s
= cint
- val
[0].length
; i
< s
; ++i
) {
716 val
[0] = '0' + val
[0];
719 val
= (n
? '-' : '') + val
[0] + '.' + val
[1];
721 val
= Math
.round(val
).toString();
723 for (var i
= 0, s
= cint
- val
.length
; i
< s
; ++i
) {
727 val
= (n
? '-' : '') + val
733 function rpoint(r
, a
) {
740 X
= x
* cos
- y
* sin
,
741 Y
= x
* sin
+ y
* cos
744 return { x
: X
, y
: Y
};
746 function clearCircle(x
, y
, radius
)
749 ctx
.arc(x
, y
, radius
, 0, 2 * Math
.PI
, false);
751 ctx
.clearRect(x
- radius
- 1, y
- radius
- 1,
752 radius
* 2 + 2, radius
* 2 + 2);
755 // draws the highlight colors
756 function drawHighlights() {
759 var r1
= max
/ 100 * 81;
760 var r2
= r1
- max
/ 100 * 15;
762 for (var i
= 0, s
= config
.highlights
.length
; i
< s
; i
++) {
764 hlt
= config
.highlights
[i
],
765 vd
= (config
.maxValue
- config
.minValue
) / 270,
766 sa
= radians(45 + (hlt
.from - config
.minValue
) / vd
),
767 ea
= radians(45 + (hlt
.to
- config
.minValue
) / vd
)
772 ctx
.rotate(radians(90));
773 ctx
.arc(0, 0, r1
, sa
, ea
, false);
781 ctx
.moveTo(ps
.x
, ps
.y
);
782 ctx
.lineTo(pe
.x
, pe
.y
);
785 ps1
= rpoint(r1
, ea
),
789 ctx
.lineTo(ps1
.x
, ps1
.y
);
790 ctx
.lineTo(pe1
.x
, pe1
.y
);
791 ctx
.lineTo(ps
.x
, ps
.y
);
795 ctx
.fillStyle
= hlt
.color
;
799 ctx
.rotate(radians(90));
800 ctx
.arc(0, 0, r2
, sa
- 0.2, ea
+ 0.2, false);
805 ctx
.fillStyle
= config
.colors
.plate
;
808 ctx
.imageSmoothingEnabled
= true
809 //clearCircle(0, 0, 100)
814 // drows the gauge needle
815 function drawNeedle() {
819 rIn
= max
/ 100 * 85,
820 rOut
= max
/ 100 * 63,
822 pad1
= max
/ 100 * 3,
823 pad2
= max
/ 100 * 2.5,
826 ctx
.shadowOffsetX
= 2;
827 ctx
.shadowOffsetY
= 2;
829 // ctx.shadowColor = 'rgba(188, 143, 143, 0.45)';
830 ctx
.shadowColor
= 'rgba(50, 50, 50, .3)';
839 fromValue
= Math
.abs(config
.minValue
- fromValue
);
840 } else if (config
.minValue
> 0) {
841 fromValue
-= config
.minValue
843 fromValue
= Math
.abs(config
.minValue
) + fromValue
;
846 ctx
.rotate(radians(45 + fromValue
/ ((config
.maxValue
- config
.minValue
) / 270)));
849 ctx
.lineTo(-pad2
, rOut
);
850 ctx
.lineTo(-pad2
, rIn
);
851 ctx
.lineTo(pad2
, rIn
);
852 ctx
.lineTo(pad2
, rOut
);
855 ctx
.strokeStyle
= "#999"
858 ctx
.fillStyle
= lgrad(
859 config
.colors
.needle
.start
,
860 config
.colors
.needle
.end
,
866 // ctx.lineTo(-_pad2, _rOut);
867 // ctx.lineTo(-_pad2, _rIn);
868 // ctx.lineTo(_pad2, _rIn);
869 // ctx.lineTo(_pad2, _rOut);
870 // ctx.lineTo(0, _rOut - 5);
873 // ctx.fillStyle = "#ccc"
877 ctx
.lineTo(-pad2
, rIn
);
878 ctx
.lineTo(-pad2
, rIn
);
879 ctx
.lineTo(-pad1
, 0);
880 ctx
.lineTo(-pad2
, rOut
);
881 ctx
.lineTo(pad2
/ 2 - 2, rOut
);
883 ctx
.fillStyle
= 'rgba(255, 255, 255, 0.2)';
892 ctx
.arc(0, 0, r2
+.5, 0, Math
.PI
* 2, true);
893 // ctx.fillStyle = lgrad( '#f0f0f0', '#ccc', r1);
894 ctx
.fillStyle
= lgrad('#3b3b3b', '#121212', r1
);
900 ctx
.arc(0, 0, r2
, 0, Math
.PI
* 2, true);
901 // ctx.fillStyle = lgrad( "#e8e8e8", "#f5f5f5", r2);
902 ctx
.fillStyle
= 'rgba(255,255,255,1)';
906 function roundRect(x
, y
, w
, h
, r
) {
909 ctx
.moveTo(x
+ r
, y
);
910 ctx
.lineTo(x
+ w
- r
, y
);
912 ctx
.quadraticCurveTo(x
+ w
, y
, x
+ w
, y
+ r
);
913 ctx
.lineTo(x
+ w
, y
+ h
- r
);
915 ctx
.quadraticCurveTo(x
+ w
, y
+ h
, x
+ w
- r
, y
+ h
);
916 ctx
.lineTo(x
+ r
, y
+ h
);
918 ctx
.quadraticCurveTo(x
, y
+ h
, x
, y
+ h
- r
);
919 ctx
.lineTo(x
, y
+ r
);
921 ctx
.quadraticCurveTo(x
, y
, x
+ r
, y
);
927 function drawValueBox() {
930 ctx
.font
= 100 + " " + 73 * (max
/ 200) + "px 'roboto-light";
932 text
= padValue(value
),
933 tw
= ctx
.measureText('-' + padValue(0)).width
,
934 y
= max
- max
/ 100 * 96,
942 -tw
/ 2 - 0.025 * max
,
949 var grd
= ctx
.createRadialGradient(
951 y
- 0.12 * max
- 0.025 * max
+ (0.12 * max
+ 0.045 * max
) / 2,
954 y
- 0.12 * max
- 0.025 * max
+ (0.12 * max
+ 0.045 * max
) / 2,
958 // grd.addColorStop( 0, "#888");
959 // grd.addColorStop( 1, "#666");
961 // ctx.strokeStyle = grd;
962 // ctx.lineWidth = 0.05 * max;
965 // ctx.shadowBlur = 0.012 * max;
966 // ctx.shadowColor = 'rgba(0, 0, 0, 1)';
968 // ctx.fillStyle = "#babab2";
973 // ctx.shadowOffsetX = 0.004 * max;
974 // ctx.shadowOffsetY = 0.004 * max;
975 // ctx.shadowBlur = 0.012 * max;
976 // ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
978 // ctx.fillStyle = "#444";
979 ctx
.fillStyle
= "rgba(50,50,50,1)";
980 // ctx.fillStyle = "rgba(50,50,50,1)";
981 ctx
.textAlign
= "center";
983 ctx
.fillText(text
, -x
, y
);
987 ctx
.font
= 100 + " " + 20 * (max
/ 200) + "px 'roboto-light";
988 //ctx.fillText(config.unit, -x, y + 30);
995 Gauge
.initialized
= false;
999 h
= d
.getElementsByTagName('head')[0],
1000 ie
= navigator
.userAgent
.toLocaleLowerCase().indexOf('msie') != -1,
1001 url
= 'fonts/digital-7-mono.' + (ie
? 'eot' : 'ttf'),
1003 // RW: don't use mono font, this was causing err in js console
1005 // text = "@font-face {" +
1006 // "font-family: 'Led';" +
1007 // "src: url('" + url + "');" +
1010 r
= d
.createElement('style')
1013 r
.type
= 'text/css';
1021 r
.appendChild(d
.createTextNode(text
));
1028 ss
= r
.styleSheet
? r
.styleSheet
:
1029 (r
.sheet
|| d
.styleSheets
[d
.styleSheets
.length
- 1])
1033 var iv
= setInterval(function () {
1040 var dd
= d
.createElement('div');
1042 dd
.style
.fontFamily
= 'Led';
1043 dd
.style
.position
= 'absolute';
1044 dd
.style
.height
= dd
.style
.width
= 0;
1045 dd
.style
.overflow
= 'hidden';
1049 d
.body
.appendChild(dd
);
1051 setTimeout(function () { // no other way to handle font is rendered by a browser
1052 // just give the browser around 250ms to do that :(
1053 Gauge
.initialized
= true;
1054 dd
.parentNode
.removeChild(dd
);
1059 Gauge
.Collection
= [];
1060 Gauge
.Collection
.get = function (id
) {
1063 if (typeof(id
) == 'string') {
1064 for (var i
= 0, s
= self
.length
; i
< s
; i
++) {
1065 var canvas
= self
[i
].config
.renderTo
.tagName
? self
[i
].config
.renderTo
: document
.getElementById(self
[i
].config
.renderTo
);
1066 if (canvas
.getAttribute('id') == id
) {
1070 } else if (typeof(id
) == 'number') {
1077 function domReady(handler
) {
1078 if (window
.addEventListener
) {
1079 window
.addEventListener('DOMContentLoaded', handler
, false);
1081 window
.attachEvent('onload', handler
);
1085 domReady(function () {
1086 function toCamelCase(arr
) {
1088 for (var i
= 1, s
= arr
.length
; i
< s
; i
++) {
1089 str
+= arr
[i
].substr(0, 1).toUpperCase() + arr
[i
].substr(1, arr
[i
].length
- 1);
1094 function trim(str
) {
1095 return str
.replace(/^\s+|\s+$/g, '');
1098 var c
= document
.getElementsByTagName('canvas');
1100 for (var i
= 0, s
= c
.length
; i
< s
; i
++) {
1102 if (c
[i
].getAttribute('data-type') == 'canv-gauge') {
1107 w
= parseInt(gauge
.getAttribute('width'), 10),
1108 h
= parseInt(gauge
.getAttribute('height'), 10)
1111 config
.renderTo
= gauge
;
1121 for (var ii
= 0, ss
= gauge
.attributes
.length
; ii
< ss
; ii
++) {
1122 prop
= gauge
.attributes
.item(ii
).nodeName
;
1124 if (prop
!= 'data-type' && prop
.substr(0, 5) == 'data-') {
1126 cfgProp
= prop
.substr(5, prop
.length
- 5).toLowerCase().split('-'),
1127 attrValue
= gauge
.getAttribute(prop
)
1134 switch (cfgProp
[0]) {
1138 if (!config
.colors
) {
1142 if (cfgProp
[1] == 'needle') {
1143 var parts
= attrValue
.split(/\s+/);
1145 if (parts
[0] && parts
[1]) {
1146 config
.colors
.needle
= { start
: parts
[0], end
: parts
[1] };
1149 config
.colors
.needle
= attrValue
;
1154 config
.colors
[toCamelCase(cfgProp
)] = attrValue
;
1161 if (!config
.highlights
) {
1162 config
.highlights
= [];
1165 var hls
= attrValue
.match(/(?:(?:-?\d*\.)?(-?\d+){1,2} ){2}(?:(?:#|0x)?(?:[0-9A-F|a-f]){3,8}|rgba?\(.*?\))/g);
1167 for (var j
= 0, l
= hls
.length
; j
< l
; j
++) {
1169 cfg
= trim(hls
[j
]).split(/\s+/),
1173 if (cfg
[0] && cfg
[0] != '') {
1174 hlCfg
.from = cfg
[0];
1177 if (cfg
[1] && cfg
[1] != '') {
1181 if (cfg
[2] && cfg
[2] != '') {
1182 hlCfg
.color
= cfg
[2];
1185 config
.highlights
.push(hlCfg
);
1192 if (!config
.animation
) {
1193 config
.animation
= {};
1196 if (cfgProp
[1] == 'fn' && /^\s*function\s*\(/.test(attrValue
)) {
1197 attrValue
= eval('(' + attrValue
+ ')');
1200 config
.animation
[cfgProp
[1]] = attrValue
;
1206 var cfgName
= toCamelCase(cfgProp
);
1208 if (cfgName
== 'onready') {
1212 if (cfgName
== 'majorTicks') {
1213 attrValue
= attrValue
.split(/\s+/);
1215 else if (cfgName
== 'strokeTicks' || cfgName
== 'glow') {
1216 attrValue
= attrValue
== 'true' ? true : false;
1218 else if (cfgName
== 'valueFormat') {
1219 var val
= attrValue
.split('.');
1221 if (val
.length
== 2) {
1223 'int': parseInt(val
[0], 10),
1224 'dec': parseInt(val
[1], 10)
1232 config
[cfgName
] = attrValue
;
1239 var g
= new Gauge(config
);
1241 if (gauge
.getAttribute('data-value')) {
1242 g
.setRawValue(parseFloat(gauge
.getAttribute('data-value')));
1245 if (gauge
.getAttribute('data-onready')) {
1246 g
.onready = function () {
1247 eval(this.config
.renderTo
.getAttribute('data-onready'));
1255 module
.exports
= Gauge
;
1256 // window['Gauge'] = Gauge;