diff --git a/.gitignore b/.gitignore index d5a320f3..d1ec22f9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ dist/ .vscode complexity/ *es6.js +test/cjs/bundle.js diff --git a/.travis.yml b/.travis.yml index 52354594..448d9958 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,12 @@ -sudo: required +sudo: required dist: trusty language: node_js node_js: + - "7" - "6" before_install: + - source /opt/jdk_switcher/jdk_switcher.sh + - jdk_switcher use oraclejdk8 - export CHROME_BIN=/usr/bin/google-chrome - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start diff --git a/README.md b/README.md index 4a197864..a7515939 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# HTML Canvas Gauges v2.0 +# HTML Canvas Gauges v2.1 [![Build Status](https://travis-ci.org/Mikhus/canvas-gauges.svg?branch=master)](https://travis-ci.org/Mikhus/canvas-gauges) ![Test Coverage](https://rawgit.com/Mikhus/canvas-gauges/master/test-coverage.svg) ![Documentation Coverage](https://rawgit.com/Mikhus/canvas-gauges/master/docs-coverage.svg) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://rawgit.com/Mikhus/canvas-gauges/master/LICENSE) diff --git a/bower.json b/bower.json index 4a9382d2..92617a22 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "canvas-gauges", - "version": "2.0.9", + "version": "2.1.0", "homepage": "https://github.com/Mikhus/canvas-gauges", "authors": [ "Mykhailo Stadnyk " diff --git a/docs-coverage.svg b/docs-coverage.svg index 9f9c6003..a51e7b82 100644 --- a/docs-coverage.svg +++ b/docs-coverage.svg @@ -1 +1 @@ -docsdocs97.53%97.53% \ No newline at end of file +docsdocs95.04%95.04% \ No newline at end of file diff --git a/examples/async.html b/examples/async.html index cfc5ca2a..0b252b20 100644 --- a/examples/async.html +++ b/examples/async.html @@ -1,4 +1,4 @@ - + @@ -68,8 +68,8 @@ function initScriptedGauges() { new RadialGauge({ renderTo: 'another-gauge', - width: 400, - height: 400, + width: 800, + height: 800, units: 'Km/h', title: false, value: 0, diff --git a/examples/events.html b/examples/events.html new file mode 100644 index 00000000..0f984692 --- /dev/null +++ b/examples/events.html @@ -0,0 +1,147 @@ + + + + + Gauge Test + + + + + + + + +
+ + + + + + + + diff --git a/examples/issue-63.html b/examples/issue-63.html index ad16de97..d29f4cab 100644 --- a/examples/issue-63.html +++ b/examples/issue-63.html @@ -1,11 +1,11 @@ - + Gauge Test @@ -15,6 +15,9 @@ 570 583 830 + +
+ + + + + + + +
+ + + + + +
+ + + +
+ + + + + + + diff --git a/examples/no-auto-init.html b/examples/no-auto-init.html new file mode 100644 index 00000000..1255ec34 --- /dev/null +++ b/examples/no-auto-init.html @@ -0,0 +1,115 @@ + + + + + Gauge Test + + + + + + +
+ + + + + + + + diff --git a/examples/outrange.html b/examples/outrange.html new file mode 100644 index 00000000..c001a44f --- /dev/null +++ b/examples/outrange.html @@ -0,0 +1,135 @@ + + + + + Gauge Test + + + + + + + +
+ + + + + + + + + + + + + + + + + diff --git a/examples/radial-component.html b/examples/radial-component.html index 4452a422..698db6c4 100644 --- a/examples/radial-component.html +++ b/examples/radial-component.html @@ -10,6 +10,11 @@ + + + + +
@@ -44,8 +49,6 @@ data-value-box="true" data-animation-rule="bounce" data-animation-duration="500" - data-font-value="Led" - data-font-numbers="Led" data-border-outer-width="3" data-border-middle-width="3" data-border-inner-width="3" @@ -73,8 +76,8 @@ data-color-needle-start="rgba(240, 128, 128, 1)" data-color-needle-end="rgba(255, 160, 122, .9)" data-value-box="true" - data-font-value="Led" - data-font-numbers="Led" + data-font-value="Repetition" + data-font-numbers="Repetition" data-animated-value="true" data-borders="false" data-border-shadow-width="0" @@ -176,6 +179,9 @@ data-color-value-box-rect="#222" data-color-value-box-rect-end="#333" data-font-value="Led" + data-font-numbers="Led" + data-font-title="Led" + data-font-units="Led" > diff --git a/examples/radial-min-path.html b/examples/radial-min-path.html new file mode 100644 index 00000000..3d8dfb17 --- /dev/null +++ b/examples/radial-min-path.html @@ -0,0 +1,147 @@ + + + + + Gauge Test + + + + + + + + +
+ + + + + + + + diff --git a/examples/radial.html b/examples/radial.html index 493b6b4f..aeb092f1 100644 --- a/examples/radial.html +++ b/examples/radial.html @@ -1,4 +1,4 @@ - + diff --git a/fonts/TickingTimebombBB.ttf b/fonts/TickingTimebombBB.ttf new file mode 100644 index 00000000..e47c14cb Binary files /dev/null and b/fonts/TickingTimebombBB.ttf differ diff --git a/fonts/fonts.css b/fonts/fonts.css index 4c7cc762..fb6eafe1 100644 --- a/fonts/fonts.css +++ b/fonts/fonts.css @@ -2,5 +2,15 @@ font-family: 'Led'; src: url('digital-7-mono.eot'); src: url('digital-7-mono.eot?#iefix') format('embedded-opentype'), - url('digital-7-mono.ttf') format('truetype'); + url('digital-7-mono.ttf') format('truetype'); +} + +@font-face { + font-family: 'TimeBomb'; + src: url('TickingTimebombBB.ttf') format('truetype'); +} + +@font-face { + font-family: 'Repetition'; + src: url('repetition.ttf') format('truetype'); } diff --git a/fonts/repetition.ttf b/fonts/repetition.ttf new file mode 100644 index 00000000..1d0a4011 Binary files /dev/null and b/fonts/repetition.ttf differ diff --git a/gauge.min.js b/gauge.min.js index 0796bfdd..e28a77c2 100644 --- a/gauge.min.js +++ b/gauge.min.js @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * @version 2.0.9 + * @version 2.1.0 */ -!function(e){"use strict";function t(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t1&&(d=1),t&&t(1===d?d:i(d)),s0){for(a=e.toFixed(r).toString().split("."),n=i-a[0].length;o1?(i=~r.indexOf("."),~r.indexOf("-")?"-"+[t.majorTicksInt+t.majorTicksDec+2+(i?1:0)-r.length].join("0")+r.replace("-",""):[t.majorTicksInt+t.majorTicksDec+1+(i?1:0)-r.length].join("0")+r):r}function f(e){return e*Math.PI/180}function v(e,t){return{x:-e*Math.sin(t),y:e*Math.cos(t)}}function m(e,t,r,i){var o=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,a=e.createLinearGradient(o?0:n,o?n:0,o?0:i,o?i:0);return a.addColorStop(0,t),a.addColorStop(1,r),a}function b(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(r)return e.restore(),!0;e.save();var i=t.borderShadowWidth;return i&&(e.shadowBlur=i,e.shadowColor=t.colorBorderShadow),!0}function g(e,t){t.needleShadow&&(e.shadowOffsetX=2,e.shadowOffsetY=2,e.shadowBlur=10,e.shadowColor=t.colorNeedleShadowDown)}function p(e,t,r){return e["font"+t+"Style"]+" "+e["font"+t+"Weight"]+" "+e["font"+t+"Size"]*r+"px "+e["font"+t]}function w(e,t,r,i,o,n){if(t.valueBox){var a=t.valueText||h(r,t);e.shadowOffsetX=null,e.shadowOffsetY=null,e.shadowBlur=null,e.shadowColor="",e.strokeStyle=null,e.lineWidth=0,e.save(),e.font=p(t,"Value",n/200),e.save(),e.beginPath();var l=.12*n,s=parseFloat(t.valueBoxStroke)||0,d=2*n-2*s,u=e.measureText(t.valueText?a:"-"+h(0,t)).width,f=u+.05*n,v=l+.07*n,m=n*t.valueBoxBorderRadius/100,b=(parseFloat(t.valueBoxWidth)||0)/100*d;b>f&&(f=b),f>d&&(f=d);var g=i-f/2,w=o-l-.04*n;m?c(e,g,w,f,v,m):e.rect(g,w,f,v);var y=o-.12*n-.025*n+(.12*n+.045*n)/2;if(t.valueBoxStroke){var x=e.createRadialGradient(i,y,n/10,i,y,n/5);x.addColorStop(0,t.colorValueBoxRect),x.addColorStop(1,t.colorValueBoxRectEnd),e.strokeStyle=x,e.lineWidth=n*t.valueBoxStroke/100,e.stroke()}t.colorValueBoxShadow&&(e.shadowBlur=.012*n,e.shadowColor=t.colorValueBoxShadow),t.colorValueBoxBackground&&(e.fillStyle=t.colorValueBoxBackground,e.fill()),e.closePath(),e.restore(),t.valueTextShadow&&(e.shadowOffsetX=.004*n,e.shadowOffsetY=.004*n,e.shadowBlur=.012*n,e.shadowColor=t.colorValueTextShadow),e.fillStyle=t.colorValueText,e.textAlign="center",e.fillText(a,g+f/2,o),e.restore()}}function y(e,t,r,i,o){r.beginPath(),r.arc(0,0,fe(e),0,2*ge,!0),r.lineWidth=t,r.strokeStyle=o?be.linearGradient(r,i,o,e):i,r.stroke(),r.closePath()}function x(e,t){return e.maxRadius||(e.maxRadius=e.max-t.borderShadowWidth-t.borderOuterWidth-t.borderMiddleWidth-t.borderInnerWidth+(t.borderOuterWidth?.5:0)+(t.borderMiddleWidth?.5:0)+(t.borderInnerWidth?.5:0)),e.maxRadius}function T(e,t){var r=t.borderShadowWidth,i=e.max-r-t.borderOuterWidth/2,o=i-t.borderOuterWidth/2-t.borderMiddleWidth/2+.5,n=o-t.borderMiddleWidth/2-t.borderInnerWidth/2+.5,a=x(e,t),l=void 0,s=!1;e.save(),t.borderOuterWidth&&(s=be.drawShadow(e,t,s),y(i,t.borderOuterWidth,e,t.colorBorderOuter,t.colorBorderOuterEnd)),t.borderMiddleWidth&&(s=be.drawShadow(e,t,s),y(o,t.borderMiddleWidth,e,t.colorBorderMiddle,t.colorBorderMiddleEnd)),t.borderInnerWidth&&(s=be.drawShadow(e,t,s),y(n,t.borderInnerWidth,e,t.colorBorderInner,t.colorBorderInnerEnd)),be.drawShadow(e,t,s),e.beginPath(),e.arc(0,0,fe(a),0,2*ge,!0),t.colorPlateEnd?(l=e.createRadialGradient(0,0,a/2,0,0,a),l.addColorStop(0,t.colorPlate),l.addColorStop(1,t.colorPlateEnd)):l=t.colorPlate,e.fillStyle=l,e.fill(),e.closePath(),e.restore()}function k(e,t){var r=e.max*(parseFloat(t.highlightsWidth)||0)/100;if(r){var i=fe(W(e,t)-r/2),o=0,n=t.highlights.length,a=(t.maxValue-t.minValue)/t.ticksAngle;for(e.save();on?o:n,n>o,o>n?r:i):a,t>0?be.roundRect(e,r,i,o,n,t):e.rect(r,i,o,n),e.fill(),e.closePath()}function E(e,t,r,i,o,n,a,l,s){e.beginPath(),e.lineWidth=t,e.strokeStyle=s?be.linearGradient(e,l,s,a,!0,o):l,r>0?be.roundRect(e,i,o,n,a,r):e.rect(i,o,n,a),e.stroke(),e.closePath()}function R(e,t,r,i,o,n){e.save();var a=t.borderRadius,l=o-t.borderShadowWidth-t.borderOuterWidth,s=l-t.borderOuterWidth-t.borderMiddleWidth,d=s-t.borderMiddleWidth-t.borderInnerWidth,c=d-t.borderInnerWidth,h=n-t.borderShadowWidth-t.borderOuterWidth,u=h-t.borderOuterWidth-t.borderMiddleWidth,f=u-t.borderMiddleWidth-t.borderInnerWidth,v=f-t.borderInnerWidth,m=r-(s-l)/2,b=m-(d-s)/2,g=b-(c-d)/2,p=i-(u-h)/2,w=p-(f-u)/2,y=w-(v-f)/2,x=0,T=!1;return t.borderOuterWidth&&(T=be.drawShadow(e,t,T),E(e,t.borderOuterWidth,a,r+t.borderOuterWidth/2-x,i+t.borderOuterWidth/2-x,l,h,t.colorBorderOuter,t.colorBorderOuterEnd),x+=.5),t.borderMiddleWidth&&(T=be.drawShadow(e,t,T),E(e,t.borderMiddleWidth,a-=1+2*x,m+t.borderMiddleWidth/2-x,p+t.borderMiddleWidth/2-x,s+2*x,u+2*x,t.colorBorderMiddle,t.colorBorderMiddleEnd),x+=.5),t.borderInnerWidth&&(T=be.drawShadow(e,t,T),E(e,t.borderInnerWidth,a-=1+2*x,b+t.borderInnerWidth/2-x,w+t.borderInnerWidth/2-x,d+2*x,f+2*x,t.colorBorderInner,t.colorBorderInnerEnd),x+=.5),be.drawShadow(e,t,T),j(e,a,g,y,c+2*x,v+2*x,t.colorPlate,t.colorPlateEnd),e.restore(),[g,y,c,v]}function I(e,t,r,i,o,n){var a=de.pixelRatio,l=n>=o,s=l?.85*o:n,d=l?n:o;r=l?ue(r+(o-s)/2):r;var c=!!t.title,h=!!t.units,u=!!t.valueBox,f=void 0,v=void 0,m=void 0;l?(v=ue(.05*d),f=ue(.075*d),m=ue(.075*d),c&&(d-=f,i+=f),h&&(d-=v),u&&(d-=m)):(v=f=ue(.15*s),c&&(s-=f,i+=f),h&&(s-=v));var b=2*t.barStrokeWidth,g=t.barBeginCircle?ue(s*t.barBeginCircle/200-b/2):0,p=ue(s*t.barWidth/100-b),w=ue(d*t.barLength/100-b),y=ue((d-w)/2),x=ue(r+(l?s/2:y+g)),T=ue(i+(l?d-y-g+b/2:s/2)),k=!l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s,S=l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s;return e.barDimensions={isVertical:l,width:s,length:d,barWidth:p,barLength:w,strokeWidth:b,barMargin:y,radius:g,pixelRatio:a,barOffset:null,titleMargin:c?f:0,unitsMargin:h?v:0,get ticksLength(){return this.barLength-this.barOffset-this.strokeWidth},X:r+k,Y:i+S,x0:x+k,y0:T+S,baseX:r,baseY:i,ticksPadding:t.ticksPadding/100},e.barDimensions}function D(e,t,r,i,o,n,a){var l=I(e,t,i,o,n,a),s=l.isVertical,d=l.width,c=l.barWidth,h=l.barLength,u=l.strokeWidth,f=l.barMargin,v=l.radius,m=l.x0,b=l.y0,g=l.X,p=l.Y,w=h;if(e.save(),e.beginPath(),t.barBeginCircle){var y=be.radians(s?270:0),x=Math.asin(c/2/v),T=Math.cos(x),k=Math.sin(x),S=m+(s?v*k:v*T-u/2),W=s?b-v*T:b+v*k,O=fe(s?W-b:S-m);e.barDimensions.barOffset=ue(O+v);var M=s?ue(m-v*k):S,B=s?W:ue(b-v*k);"progress"===r&&(h=e.barDimensions.barOffset+(h-e.barDimensions.barOffset)*(t.value-t.minValue)/(t.maxValue-t.minValue));var P=ue(S+h-e.barDimensions.barOffset+u/2),A=ue(W-h+e.barDimensions.barOffset-u/2);e.arc(m,b,v,y+x,y-x),s?(e.moveTo(S,B),e.lineTo(S,A),e.lineTo(M,A),e.lineTo(M,B)):(e.moveTo(S,B),e.lineTo(P,B),e.lineTo(P,W),e.lineTo(S,W))}else{var C=ue(s?g+(d-c)/2:g+f),V=ue(s?p+h+f:p+(d-c)/2);"progress"===r&&(h*=(t.value-t.minValue)/(t.maxValue-t.minValue)),s?e.rect(C,V,c,-h):e.rect(C,V,h,c)}"progress"!==r&&t.barStrokeWidth&&(e.lineWidth=u,e.strokeStyle=t.colorBarStroke,e.stroke()),"progress"!==r&&t.colorBar?(e.fillStyle=t.colorBarEnd?be.linearGradient(e,t.colorBar,t.colorBarEnd,h,s,s?p:g):t.colorBar,e.fill()):"progress"===r&&t.colorBarProgress&&(e.fillStyle=t.colorBarProgressEnd?be.linearGradient(e,t.colorBarProgress,t.colorBarProgressEnd,w,s,s?p:g):t.colorBarProgress,e.fill()),e.closePath(),t.barBeginCircle&&(e.barDimensions.radius+=u),e.barDimensions.barWidth+=u,e.barDimensions.barLength+=u}function L(e,t,r,i,o,n){D(e,t,"",r,i,o,n)}function z(e,t){return t.needleSide!==e||t.tickSide!==e||t.numberSide!==e}function _(e,t,r,i,o,n){t.barProgress&&D(e,t,"progress",r,i,o,n)}function G(e,t){var r=e.barDimensions,i=r.isVertical,o=r.width,n=r.length,a=r.barWidth,l=r.barOffset,s=r.barMargin,d=r.X,c=r.Y,h=r.ticksLength,u=r.ticksPadding,f=o*(parseFloat(t.highlightsWidth)||0)/100;if(t.highlights&&f){var v="right"!==t.tickSide,m="left"!==t.tickSide,b=0,g=t.highlights.length,p=(o-a)/2,w=t.maxValue-t.minValue,y=ue(i?d+p:d+s+l),x=f,T=i?c+n-s-l:c+p,k=ue((t.ticksWidth/100+u)*o)+(f-t.ticksWidth/100*o),S=ue(a+u*o);for(e.save();bn&&(d*=-1),e.moveTo(r-h,i),e.lineTo(r+h,i),e.lineTo(r+h,i+d),e.lineTo(r,n),e.lineTo(r-h,i+d),e.lineTo(r-h,i)):(r>o&&(d*=-1),e.moveTo(r,i-h),e.lineTo(r,i+h),e.lineTo(r+d,i+h),e.lineTo(o,i),e.lineTo(r+d,i-h),e.lineTo(r,i-h)),e.fill(),e.closePath()}function te(e,t,r,i,o,n,a){e.barDimensions.isVertical&&be.drawValueBox(e,t,r,i+n/2,o+a-40*(n/300),n)}var re=function(){function e(e,t){var r=[],i=!0,o=!1,n=void 0;try{for(var a,l=e[Symbol.iterator]();!(i=(a=l.next()).done)&&(r.push(a.value),!t||r.length!==t);i=!0);}catch(e){o=!0,n=e}finally{try{!i&&l.return&&l.return()}finally{if(o)throw n}}return r}return function(t,r){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,r);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),ie=function e(t,r,i){null===t&&(t=Function.prototype);var o=Object.getOwnPropertyDescriptor(t,r);if(void 0===o){var n=Object.getPrototypeOf(t);return null===n?void 0:e(n,r,i)}if("value"in o)return o.value;var a=o.get;if(void 0!==a)return a.call(i)},oe=function(){function e(e,t){for(var r=0;r>>0;if(0===o)return-1;var n=+t||0;if(Math.abs(n)===1/0&&(n=0),n>=o)return-1;for(r=Math.max(n>=0?n:o-Math.abs(n),0);r>>0,i=arguments[1],o=i>>0,n=o<0?Math.max(r+o,0):Math.min(o,r),a=arguments[2],l=void 0===a?r:a>>0,s=l<0?Math.max(r+l,0):Math.min(l,r);n=(7-4*t)/11)return-Math.pow((11-6*t-11*e)/4,2)+Math.pow(r,2)},elastic:function(e){return 1-ae.delastic(1-e)},delastic:function(e){var t=1.5;return Math.pow(2,10*(e-1))*Math.cos(20*Math.PI*t/3*e)}},le=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"linear",r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:250,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){};if(o(this,t),this.duration=r,this.rule=e,this.draw=i,this.end=n,"function"!=typeof this.draw)throw new TypeError("Invalid animation draw callback:",i);if("function"!=typeof this.end)throw new TypeError("Invalid animation end callback:",n)}return oe(t,[{key:"animate",value:function(t,r){var i=this,o=e.performance&&e.performance.now?e.performance.now():n("animationStartTime")||Date.now();t=t||this.draw,r=r||this.end,this.frame=ne(function(e){return a(e,t,o,ae[i.rule]||i.rule,i.duration,r,i)})}},{key:"destroy",value:function(){if(this.frame){var e=n("cancelAnimationFrame")||function(e){};e(this.frame),this.frame=null}this.draw=null,this.end=null}}]),t}();le.rules=ae;var se=function(){function t(r,i,n){o(this,t),this.options=r,this.element=i.toLowerCase(),this.type=t.toDashed(n),this.Type=e[n],this.mutationsObserved=!1,this.isObservable=!!e.MutationObserver,t.domReady(this.traverse.bind(this))}return oe(t,[{key:"isValidNode",value:function(e){return!(!e.tagName||e.tagName.toLowerCase()!==this.element||e.getAttribute("data-type")!==this.type)}},{key:"traverse",value:function(){for(var t=document.getElementsByTagName(this.element),r=0,i=t.length;r360&&(e.ticksAngle=360),e.ticksAngle<0&&(e.ticksAngle=0),e.startAngle<0&&(e.startAngle=0),e.startAngle>360&&(e.startAngle=360),r(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e))}return i(t,e),oe(t,[{key:"draw",value:function(){try{var e=this.canvas,r=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],i=r[0],o=r[1],n=r[2],a=r[3],l=this.options; -if("needle"===l.animationTarget){if(!e.elementClone.initialized){var s=e.contextClone;s.clearRect(i,o,n,a),s.save(),T(s,l),k(s,l),S(s,l),O(s,l),P(s,l),A(s,l),C(s,l),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(i,o,n,a),e.context.save(),e.context.drawImage(e.elementClone,i,o,n,a),e.context.save(),N(e.context,l,l.animatedValue?this.options.value:this.value),V(e.context,l)}else{var d=-be.radians((l.value-l.minValue)/(l.maxValue-l.minValue)*l.ticksAngle);if(e.context.clearRect(i,o,n,a),e.context.save(),T(e.context,l),e.context.rotate(d),k(e.context,l),S(e.context,l),O(e.context,l),P(e.context,l),e.context.rotate(-d),e.context.save(),!e.elementClone.initialized){var c=e.contextClone;c.clearRect(i,o,n,a),c.save(),A(c,l),C(c,l),V(c,l),e.elementClone.initialized=!0}e.context.drawImage(e.elementClone,i,o,n,a)}N(e.context,l,l.animatedValue?this.options.value:this.value),ie(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"draw",this).call(this)}catch(e){be.verifyError(e)}return this}}]),t}(me);"undefined"!=typeof e&&(e.RadialGauge=ye),me.initialize("RadialGauge",we);var xe=Object.assign({},ce,{borderRadius:0,barBeginCircle:30,barWidth:20,barStrokeWidth:0,barProgress:!0,colorBarStroke:"#222",colorBar:"#ccc",colorBarEnd:"",colorBarProgress:"#888",colorBarProgressEnd:"",needleWidth:6,tickSide:"both",needleSide:"both",numberSide:"both",ticksWidth:10,ticksWidthMinor:5,ticksPadding:5,barLength:85,fontTitleSize:26,highlightsWidth:10}),Te=function(e){function n(e){return o(this,n),e=Object.assign({},xe,e||{}),e.barStrokeWidth>=e.barWidth&&(e.barStrokeWidth=ue(e.barWidth/2)),e.hasLeft=z("right",e),e.hasRight=z("left",e),r(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,e))}return i(n,e),oe(n,[{key:"draw",value:function(){try{var e=this.canvas,r=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],i=r[0],o=r[1],a=r[2],l=r[3],s=this.options;if(!e.elementClone.initialized){var d=e.contextClone;d.clearRect(i,o,a,l),d.save(),this.drawBox=R(d,s,i,o,a,l),L.apply(void 0,[d,s].concat(t(this.drawBox))),e.context.barDimensions=d.barDimensions,G(d,s),q(d,s),F(d,s),H(d,s),J(d,s),Z(d,s),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(i,o,a,l),e.context.save(),e.context.drawImage(e.elementClone,i,o,a,l),e.context.save(),_.apply(void 0,[e.context,s].concat(t(this.drawBox))),$(e.context,s),te.apply(void 0,[e.context,s,s.animatedValue?this.options.value:this.value].concat(t(this.drawBox))),ie(n.prototype.__proto__||Object.getPrototypeOf(n.prototype),"draw",this).call(this)}catch(e){be.verifyError(e)}return this}}]),n}(me);"undefined"!=typeof e&&(e.LinearGauge=Te),me.initialize("LinearGauge",xe),"undefined"!=typeof module&&Object.assign(e,{Collection:l,GenericOptions:ce,Animation:le,BaseGauge:me,drawings:be,SmartCanvas:de,vendorize:n})}("undefined"!=typeof module?module.exports:window); +!function(e){"use strict";function t(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t1&&(d=1),t&&t(1===d?d:r(d)),s0){for(a=e.toFixed(i).toString().split("."),n=r-a[0].length;o1?(r=~i.indexOf("."),~i.indexOf("-")?"-"+[t.majorTicksInt+t.majorTicksDec+2+(r?1:0)-i.length].join("0")+i.replace("-",""):[t.majorTicksInt+t.majorTicksDec+1+(r?1:0)-i.length].join("0")+i):i}function f(e){return e*Math.PI/180}function v(e,t){return{x:-e*Math.sin(t),y:e*Math.cos(t)}}function m(e,t,i,r){var o=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,a=e.createLinearGradient(o?0:n,o?n:0,o?0:r,o?r:0);return a.addColorStop(0,t),a.addColorStop(1,i),a}function b(e,t){var i=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(i)return e.restore(),!0;e.save();var r=t.borderShadowWidth;return r&&(e.shadowBlur=r,e.shadowColor=t.colorBorderShadow),!0}function g(e,t){t.needleShadow&&(e.shadowOffsetX=2,e.shadowOffsetY=2,e.shadowBlur=10,e.shadowColor=t.colorNeedleShadowDown)}function p(e,t,i){return e["font"+t+"Style"]+" "+e["font"+t+"Weight"]+" "+e["font"+t+"Size"]*i+"px "+e["font"+t]}function w(e){e.shadowOffsetX=null,e.shadowOffsetY=null,e.shadowBlur=null,e.shadowColor="",e.strokeStyle=null,e.lineWidth=0,e.save()}function y(e,t,i,r){t.valueTextShadow&&(e.shadowOffsetX=i,e.shadowOffsetY=i,e.shadowBlur=r,e.shadowColor=t.colorValueTextShadow)}function k(e,t,i,r,o,n){if(t.valueBox){w(e);var a=t.valueText||c(i,t),l=n/200,s=n/100,d=.4*s,u=1.2*s;e.font=p(t,"Value",l),y(e,t,d,u);var f=e.measureText(t.valueText?a:"-"+c(0,t)).width;w(e);var v=parseFloat(t.fontValueSize)*l+d+u,m=s*parseFloat(t.valueBoxStroke),b=2*n-2*m,g=f+10*s,k=1.1*v+d+u,x=s*t.valueBoxBorderRadius,T=(parseFloat(t.valueBoxWidth)||0)/100*b;T>g&&(g=T),g>b&&(g=b);var S=r-g/2,W=o-k/2,O=o-5.75*s;if(e.beginPath(),x?h(e,S,W,g,k,x):e.rect(S,W,g,k),m){var P=e.createRadialGradient(r,O,10*s,r,O,20*s);P.addColorStop(0,t.colorValueBoxRect),P.addColorStop(1,t.colorValueBoxRectEnd),e.strokeStyle=P,e.lineWidth=m,e.stroke()}t.colorValueBoxShadow&&(e.shadowBlur=1.2*s,e.shadowColor=t.colorValueBoxShadow),t.colorValueBoxBackground&&(e.fillStyle=t.colorValueBoxBackground,e.fill()),e.closePath(),e.restore(),y(e,t,d,u),e.fillStyle=t.colorValueText,e.textAlign="center",e.textBaseline="alphabetic",e.fillText(a,S+g/2,o+k/2-v/3),e.restore()}}function x(e){var t=e.value,i=e.minValue,r=e.maxValue,o=.01*(r-i);return{normal:tr?r:t,indented:tr?r+o:t}}function T(e,t,i,r,o){i.beginPath(),i.arc(0,0,ye(e),0,2*Se,!0),i.lineWidth=t,i.strokeStyle=o?Te.linearGradient(i,r,o,e):r,i.stroke(),i.closePath()}function S(e,t){return e.maxRadius||(e.maxRadius=e.max-t.borderShadowWidth-t.borderOuterWidth-t.borderMiddleWidth-t.borderInnerWidth+(t.borderOuterWidth?.5:0)+(t.borderMiddleWidth?.5:0)+(t.borderInnerWidth?.5:0)),e.maxRadius}function W(e,t){var i=t.borderShadowWidth,r=e.max-i-t.borderOuterWidth/2,o=r-t.borderOuterWidth/2-t.borderMiddleWidth/2+.5,n=o-t.borderMiddleWidth/2-t.borderInnerWidth/2+.5,a=S(e,t),l=void 0,s=!1;e.save(),t.borderOuterWidth&&(s=Te.drawShadow(e,t,s),T(r,t.borderOuterWidth,e,t.colorBorderOuter,t.colorBorderOuterEnd)),t.borderMiddleWidth&&(s=Te.drawShadow(e,t,s),T(o,t.borderMiddleWidth,e,t.colorBorderMiddle,t.colorBorderMiddleEnd)),t.borderInnerWidth&&(s=Te.drawShadow(e,t,s),T(n,t.borderInnerWidth,e,t.colorBorderInner,t.colorBorderInnerEnd)),Te.drawShadow(e,t,s),e.beginPath(),e.arc(0,0,ye(a),0,2*Se,!0),t.colorPlateEnd?(l=e.createRadialGradient(0,0,a/2,0,0,a),l.addColorStop(0,t.colorPlate),l.addColorStop(1,t.colorPlateEnd)):l=t.colorPlate,e.fillStyle=l,e.fill(),e.closePath(),e.restore()}function O(e,t){var i=e.max*(parseFloat(t.highlightsWidth)||0)/100;if(i){var r=ye(V(e,t)-i/2),o=0,n=t.highlights.length,a=(t.maxValue-t.minValue)/t.ticksAngle;for(e.save();on?o:n,n>o,o>n?i:r):a,t>0?Te.roundRect(e,i,r,o,n,t):e.rect(i,r,o,n),e.fill(),e.closePath()}function z(e,t,i,r,o,n,a,l,s){e.beginPath(),e.lineWidth=t,e.strokeStyle=s?Te.linearGradient(e,l,s,a,!0,o):l,i>0?Te.roundRect(e,r,o,n,a,i):e.rect(r,o,n,a),e.stroke(),e.closePath()}function L(e,t,i,r,o,n){e.save();var a=t.borderRadius,l=o-t.borderShadowWidth-t.borderOuterWidth,s=l-t.borderOuterWidth-t.borderMiddleWidth,d=s-t.borderMiddleWidth-t.borderInnerWidth,h=d-t.borderInnerWidth,c=n-t.borderShadowWidth-t.borderOuterWidth,u=c-t.borderOuterWidth-t.borderMiddleWidth,f=u-t.borderMiddleWidth-t.borderInnerWidth,v=f-t.borderInnerWidth,m=i-(s-l)/2,b=m-(d-s)/2,g=b-(h-d)/2,p=r-(u-c)/2,w=p-(f-u)/2,y=w-(v-f)/2,k=0,x=!1;return t.borderOuterWidth&&(x=Te.drawShadow(e,t,x),z(e,t.borderOuterWidth,a,i+t.borderOuterWidth/2-k,r+t.borderOuterWidth/2-k,l,c,t.colorBorderOuter,t.colorBorderOuterEnd),k+=.5),t.borderMiddleWidth&&(x=Te.drawShadow(e,t,x),z(e,t.borderMiddleWidth,a-=1+2*k,m+t.borderMiddleWidth/2-k,p+t.borderMiddleWidth/2-k,s+2*k,u+2*k,t.colorBorderMiddle,t.colorBorderMiddleEnd),k+=.5),t.borderInnerWidth&&(x=Te.drawShadow(e,t,x),z(e,t.borderInnerWidth,a-=1+2*k,b+t.borderInnerWidth/2-k,w+t.borderInnerWidth/2-k,d+2*k,f+2*k,t.colorBorderInner,t.colorBorderInnerEnd),k+=.5),Te.drawShadow(e,t,x),D(e,a,g,y,h+2*k,v+2*k,t.colorPlate,t.colorPlateEnd),e.restore(),[g,y,h,v]}function G(e,t,i,r,o,n){var a=be.pixelRatio,l=n>=o,s=l?.85*o:n,d=l?n:o;i=l?we(i+(o-s)/2):i;var h=!!t.title,c=!!t.units,u=!!t.valueBox,f=void 0,v=void 0,m=void 0;l?(v=we(.05*d),f=we(.075*d),m=we(.11*d),h&&(d-=f,r+=f),c&&(d-=v),u&&(d-=m)):(v=f=we(.15*s),h&&(s-=f,r+=f),c&&(s-=v));var b=2*t.barStrokeWidth,g=t.barBeginCircle?we(s*t.barBeginCircle/200-b/2):0,p=we(s*t.barWidth/100-b),w=we(d*t.barLength/100-b),y=we((d-w)/2),k=we(i+(l?s/2:y+g)),x=we(r+(l?d-y-g+b/2:s/2)),T=!l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s,S=l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s;return e.barDimensions={isVertical:l,width:s,length:d,barWidth:p,barLength:w,strokeWidth:b,barMargin:y,radius:g,pixelRatio:a,barOffset:null,titleMargin:h?f:0,unitsMargin:c?v:0,get ticksLength(){return this.barLength-this.barOffset-this.strokeWidth},X:i+T,Y:r+S,x0:k+T,y0:x+S,baseX:i,baseY:r,ticksPadding:t.ticksPadding/100},e.barDimensions}function F(e,t,i,r,o,n,a){var l=G(e,t,r,o,n,a),s=l.isVertical,d=l.width,h=l.barWidth,c=l.barLength,u=l.strokeWidth,f=l.barMargin,v=l.radius,m=l.x0,b=l.y0,g=l.X,p=l.Y,w=c;if(e.save(),e.beginPath(),t.barBeginCircle){var y=Te.radians(s?270:0),k=Math.asin(h/2/v),x=Math.cos(k),T=Math.sin(k),S=m+(s?v*T:v*x-u/2),W=s?b-v*x:b+v*T,O=ye(s?W-b:S-m);e.barDimensions.barOffset=we(O+v);var P=s?we(m-v*T):S,V=s?W:we(b-v*T);"progress"===i&&(c=e.barDimensions.barOffset+(c-e.barDimensions.barOffset)*(Te.normalizedValue(t).normal-t.minValue)/(t.maxValue-t.minValue));var B=we(S+c-e.barDimensions.barOffset+u/2),M=we(W-c+e.barDimensions.barOffset-u/2);e.arc(m,b,v,y+k,y-k),s?(e.moveTo(S,V),e.lineTo(S,M),e.lineTo(P,M),e.lineTo(P,V)):(e.moveTo(S,V),e.lineTo(B,V),e.lineTo(B,W),e.lineTo(S,W))}else{var A=we(s?g+(d-h)/2:g+f),C=we(s?p+c+f:p+(d-h)/2);"progress"===i&&(c*=(t.value-t.minValue)/(t.maxValue-t.minValue)),s?e.rect(A,C,h,-c):e.rect(A,C,c,h)}"progress"!==i&&t.barStrokeWidth&&(e.lineWidth=u,e.strokeStyle=t.colorBarStroke,e.stroke()),"progress"!==i&&t.colorBar?(e.fillStyle=t.colorBarEnd?Te.linearGradient(e,t.colorBar,t.colorBarEnd,c,s,s?p:g):t.colorBar,e.fill()):"progress"===i&&t.colorBarProgress&&(e.fillStyle=t.colorBarProgressEnd?Te.linearGradient(e,t.colorBarProgress,t.colorBarProgressEnd,w,s,s?p:g):t.colorBarProgress,e.fill()),e.closePath(),t.barBeginCircle&&(e.barDimensions.radius+=u),e.barDimensions.barWidth+=u,e.barDimensions.barLength+=u}function X(e,t,i,r,o,n){F(e,t,"",i,r,o,n)}function Y(e,t){return t.needleSide!==e||t.tickSide!==e||t.numberSide!==e}function U(e,t,i,r,o,n){t.barProgress&&F(e,t,"progress",i,r,o,n)}function H(e,t){var i=e.barDimensions,r=i.isVertical,o=i.width,n=i.length,a=i.barWidth,l=i.barOffset,s=i.barMargin,d=i.X,h=i.Y,c=i.ticksLength,u=i.ticksPadding,f=o*(parseFloat(t.highlightsWidth)||0)/100;if(t.highlights&&f){var v="right"!==t.tickSide,m="left"!==t.tickSide,b=0,g=t.highlights.length,p=(o-a)/2,w=t.maxValue-t.minValue,y=we(r?d+p:d+s+l),k=f,x=r?h+n-s-l:h+p,T=we((t.ticksWidth/100+u)*o)+(f-t.ticksWidth/100*o),S=we(a+u*o);for(e.save();bn&&(d*=-1),e.moveTo(i-c,r),e.lineTo(i+c,r),e.lineTo(i+c,r+d),e.lineTo(i,n),e.lineTo(i-c,r+d),e.lineTo(i-c,r)):(i>o&&(d*=-1),e.moveTo(i,r-c),e.lineTo(i,r+c),e.lineTo(i+d,r+c),e.lineTo(o,r),e.lineTo(i+d,r-c),e.lineTo(i,r-c)),e.fill(),e.closePath()}function ae(e,t,i,r,o,n,a){var l=(parseFloat(t.fontValueSize)||0)*n/200,s=(.11*a-l)/2;e.barDimensions.isVertical&&Te.drawValueBox(e,t,i,r+n/2,o+a-l-s,n)}var le=function(){function e(e,t){var i=[],r=!0,o=!1,n=void 0;try{for(var a,l=e[Symbol.iterator]();!(r=(a=l.next()).done)&&(i.push(a.value),!t||i.length!==t);r=!0);}catch(e){o=!0,n=e}finally{try{!r&&l.return&&l.return()}finally{if(o)throw n}}return i}return function(t,i){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),se=function e(t,i,r){null===t&&(t=Function.prototype);var o=Object.getOwnPropertyDescriptor(t,i);if(void 0===o){var n=Object.getPrototypeOf(t);return null===n?void 0:e(n,i,r)}if("value"in o)return o.value;var a=o.get;if(void 0!==a)return a.call(r)},de=function e(t,i,r,o){var n=Object.getOwnPropertyDescriptor(t,i);if(void 0===n){var a=Object.getPrototypeOf(t);null!==a&&e(a,i,r,o)}else if("value"in n&&n.writable)n.value=r;else{var l=n.set;void 0!==l&&l.call(o,r)}return r},he=function(){function e(e,t){for(var i=0;i>>0;if(0===o)return-1;var n=+t||0;if(Math.abs(n)===1/0&&(n=0),n>=o)return-1;for(i=Math.max(n>=0?n:o-Math.abs(n),0);i>>0,r=arguments[1],o=r>>0,n=o<0?Math.max(i+o,0):Math.min(o,i),a=arguments[2],l=void 0===a?i:a>>0,s=l<0?Math.max(i+l,0):Math.min(l,i);n1?r-1:0),n=1;n1?t-1:0),r=1;r=(7-4*t)/11)return-Math.pow((11-6*t-11*e)/4,2)+Math.pow(i,2)},elastic:function(e){return 1-fe.delastic(1-e)},delastic:function(e){var t=1.5;return Math.pow(2,10*(e-1))*Math.cos(20*Math.PI*t/3*e)}},ve=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"linear",i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:250,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){};if(o(this,e),this.duration=i,this.rule=t,this.draw=r,this.end=n,"function"!=typeof this.draw)throw new TypeError("Invalid animation draw callback:",r);if("function"!=typeof this.end)throw new TypeError("Invalid animation end callback:",n)}return he(e,[{key:"animate",value:function(e,t){var i=this,r=window.performance&&window.performance.now?window.performance.now():n("animationStartTime")||Date.now();e=e||this.draw,t=t||this.end,this.frame=ue(function(o){return a(o,e,r,fe[i.rule]||i.rule,i.duration,t,i)})}},{key:"destroy",value:function(){if(this.frame){var e=n("cancelAnimationFrame")||function(e){};e(this.frame),this.frame=null}this.draw=null,this.end=null}}]),e}();ve.rules=fe;var me=function(){function t(i,r,n){o(this,t),this.options=i,this.element=r.toLowerCase(),this.type=t.toDashed(n),this.Type=e[n],this.mutationsObserved=!1,this.isObservable=!!window.MutationObserver,window.GAUGES_NO_AUTO_INIT||t.domReady(this.traverse.bind(this))}return he(t,[{key:"isValidNode",value:function(e){return!(!e.tagName||e.tagName.toLowerCase()!==this.element||e.getAttribute("data-type")!==this.type)}},{key:"traverse",value:function(){for(var e=document.getElementsByTagName(this.element),t=0,i=e.length;t1&&void 0!==arguments[1])||arguments[1],i=e.split(/-/),r=0,o=i.length,n="";r1&&void 0!==arguments[1]?arguments[1]:0;return e=parseFloat(e),!isNaN(e)&&isFinite(e)||(e=parseFloat(t)||0),e}},{key:"version",get:function(){return pe}}]),n}(ce);"undefined"!=typeof e&&(e.BaseGauge=xe,e.gauges=(window.document||{}).gauges=ke);var Te={roundRect:h,padValue:c,formatMajorTickNumber:u,radians:f,radialPoint:v,linearGradient:m,drawNeedleShadow:g,drawValueBox:k,verifyError:s,prepareTicks:d,drawShadow:b,font:p,normalizedValue:x},Se=Math.PI,We=Se/2,Oe=Object.assign({},ge,{ticksAngle:270,startAngle:45,colorNeedleCircleOuter:"#f0f0f0",colorNeedleCircleOuterEnd:"#ccc",colorNeedleCircleInner:"#e8e8e8",colorNeedleCircleInnerEnd:"#f5f5f5",needleCircleSize:10,needleCircleInner:!0,needleCircleOuter:!0,animationTarget:"needle",useMinPath:!1,barWidth:0}),Pe=function(e){function t(e){return o(this,t),e=Object.assign({},Oe,e||{}),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,t.configure(e)))}return r(t,e),he(t,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],n=i[2],a=i[3],l=this.options;if("needle"===l.animationTarget){if(!e.elementClone.initialized){var s=e.contextClone;s.clearRect(r,o,n,a),s.save(),this.emit("beforePlate"),W(s,l),this.emit("beforeHighlights"),O(s,l),this.emit("beforeMinorTicks"),P(s,l),this.emit("beforeMajorTicks"),B(s,l),this.emit("beforeNumbers"),C(s,l),this.emit("beforeTitle"),N(s,l),this.emit("beforeUnits"),j(s,l),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,n,a),e.context.save(),e.context.drawImage(e.elementClone,r,o,n,a),e.context.save(),this.emit("beforeProgressBar"),R(e.context,l),this.emit("beforeValueBox"),_(e.context,l,I(this)),this.emit("beforeNeedle"),E(e.context,l)}else{var d=-Te.radians((l.value-l.minValue)/(l.maxValue-l.minValue)*l.ticksAngle);if(e.context.clearRect(r,o,n,a),e.context.save(),this.emit("beforePlate"),W(e.context,l),e.context.rotate(d),this.emit("beforeHighlights"),O(e.context,l),this.emit("beforeMinorTicks"),P(e.context,l),this.emit("beforeMajorTicks"),B(e.context,l),this.emit("beforeNumbers"),C(e.context,l),this.emit("beforeProgressBar"),R(e.context,l),e.context.rotate(-d),e.context.save(),!e.elementClone.initialized){var h=e.contextClone;h.clearRect(r,o,n,a),h.save(),this.emit("beforeTitle"),N(h,l),this.emit("beforeUnits"),j(h,l),this.emit("beforeNeedle"),E(h,l),e.elementClone.initialized=!0}e.context.drawImage(e.elementClone,r,o,n,a)}this.emit("beforeValueBox"),_(e.context,l,I(this)),se(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"draw",this).call(this)}catch(e){Te.verifyError(e)}return this}},{key:"value",set:function(e){e=xe.ensureValue(e,this.options.minValue),this.options.animation&&360===this.options.ticksAngle&&this.options.useMinPath&&(this._value=e,e=this.options.value+((e-this.options.value)%360+540)%360-180),de(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",e,this)},get:function(){return se(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",this)}}],[{key:"configure",value:function(e){return e.barWidth>50&&(e.barWidth=50),isNaN(e.startAngle)&&(e.startAngle=45),isNaN(e.ticksAngle)&&(e.ticksAngle=270),e.ticksAngle>360&&(e.ticksAngle=360),e.ticksAngle<0&&(e.ticksAngle=0),e.startAngle<0&&(e.startAngle=0),e.startAngle>360&&(e.startAngle=360),e}}]),t}(xe);"undefined"!=typeof e&&(e.RadialGauge=Pe),xe.initialize("RadialGauge",Oe);var Ve=Object.assign({},ge,{borderRadius:0,barBeginCircle:30,colorBarEnd:"",colorBarProgressEnd:"",needleWidth:6,tickSide:"both",needleSide:"both",numberSide:"both",ticksWidth:10,ticksWidthMinor:5,ticksPadding:5,barLength:85,fontTitleSize:26,highlightsWidth:10}),Be=function(e){function n(e){return o(this,n),e=Object.assign({},Ve,e||{}),i(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n.configure(e)))}return r(n,e),he(n,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],a=i[2],l=i[3],s=this.options;if(!e.elementClone.initialized){var d=e.contextClone;d.clearRect(r,o,a,l),d.save(),this.emit("beforePlate"),this.drawBox=L(d,s,r,o,a,l),this.emit("beforeBar"),X.apply(void 0,[d,s].concat(t(this.drawBox))),e.context.barDimensions=d.barDimensions,this.emit("beforeHighlights"),H(d,s),this.emit("beforeMinorTicks"),K(d,s),this.emit("beforeMajorTicks"),$(d,s),this.emit("beforeNumbers"),Q(d,s),this.emit("beforeTitle"),ee(d,s),this.emit("beforeUnits"),te(d,s),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,a,l),e.context.save(),e.context.drawImage(e.elementClone,r,o,a,l),e.context.save(),this.emit("beforeProgressBar"),U.apply(void 0,[e.context,s].concat(t(this.drawBox))),this.emit("beforeNeedle"),ie(e.context,s),this.emit("beforeValueBox"),ae.apply(void 0,[e.context,s,s.animatedValue?this.options.value:this.value].concat(t(this.drawBox))),se(n.prototype.__proto__||Object.getPrototypeOf(n.prototype),"draw",this).call(this)}catch(e){Te.verifyError(e)}return this}}],[{key:"configure",value:function(e){return e.barStrokeWidth>=e.barWidth&&(e.barStrokeWidth=we(e.barWidth/2)),e.hasLeft=Y("right",e),e.hasRight=Y("left",e),e.value>e.maxValue&&(e.value=e.maxValue),e.value\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * @version 2.0.9\n */\n(function(ns) {'use strict';\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nvar _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if (\"value\" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * @external {Object.assign} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n */\n/* istanbul ignore next */\nif (!Object.assign) {\n Object.defineProperty(Object, 'assign', {\n enumerable: false,\n configurable: true,\n writable: true,\n value: function value(target, firstSource) {\n 'use strict';\n\n if (target === undefined || target === null) {\n throw new TypeError('Cannot convert first argument to object');\n }\n\n var to = Object(target);\n var i = 1;\n\n for (; i < arguments.length; i++) {\n var nextSource = arguments[i];\n\n if (nextSource === undefined || nextSource === null) {\n continue;\n }\n\n var keysArray = Object.keys(Object(nextSource));\n var nextIndex = 0,\n len = keysArray.length;\n\n for (; nextIndex < len; nextIndex++) {\n var nextKey = keysArray[nextIndex];\n var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);\n\n if (desc !== undefined && desc.enumerable) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n\n return to;\n }\n });\n}\n\n/**\n * @external {Array.indexOf} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf\n */\n/* istanbul ignore next */\nif (!Array.prototype.indexOf) {\n Array.prototype.indexOf = function (searchElement, fromIndex) {\n var k;\n\n if (this === null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n var O = Object(this);\n var len = O.length >>> 0;\n\n if (len === 0) {\n return -1;\n }\n\n var n = +fromIndex || 0;\n\n if (Math.abs(n) === Infinity) {\n n = 0;\n }\n\n if (n >= len) {\n return -1;\n }\n\n k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n while (k < len) {\n if (k in O && O[k] === searchElement) {\n return k;\n }\n\n k++;\n }\n\n return -1;\n };\n}\n\n/**\n * @external {Array.fill} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/fill\n */\n/* istanbul ignore next */\nif (!Array.prototype.fill) {\n Array.prototype.fill = function (value) {\n if (this === null) {\n throw new TypeError('this is null or not defined');\n }\n\n var O = Object(this);\n var len = O.length >>> 0;\n var start = arguments[1];\n var relativeStart = start >> 0;\n var k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);\n var end = arguments[2];\n var relativeEnd = end === undefined ? len : end >> 0;\n var final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);\n while (k < final) {\n O[k] = value;\n k++;\n }\n\n return O;\n };\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/**\n * Look-ups for a proper vendor-specific property and returns its value\n *\n * @example\n * var requestAnimationFrame = vendorize('requestAnimationFrame');\n * // it will refer properly to:\n * // - window.requestAnimationFrame by default or to\n * // - window.webkitRequestAnimationFrame or to\n * // - window.mozRequestAnimationFrame or to\n * // - window.msRequestAnimationFrame or to\n * // - window.oRequestAnimationFrame\n * // depending on the current browser vendor\n *\n * @author Mykhailo Stadnyk \n * @param {string} prop\n * @param {HTMLElement|Window|object} [from] - default is window\n * @returns {*}\n */\nfunction vendorize(prop, from) {\n /* istanbul ignore else: no reason to cover */\n if (!from) {\n from = typeof window === 'undefined' ? global : window;\n }\n\n if (typeof from[prop] !== 'undefined') {\n return from[prop];\n }\n\n var vendors = ['webkit', 'moz', 'ms', 'o'];\n var i = 0;\n var s = vendors.length;\n var capitalized = prop.charAt(0).toUpperCase() + prop.substr(1);\n\n for (; i < s; i++) {\n var vendorProp = from[vendors[i] + capitalized];\n\n /* istanbul ignore if: requires very complex environment to test (specific browser version) */\n if (typeof vendorProp !== 'undefined') {\n return vendorProp;\n }\n }\n\n return null;\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/* jshint -W079 */\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n\n/* istanbul ignore next */\n/**\n * @type {function(callback: function(time: number): number, element?: HTMLElement)}\n * @access private\n */\nvar requestAnimationFrame = vendorize('requestAnimationFrame') || function (callback) {\n return setTimeout(function () {\n return callback(new Date().getTime());\n }, 1000 / 60);\n};\n\n/**\n * Generic AnimationRule function interface\n *\n * @typedef {function(percent: number): number} AnimationRule\n */\n\n/**\n * Callback for animation step draw event.\n * It will be called each time animation step is executed, bypassing\n * as first argument a percent of animation completeness. It is expected\n * that this callback will do an actual work of animating an elements or\n * whatever, as far as animation engine is just calculating and executing\n * animation steps without any knowledge about things under animation.\n *\n * @typedef {function(percent: number): *} DrawEventCallback\n */\n\n/**\n * Callback for animation complete event.\n * It is called once each animation is complete.\n *\n * @typedef {function(): *} EndEventCallback\n */\n\n/**\n * Predefined known animation rules.\n * It's a simple collection of math for some most used animations.\n *\n * @typedef {{linear: AnimationRule, quad: AnimationRule, dequad: AnimationRule, quint: AnimationRule, dequint: AnimationRule, cycle: AnimationRule, decycle: AnimationRule, bounce: AnimationRule, debounce: AnimationRule, elastic: AnimationRule, delastic: AnimationRule}} AnimationRules\n */\n\n/* istanbul ignore next: no reason covering this */\nvar rules = {\n linear: function linear(p) {\n return p;\n },\n quad: function quad(p) {\n return Math.pow(p, 2);\n },\n dequad: function dequad(p) {\n return 1 - rules.quad(1 - p);\n },\n quint: function quint(p) {\n return Math.pow(p, 5);\n },\n dequint: function dequint(p) {\n return 1 - Math.pow(1 - p, 5);\n },\n cycle: function cycle(p) {\n return 1 - Math.sin(Math.acos(p));\n },\n decycle: function decycle(p) {\n return Math.sin(Math.acos(1 - p));\n },\n bounce: function bounce(p) {\n return 1 - rules.debounce(1 - p);\n },\n debounce: function debounce(p) {\n var a = 0,\n b = 1;\n for (; 1; a += b, b /= 2) {\n if (p >= (7 - 4 * a) / 11) {\n return -Math.pow((11 - 6 * a - 11 * p) / 4, 2) + Math.pow(b, 2);\n }\n }\n },\n elastic: function elastic(p) {\n return 1 - rules.delastic(1 - p);\n },\n delastic: function delastic(p) {\n var x = 1.5;\n return Math.pow(2, 10 * (p - 1)) * Math.cos(20 * Math.PI * x / 3 * p);\n }\n};\n\n/* istanbul ignore next: private, not testable */\n/**\n * Evaluates animation step and decides if the next step required or\n * stops animation calling a proper events.\n *\n * @access private\n * @param {number} time\n * @param {DrawEventCallback} draw\n * @param {number} start\n * @param {AnimationRule} rule\n * @param {number} duration\n * @param {EndEventCallback} end\n * @param {Animation} anim\n */\nfunction step(time, draw, start, rule, duration, end, anim) {\n if (typeof rule !== 'function') {\n throw new TypeError('Invalid animation rule:', rule);\n }\n\n var progress = time - start;\n var percent = progress / duration;\n\n if (percent > 1) {\n percent = 1;\n }\n\n draw && draw(percent === 1 ? percent : rule(percent));\n\n if (progress < duration) {\n anim.frame = requestAnimationFrame(function (time) {\n return step(time, draw, start, rule, duration, end, anim);\n });\n } else {\n end && end();\n }\n}\n\n/**\n * Animation engine API for JavaScript-based animations.\n * This is simply an animation core framework which simplifies creation\n * of various animations for generic purposes.\n *\n * @example\n * // create 'linear' animation engine, 500ms duration\n * let linear = new Animation('linear', 500);\n *\n * // create 'elastic' animation engine\n * let elastic = new Animation('elastic');\n *\n * // define animation behavior\n * let bounced = new Animation('bounce', 500, percent => {\n * let value = parseInt(percent * 100, 10);\n *\n * $('div.bounced').css({\n * width: value + '%',\n * height: value + '%'\n * });\n * });\n *\n * // execute animation\n * bounced.animate();\n *\n * // execute animation and handle when its finished\n * bounced.animate(null, () => {\n * console.log('Animation finished!');\n * });\n */\n\nvar Animation = function () {\n\n /**\n * @constructor\n * @param {string|AnimationRule} rule\n * @param {number} duration\n * @param {DrawEventCallback} [draw]\n * @param {EndEventCallback} [end]\n */\n function Animation() {\n var rule = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'linear';\n var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 250;\n var draw = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};\n var end = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};\n\n _classCallCheck(this, Animation);\n\n /**\n * Overall animation duration in milliseconds.\n * By default is equal to 250 ms.\n *\n * @type {number}\n */\n this.duration = duration;\n\n /**\n * Animation rule. By default is linear animation.\n * Animation rule is a subject to animation rules, which are\n * a simple object containing math-based methods for calculating\n * animation steps.\n *\n * @type {string|AnimationRule}\n */\n this.rule = rule;\n\n /**\n * Callback function for the animation step draw event.\n *\n * @type {DrawEventCallback}\n */\n this.draw = draw;\n\n /**\n * Callback for the animation complete event.\n *\n * @type {EndEventCallback}\n */\n this.end = end;\n\n if (typeof this.draw !== 'function') {\n throw new TypeError('Invalid animation draw callback:', draw);\n }\n\n if (typeof this.end !== 'function') {\n throw new TypeError('Invalid animation end callback:', end);\n }\n }\n\n /* istanbul ignore next: non-testable */\n /**\n * Performs animation calling each animation step draw callback and\n * end callback at the end of animation. Callbacks are optional to this\n * method call. If them are not bypassed will be used that ones which\n * was pre-set on constructing an Animation object or pre-set after\n * construction.\n *\n * @example\n * function draw(percent) {\n * $('.my-animated-divs').css({\n * width: parseInt(percent * 100, 10) + '%'\n * });\n * }\n * function done() {\n * console.log('Animation complete!');\n * }\n *\n * // Define 'draw' and 'end' callbacks on construction\n * var animation = new Animation('cycle', 500, draw, done);\n * animation.animate();\n *\n * // Define 'draw' and 'end' callbacks after construction\n * var animation = new Animation('cycle', 500);\n * animation.draw = draw;\n * animation.end = done;\n * animation.animate();\n *\n * // Define 'draw' and 'end' callbacks at animation\n * var animation = new Animation('cycle', 500);\n * animation.animate(draw, done);\n *\n * @param {DrawEventCallback} [draw]\n * @param {EndEventCallback} [end]\n */\n\n\n _createClass(Animation, [{\n key: 'animate',\n value: function animate(draw, end) {\n var _this = this;\n\n //noinspection JSUnresolvedVariable\n var start = ns.performance && ns.performance.now ? ns.performance.now() : vendorize('animationStartTime') || Date.now();\n\n draw = draw || this.draw;\n end = end || this.end;\n\n /**\n * Current requested animation frame identifier\n *\n * @type {number}\n */\n this.frame = requestAnimationFrame(function (time) {\n return step(time, draw, start, rules[_this.rule] || _this.rule, _this.duration, end, _this);\n });\n }\n\n /**\n * Destroys this object properly\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n if (this.frame) {\n var cancelAnimationFrame = vendorize('cancelAnimationFrame') ||\n /* istanbul ignore next */\n function (id) {};\n\n cancelAnimationFrame(this.frame);\n this.frame = null;\n }\n\n this.draw = null;\n this.end = null;\n }\n }]);\n\n return Animation;\n}();\n\n/**\n * Animation rules bound statically to Animation constructor.\n *\n * @type {AnimationRules}\n * @static\n */\n\n\nAnimation.rules = rules;\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/**\n * @typedef {{ constructor: function(options: GenericOptions): GaugeInterface, draw: function(): GaugeInterface, destroy: function, update: function(options: GenericOptions) }} GaugeInterface\n */\n/**\n * @typedef {{parse: function, stringify: function}} JSON\n * @external {JSON} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON\n */\n/**\n * @ignore\n * @typedef {{MutationObserver: function}} ns\n */\n\n/**\n * DOM Observer.\n * It will observe DOM document for a configured element types and\n * instantiate associated Types for an existing or newly added DOM elements\n *\n * @example\n * class ProgressBar {\n * constructor(options) {}\n * draw() {}\n * }\n *\n * // It will observe DOM document for elements
\n * // having attribute 'data-type=\"progress\"'\n * // and instantiate for each new instance of ProgressBar\n *\n * new DomParser({color: 'red'}, 'div', 'progress', ProgressBar);\n *\n * // assume we could have HTML like this\n * //
\n * // in this case all matching attributes names for a given options will be\n * // parsed and bypassed to an instance from HTML attributes\n */\n\nvar DomObserver = function () {\n\n /**\n * @constructor\n * @param {object} options\n * @param {string} element\n * @param {string} type\n */\n function DomObserver(options, element, type) {\n _classCallCheck(this, DomObserver);\n\n //noinspection JSUnresolvedVariable\n /**\n * Default instantiation options for the given type\n *\n * @type {Object}\n */\n this.options = options;\n\n /**\n * Name of an element to lookup/observe\n *\n * @type {string}\n */\n this.element = element.toLowerCase();\n\n /**\n * data-type attribute value to lookup\n *\n * @type {string}\n */\n this.type = DomObserver.toDashed(type);\n\n /**\n * Actual type constructor to instantiate for each found element\n *\n * @type {Function}\n */\n this.Type = ns[type];\n\n /**\n * Signals if mutations observer for this type or not\n *\n * @type {boolean}\n */\n this.mutationsObserved = false;\n\n /**\n * Flag specifies whenever the browser supports observing\n * of DOM tree mutations or not\n *\n * @type {boolean}\n */\n this.isObservable = !!ns.MutationObserver;\n\n /* istanbul ignore next: this should be tested with end-to-end tests */\n DomObserver.domReady(this.traverse.bind(this));\n }\n\n /**\n * Checks if given node is valid node to process\n *\n * @param {Node|HTMLElement} node\n * @returns {boolean}\n */\n\n\n _createClass(DomObserver, [{\n key: 'isValidNode',\n value: function isValidNode(node) {\n //noinspection JSUnresolvedVariable\n return !!(node.tagName && node.tagName.toLowerCase() === this.element && node.getAttribute('data-type') === this.type);\n }\n\n /**\n * Traverse entire current DOM tree and process matching nodes.\n * Usually it should be called only once on document initialization.\n */\n\n }, {\n key: 'traverse',\n value: function traverse() {\n var elements = document.getElementsByTagName(this.element);\n var i = 0,\n s = elements.length;\n\n /* istanbul ignore next: this should be tested with end-to-end tests */\n for (; i < s; i++) {\n this.process(elements[i]);\n }\n\n if (this.isObservable && !this.mutationsObserved) {\n new ns.MutationObserver(this.observe.bind(this)).observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n attributeOldValue: true,\n characterDataOldValue: true\n });\n\n this.mutationsObserved = true;\n }\n }\n\n /**\n * Observes given mutation records for an elements to process\n *\n * @param {MutationRecord[]} records\n */\n\n }, {\n key: 'observe',\n value: function observe(records) {\n var i = 0;\n var s = records.length;\n\n /* istanbul ignore next: this should be tested with end-to-end tests */\n for (; i < s; i++) {\n var record = records[i];\n\n if (record.type === 'attributes' && record.attributeName === 'data-type' && this.isValidNode(record.target) && record.oldValue !== this.type) // skip false-positive mutations\n {\n setTimeout(this.process.bind(this, record.target));\n } else if (record.addedNodes && record.addedNodes.length) {\n var ii = 0;\n var ss = record.addedNodes.length;\n\n for (; ii < ss; ii++) {\n setTimeout(this.process.bind(this, record.addedNodes[ii]));\n }\n }\n }\n }\n\n /**\n * Parses given attribute value to a proper JavaScript value.\n * For example it will parse some stringified value to a proper type\n * value, e.g. 'true' => true, 'null' => null, '{\"prop\": 20}' => {prop: 20}\n *\n * @param {*} value\n * @return {*}\n */\n\n }, {\n key: 'process',\n\n\n /**\n * Processes a given node, instantiating a proper type constructor for it\n *\n * @param {Node|HTMLElement} node\n * @returns {GaugeInterface|null}\n */\n value: function process(node) {\n var _this2 = this;\n\n if (!this.isValidNode(node)) return null;\n\n var prop = void 0;\n var options = JSON.parse(JSON.stringify(this.options));\n var instance = null;\n\n for (prop in options) {\n /* istanbul ignore else: non-testable in most cases */\n if (options.hasOwnProperty(prop)) {\n var attributeName = DomObserver.toAttributeName(prop);\n var attributeValue = DomObserver.parse(node.getAttribute(attributeName));\n\n if (attributeValue !== null && attributeValue !== undefined) {\n options[prop] = attributeValue;\n }\n }\n }\n\n options.renderTo = node;\n instance = new this.Type(options);\n instance.draw && instance.draw();\n\n if (!this.isObservable) return instance;\n\n instance.observer = new ns.MutationObserver(function (records) {\n records.forEach(function (record) {\n if (record.type === 'attributes') {\n var attr = record.attributeName.toLowerCase();\n var type = node.getAttribute(attr).toLowerCase();\n\n if (attr === 'data-type' && type && type !== _this2.type) {\n instance.observer.disconnect();\n delete instance.observer;\n instance.destroy && instance.destroy();\n } else if (attr.substr(0, 5) === 'data-') {\n var _prop = attr.substr(5).split('-').map(function (part, i) {\n return !i ? part : part.charAt(0).toUpperCase() + part.substr(1);\n }).join('');\n var _options = {};\n\n _options[_prop] = DomObserver.parse(node.getAttribute(record.attributeName));\n\n instance.update && instance.update(_options);\n }\n }\n });\n });\n\n //noinspection JSCheckFunctionSignatures\n instance.observer.observe(node, { attributes: true });\n\n return instance;\n }\n\n /**\n * Transforms camelCase string to dashed string\n *\n * @static\n * @param {string} camelCase\n * @return {string}\n */\n\n }], [{\n key: 'parse',\n value: function parse(value) {\n // parse boolean\n if (value === 'true') return true;\n if (value === 'false') return false;\n\n // parse undefined\n if (value === 'undefined') return undefined;\n\n // parse null\n if (value === 'null') return null;\n\n // Comma-separated strings to array parsing.\n // It won't match strings which contains non alphanumeric characters to\n // prevent strings like 'rgba(0,0,0,0)' or JSON-like from being parsed.\n // Typically it simply allows easily declare arrays as comma-separated\n // numbers or plain strings. If something more complicated is\n // required it can be declared using JSON format syntax\n if (/^[-+#.\\w\\d\\s]+(?:,[-+#.\\w\\d\\s]*)+$/.test(value)) {\n return value.split(',');\n }\n\n // parse JSON\n try {\n return JSON.parse(value);\n } catch (e) {}\n\n // plain value - no need to parse\n return value;\n }\n }, {\n key: 'toDashed',\n value: function toDashed(camelCase) {\n var arr = camelCase.split(/(?=[A-Z])/);\n var i = 1;\n var s = arr.length;\n var str = arr[0].toLowerCase();\n\n for (; i < s; i++) {\n str += '-' + arr[i].toLowerCase();\n }\n\n return str;\n }\n\n /**\n * Transforms camel case property name to dash separated attribute name\n *\n * @static\n * @param {string} str\n * @returns {string}\n */\n\n }, {\n key: 'toAttributeName',\n value: function toAttributeName(str) {\n return 'data-' + DomObserver.toDashed(str);\n }\n\n /**\n * Cross-browser DOM ready handler\n *\n * @static\n * @param {Function} handler\n */\n\n }, {\n key: 'domReady',\n value: function domReady(handler) {\n if (/comp|inter|loaded/.test((ns.document || {}).readyState + '')) return handler();\n\n if (ns.addEventListener) ns.addEventListener('DOMContentLoaded', handler, false);else if (ns.attachEvent) ns.attachEvent('onload', handler);\n }\n }]);\n\n return DomObserver;\n}();\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n\n/**\n * Drawings on canvas using hidden canvas as a cache for better\n * performance drawings during canvas animations. SmartCanvas also\n * adopts a canvas to\n */\n\n\nvar SmartCanvas = function () {\n\n /**\n * @constructor\n * @param {HTMLCanvasElement} canvas\n * @param {number} [width]\n * @param {number} [height]\n */\n function SmartCanvas(canvas, width, height) {\n _classCallCheck(this, SmartCanvas);\n\n SmartCanvas.collection.push(this);\n\n /**\n * Canvas base width\n *\n * @type {number}\n */\n this.width = width || 0;\n\n /**\n * Canvas base height\n *\n * @type {number}\n */\n this.height = height || 0;\n\n /**\n * Target drawings canvas element\n *\n * @type {HTMLCanvasElement}\n */\n this.element = canvas;\n\n this.init();\n }\n\n /**\n * Initializes canvases and contexts\n */\n\n\n _createClass(SmartCanvas, [{\n key: 'init',\n value: function init() {\n var pixelRatio = SmartCanvas.pixelRatio;\n\n this.element.width = this.width * pixelRatio;\n this.element.height = this.height * pixelRatio;\n\n this.element.style.width = this.width + 'px';\n this.element.style.height = this.height + 'px';\n\n /**\n * Canvas caching element\n *\n * @type {HTMLCanvasElement|Node}\n */\n this.elementClone = this.element.cloneNode(true);\n\n //noinspection JSUnresolvedVariable\n /**\n * Target drawings canvas element 2D context\n *\n * @type {CanvasRenderingContext2D}\n */\n this.context = this.element.getContext('2d');\n\n /**\n * Canvas caching element 2D context\n *\n * @type {CanvasRenderingContext2D}\n */\n this.contextClone = this.elementClone.getContext('2d');\n\n /**\n * Actual drawings width\n *\n * @type {number}\n */\n this.drawWidth = this.element.width;\n\n /**\n * Actual drawings height\n *\n * @type {number}\n */\n this.drawHeight = this.element.height;\n\n /**\n * X-coordinate of drawings zero point\n *\n * @type {number}\n */\n this.drawX = this.drawWidth / 2;\n\n /**\n * Y-coordinate of drawings zero point\n *\n * @type {number}\n */\n this.drawY = this.drawHeight / 2;\n\n /**\n * Minimal side length in pixels of the drawing\n *\n * @type {number}\n */\n this.minSide = this.drawX < this.drawY ? this.drawX : this.drawY;\n\n this.elementClone.initialized = false;\n\n this.contextClone.translate(this.drawX, this.drawY);\n this.contextClone.save();\n\n this.context.translate(this.drawX, this.drawY);\n this.context.save();\n\n this.context.max = this.contextClone.max = this.minSide;\n this.context.maxRadius = this.contextClone.maxRadius = null;\n }\n\n /**\n * Destroys this object, removing the references from memory\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n var index = SmartCanvas.collection.indexOf(this);\n\n /* istanbul ignore else */\n if (~index) {\n SmartCanvas.collection.splice(index, 1);\n }\n\n this.context.clearRect(-this.drawX, -this.drawY, this.drawWidth, this.drawHeight);\n\n // dereference all created elements\n this.context.max = null;\n delete this.context.max;\n\n this.context.maxRadius = null;\n delete this.context.maxRadius;\n\n this.context = null;\n this.contextClone = null;\n this.elementClone = null;\n this.element = null;\n\n /**\n * On canvas redraw event callback\n *\n * @type {function|null|undefined}\n */\n this.onRedraw = null;\n }\n\n /**\n * Commits the drawings\n */\n\n }, {\n key: 'commit',\n value: function commit() {\n var scale = SmartCanvas.pixelRatio;\n\n if (scale !== 1) {\n this.contextClone.scale(scale, scale);\n this.contextClone.save();\n }\n\n return this;\n }\n\n /**\n * Redraw this object\n */\n\n }, {\n key: 'redraw',\n value: function redraw() {\n this.init();\n\n /**\n * On canvas redraw event callback\n *\n * @type {function(): *}\n */\n this.onRedraw && this.onRedraw();\n\n return this;\n }\n\n /**\n * Returns current device pixel ratio\n *\n * @returns {number}\n */\n\n }], [{\n key: 'redraw',\n\n\n /**\n * Forces redraw all canvas in the current collection\n */\n value: function redraw() {\n var i = 0;\n var s = SmartCanvas.collection.length;\n\n for (; i < s; i++) {\n SmartCanvas.collection[i].redraw();\n }\n }\n }, {\n key: 'pixelRatio',\n get: function get() {\n /* istanbul ignore next */\n //noinspection JSUnresolvedVariable\n return ns.devicePixelRatio || 1;\n }\n }]);\n\n return SmartCanvas;\n}();\n\nSmartCanvas.collection = [];\n\n/* istanbul ignore next: very browser-specific testing required to cover */\n//noinspection JSUnresolvedVariable\nif (ns.matchMedia) {\n //noinspection JSUnresolvedFunction\n ns.matchMedia('screen and (min-resolution: 2dppx)').addListener(SmartCanvas.redraw);\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Describes rendering target element. Can be either string identifier of\n * the element or the element itself.\n *\n * @typedef {HTMLElement|string} RenderTarget\n */\n\n/**\n * Highlight area definition.\n * It describes highlight area starting from value to value using\n * color. Color can be describes with hex, rgb or rgba value.\n *\n * @typedef {{ from: number, to: number, color: string}} Highlight\n */\n\n/**\n * Shared generic gauges options\n *\n * @type {{renderTo: RenderTarget, width: number, height: number, minValue: number, maxValue: number, value: number, units: string|boolean, majorTicks: number[]|string[], minorTicks: number, strokeTicks: boolean, animatedValue: boolean, animateOnInit: boolean, title: string|boolean, borders: boolean, valueInt: number, valueDec: number, majorTicksInt: number, majorTicksDec: number, animation: boolean, animationDuration: number, animationRule: string|AnimationRule, colorPlate: string, colorPlateEnd: string, colorMajorTicks: string, colorMinorTicks: string, colorTitle: string, colorUnits: string, colorNumbers: string, colorNeedle: string, colorNeedleEnd: string, colorValueText: string, colorValueTextShadow: string, colorBorderShadow: string, colorBorderOuter: string, colorBorderOuterEnd: string, colorBorderMiddle: string, colorBorderMiddleEnd: string, colorBorderInner: string, colorBorderInnerEnd: string, colorValueBoxRect: string, colorValueBoxRectEnd: string, colorValueBoxBackground: string, colorValueBoxShadow: string, colorNeedleShadowUp: string, colorNeedleShadowDown: string, needle: boolean, needleShadow: boolean, needleType: string, needleStart: number, needleEnd: number, needleWidth: number, borderOuterWidth: number, borderMiddleWidth: number, borderInnerWidth: number, borderShadowWidth: number, valueBox: boolean, valueBoxWidth: number, valueBoxStroke: number, valueText: string, valueTextShadow: boolean, valueBoxBorderRadius: number, highlights: Highlight[], highlightsWidth: number, fontNumbers: string, fontTitle: string, fontUnits: string, fontValue: string, fontTitleSize: number, fontValueSize: number, fontUnitsSize: number, fontNumbersSize: number, fontNumbersStyle: string, fontTitleStyle: string, fontUnitsStyle: string, fontValueStyle: string, fontNumbersWeight: string, fontTitleWeight: string, fontUnitsWeight: string, fontValueWeight: string}} GenericOptions\n */\nvar GenericOptions = {\n // basic options\n renderTo: null,\n width: 0,\n height: 0,\n minValue: 0,\n maxValue: 100,\n value: 0,\n units: false,\n majorTicks: [0, 20, 40, 60, 80, 100],\n minorTicks: 10,\n strokeTicks: true,\n animatedValue: false,\n animateOnInit: false,\n title: false,\n borders: true,\n\n // number formats\n valueInt: 3,\n valueDec: 2,\n majorTicksInt: 1,\n majorTicksDec: 0,\n\n // animations\n animation: true,\n animationDuration: 500,\n animationRule: 'cycle',\n\n // colors\n colorPlate: '#fff',\n colorPlateEnd: '',\n colorMajorTicks: '#444',\n colorMinorTicks: '#666',\n colorTitle: '#888',\n colorUnits: '#888',\n colorNumbers: '#444',\n colorNeedle: 'rgba(240,128,128,1)',\n colorNeedleEnd: 'rgba(255,160,122,.9)',\n colorValueText: '#444',\n colorValueTextShadow: 'rgba(0,0,0,0.3)',\n colorBorderShadow: 'rgba(0,0,0,0.5)',\n colorBorderOuter: '#ddd',\n colorBorderOuterEnd: '#aaa',\n colorBorderMiddle: '#eee',\n colorBorderMiddleEnd: '#f0f0f0',\n colorBorderInner: '#fafafa',\n colorBorderInnerEnd: '#ccc',\n colorValueBoxRect: '#888',\n colorValueBoxRectEnd: '#666',\n colorValueBoxBackground: '#babab2',\n colorValueBoxShadow: 'rgba(0,0,0,1)',\n colorNeedleShadowUp: 'rgba(2,255,255,0.2)',\n colorNeedleShadowDown: 'rgba(188,143,143,0.45)',\n\n fontNumbers: 'Arial',\n fontTitle: 'Arial',\n fontUnits: 'Arial',\n fontValue: 'Arial',\n\n fontNumbersSize: 20,\n fontTitleSize: 24,\n fontUnitsSize: 22,\n fontValueSize: 40,\n\n fontNumbersStyle: 'normal',\n fontTitleStyle: 'normal',\n fontUnitsStyle: 'normal',\n fontValueStyle: 'normal',\n\n fontNumbersWeight: 'normal',\n fontTitleWeight: 'normal',\n fontUnitsWeight: 'normal',\n fontValueWeight: 'normal',\n\n // needle\n needle: true,\n needleShadow: true,\n needleType: 'arrow',\n needleStart: 5,\n needleEnd: 85,\n needleWidth: 4,\n\n // borders\n borderOuterWidth: 3,\n borderMiddleWidth: 3,\n borderInnerWidth: 3,\n borderShadowWidth: 3,\n\n // value and highlights\n valueBox: true,\n valueBoxStroke: 5,\n valueBoxWidth: 0,\n valueText: '',\n valueTextShadow: true,\n valueBoxBorderRadius: 2.5,\n\n // highlights\n highlights: [{ from: 20, to: 60, color: '#eee' }, { from: 60, to: 80, color: '#ccc' }, { from: 80, to: 100, color: '#999' }],\n highlightsWidth: 15\n};\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Gauge collections type.\n *\n * It is used ES5 declaration here, because babel\n * transpiles inheritance incorrectly in this case.\n *\n * @class Collection\n * @constructor\n */\nfunction Collection() {\n Array.prototype.constructor.apply(this, arguments);\n}\n\nCollection.prototype = Object.create(Array.prototype);\nCollection.prototype.constructor = Collection;\n\n/**\n * Returns gauge object by its identifier or index in the collection\n *\n * @param {string|number} id\n * @return {*}\n */\nCollection.prototype.get = function (id) {\n if (typeof id === 'string') {\n var i = 0;\n var s = this.length;\n\n for (; i < s; i++) {\n var canvas = this[i].options.renderTo.tagName ? this[i].options.renderTo :\n /* istanbul ignore next: should be tested with e2e tests */\n document.getElementById(this[i].options.renderTo || '');\n\n if (canvas.getAttribute('id') === id) {\n return this[i];\n }\n }\n } else if (typeof id === 'number') {\n return this[id];\n }\n\n return null;\n};\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nvar version = '2.0.9';\n\nvar round = Math.round;\nvar abs = Math.abs;\n\nvar gauges = new Collection();\n\ngauges.version = version;\n\n/**\n * Basic abstract BaseGauge class implementing common functionality\n * for different type of gauges.\n *\n * It should not be instantiated directly but must be extended by a final\n * gauge implementation.\n *\n * @abstract\n * @example\n *\n * class MyCoolGauge extends BaseGauge {\n *\n * // theses methods below MUST be implemented:\n *\n * constructor(options) {\n * // ... do something with options\n * super(options);\n * // ... implement anything else\n * }\n *\n * draw() {\n * // ... some implementation here\n * return this;\n * }\n * }\n */\n\nvar BaseGauge = function () {\n\n /**\n * @constructor\n * @abstract\n * @param {GenericOptions} options\n */\n function BaseGauge(options) {\n _classCallCheck(this, BaseGauge);\n\n var className = this.constructor.name;\n\n if (className === 'BaseGauge') {\n throw new TypeError('Attempt to instantiate abstract class!');\n }\n\n gauges.push(this);\n\n //noinspection JSUnresolvedVariable\n /**\n * Gauges version string\n *\n * @type {string}\n */\n this.version = version;\n\n /**\n * Gauge type class\n *\n * @type {BaseGauge} type\n */\n this.type = ns[className];\n\n /**\n * True if gauge has been drawn for the first time, false otherwise.\n *\n * @type {boolean}\n */\n this.initialized = false;\n\n options.minValue = parseFloat(options.minValue);\n options.maxValue = parseFloat(options.maxValue);\n options.value = parseFloat(options.value) || 0;\n\n if (!options.borders) {\n options.borderInnerWidth = options.borderMiddleWidth = options.borderOuterWidth = 0;\n }\n\n if (!options.renderTo) {\n throw TypeError('Canvas element was not specified when creating ' + 'the Gauge object!');\n }\n\n var canvas = options.renderTo.tagName ? options.renderTo :\n /* istanbul ignore next: to be tested with e2e tests */\n document.getElementById(options.renderTo);\n\n if (!(canvas instanceof HTMLCanvasElement)) {\n throw TypeError('Given gauge canvas element is invalid!');\n }\n\n options.width = parseFloat(options.width) || 0;\n options.height = parseFloat(options.height) || 0;\n\n if (!options.width || !options.height) {\n if (!options.width) options.width = canvas.parentNode ? canvas.parentNode.offsetWidth : canvas.offsetWidth;\n if (!options.height) options.height = canvas.parentNode ? canvas.parentNode.offsetHeight : canvas.offsetHeight;\n }\n\n /**\n * Gauge options\n *\n * @type {GenericOptions} options\n */\n this.options = options || {};\n\n if (this.options.animateOnInit) {\n this._value = this.options.value;\n this.options.value = this.options.minValue;\n }\n\n /**\n * @type {SmartCanvas} canvas\n */\n this.canvas = new SmartCanvas(canvas, options.width, options.height);\n this.canvas.onRedraw = this.draw.bind(this);\n\n /**\n * @type {Animation} animation\n */\n this.animation = new Animation(options.animationRule, options.animationDuration);\n }\n\n /**\n * Sets new value for this gauge.\n * If gauge is animated by configuration it will trigger a proper animation.\n * Upsetting a value triggers gauge redraw.\n *\n * @param {number} value\n */\n\n\n _createClass(BaseGauge, [{\n key: 'update',\n\n\n /**\n * Updates gauge configuration options at runtime and redraws the gauge\n *\n * @param {RadialGaugeOptions} options\n * @returns {BaseGauge}\n */\n value: function update(options) {\n Object.assign(this.options, options || {});\n\n this.canvas.width = this.options.width;\n this.canvas.height = this.options.height;\n\n this.animation.rule = this.options.animationRule;\n this.animation.duration = this.options.animationDuration;\n\n this.canvas.redraw();\n\n return this;\n }\n\n /**\n * Performs destruction of this object properly\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n var index = gauges.indexOf(this);\n\n /* istanbul ignore else */\n if (~index) {\n //noinspection JSUnresolvedFunction\n gauges.splice(index, 1);\n }\n\n this.canvas.destroy();\n this.canvas = null;\n\n this.animation.destroy();\n this.animation = null;\n }\n\n /**\n * Returns gauges version string\n *\n * @return {string}\n */\n\n }, {\n key: 'draw',\n\n\n /**\n * Triggering gauge render on a canvas.\n *\n * @abstract\n * @returns {BaseGauge}\n */\n value: function draw() {\n if (this.options.animateOnInit && !this.initialized) {\n this.value = this._value;\n this.initialized = true;\n }\n }\n\n /**\n * Inject given gauge object into DOM\n *\n * @param {string} type\n * @param {GenericOptions} options\n */\n\n }, {\n key: 'value',\n set: function set(value) {\n var _this3 = this;\n\n value = parseFloat(value);\n\n if (isNaN(value) || !isFinite(value)) {\n value = this.options.minValue;\n }\n\n var fromValue = this.options.value;\n\n if (value === this.options.value) return;\n\n if (this.options.animation) {\n /**\n * @type {number}\n * @access private\n */\n this._value = value;\n\n this.animation.animate(function (percent) {\n _this3.options.value = fromValue + (value - fromValue) * percent;\n\n _this3.draw();\n }, function () {\n _this3.options.value = value;\n delete _this3._value;\n _this3.draw();\n });\n } else {\n this.options.value = value;\n this.draw();\n }\n }\n\n /**\n * Returns current value of the gauge\n *\n * @return {number}\n */\n ,\n get: function get() {\n return typeof this._value === 'undefined' ? this.options.value : this._value;\n }\n }], [{\n key: 'initialize',\n value: function initialize(type, options) {\n new DomObserver(options, 'canvas', type);\n }\n }, {\n key: 'version',\n get: function get() {\n return version;\n }\n }]);\n\n return BaseGauge;\n}();\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n/* istanbul ignore if */\n\n\nif (typeof ns !== 'undefined') {\n ns['BaseGauge'] = BaseGauge;\n (ns.document || ns)['gauges'] = gauges;\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @access private\n * @typedef {CanvasRenderingContext2D|{max: number, maxRadius: number, barDimensions: object}} Canvas2DContext\n */\n\n/* istanbul ignore next: private, not testable */\n/**\n * Examines if a given error is something to throw or to ignore\n *\n * @param {Error} err\n */\nfunction verifyError(err) {\n // there is some unpredictable error in FF in some circumstances\n // which we found simply safe to ignore than to fight with it\n // noinspection JSUnresolvedVariable\n if (err instanceof DOMException && err.result === 0x8053000b) {\n return; // ignore it\n }\n\n throw err;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Prepares major ticks data\n *\n * @access private\n * @param {GenericOptions|{ tickSide: string }} options\n * @return {[boolean, boolean]}\n */\nfunction prepareTicks(options) {\n if (!(options.majorTicks instanceof Array)) {\n options.majorTicks = options.majorTicks ? [options.majorTicks] : [];\n }\n\n if (!options.majorTicks.length) {\n options.majorTicks.push(drawings.formatMajorTickNumber(options.minValue, options));\n options.majorTicks.push(drawings.formatMajorTickNumber(options.maxValue, options));\n }\n\n return [options.tickSide !== 'right', options.tickSide !== 'left'];\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws rounded corners rectangle\n *\n * @param {Canvas2DContext} context\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {number} r\n */\nfunction roundRect(context, x, y, w, h, r) {\n context.beginPath();\n\n context.moveTo(x + r, y);\n context.lineTo(x + w - r, y);\n\n context.quadraticCurveTo(x + w, y, x + w, y + r);\n context.lineTo(x + w, y + h - r);\n\n context.quadraticCurveTo(x + w, y + h, x + w - r, y + h);\n context.lineTo(x + r, y + h);\n\n context.quadraticCurveTo(x, y + h, x, y + h - r);\n context.lineTo(x, y + r);\n\n context.quadraticCurveTo(x, y, x + r, y);\n\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Pads a given value with leading zeros using the given options\n *\n * @param {number} val\n * @param {RadialGaugeOptions|{valueInt: number, valueDec: number}} options\n * @returns {string}\n */\nfunction padValue(val, options) {\n var dec = options.valueDec;\n var int = options.valueInt;\n var i = 0;\n var s = void 0,\n strVal = void 0,\n n = void 0;\n\n val = parseFloat(val);\n n = val < 0;\n val = Math.abs(val);\n\n if (dec > 0) {\n strVal = val.toFixed(dec).toString().split('.');\n s = int - strVal[0].length;\n\n for (; i < s; ++i) {\n strVal[0] = '0' + strVal[0];\n }\n\n strVal = (n ? '-' : '') + strVal[0] + '.' + strVal[1];\n } else {\n strVal = Math.round(val).toString();\n s = int - strVal.length;\n\n for (; i < s; ++i) {\n strVal = '0' + strVal;\n }\n\n strVal = (n ? '-' : '') + strVal;\n }\n\n return strVal;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Formats a number for display on the dial's plate using the majorTicksFormat\n * config option.\n *\n * @param {number} num number to format\n * @param {object} options\n * @returns {string} formatted number\n */\nfunction formatMajorTickNumber(num, options) {\n var right = void 0,\n hasDec = false;\n\n // First, force the correct number of digits right of the decimal.\n if (options.majorTicksDec === 0) {\n right = Math.round(num).toString();\n } else {\n right = num.toFixed(options.majorTicksDec);\n }\n\n // Second, force the correct number of digits left of the decimal.\n if (options.majorTicksInt > 1) {\n // Does this number have a decimal?\n hasDec = ~right.indexOf('.');\n\n // Is this number a negative number?\n if (~right.indexOf('-')) {\n return '-' + [options.majorTicksInt + options.majorTicksDec + 2 + (hasDec ? 1 : 0) - right.length].join('0') + right.replace('-', '');\n } else {\n return [options.majorTicksInt + options.majorTicksDec + 1 + (hasDec ? 1 : 0) - right.length].join('0') + right;\n }\n }\n\n return right;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Transforms degrees to radians\n *\n * @param {number} degrees\n * @returns {number}\n */\nfunction radians(degrees) {\n return degrees * Math.PI / 180;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Calculates and returns radial point coordinates\n *\n * @param {number} radius\n * @param {number} angle\n * @returns {{x: number, y: number}}\n */\nfunction radialPoint(radius, angle) {\n return { x: -radius * Math.sin(angle), y: radius * Math.cos(angle) };\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Creates and returns linear gradient canvas object\n *\n * @param {Canvas2DContext} context\n * @param {string} colorFrom\n * @param {string} colorTo\n * @param {number} length\n * @param {boolean} [isVertical]\n * @param {number} [from]\n * @returns {CanvasGradient}\n */\nfunction linearGradient(context, colorFrom, colorTo, length) {\n var isVertical = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;\n var from = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;\n\n var grad = context.createLinearGradient(isVertical ? 0 : from, isVertical ? from : 0, isVertical ? 0 : length, isVertical ? length : 0);\n\n grad.addColorStop(0, colorFrom);\n grad.addColorStop(1, colorTo);\n\n return grad;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws the shadow if it was not drawn\n *\n * @param {Canvas2DContext} context\n * @param {GenericOptions} options\n * @param {boolean} shadowDrawn\n * @return {boolean}\n */\nfunction drawShadow(context, options) {\n var shadowDrawn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n if (shadowDrawn) {\n context.restore();\n return true;\n }\n\n context.save();\n\n var w = options.borderShadowWidth;\n\n if (w) {\n context.shadowBlur = w;\n context.shadowColor = options.colorBorderShadow;\n }\n\n return true;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge needle shadow\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawNeedleShadow(context, options) {\n if (!options.needleShadow) return;\n\n context.shadowOffsetX = 2;\n context.shadowOffsetY = 2;\n context.shadowBlur = 10;\n context.shadowColor = options.colorNeedleShadowDown;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Constructs font styles for canvas fonts\n *\n * @param {GenericOptions} options\n * @param {string} target\n * @param {number} baseSize\n */\nfunction font(options, target, baseSize) {\n return options['font' + target + 'Style'] + ' ' + options['font' + target + 'Weight'] + ' ' + options['font' + target + 'Size'] * baseSize + 'px ' + options['font' + target];\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws value box at given position\n *\n * @param {Canvas2DContext} context\n * @param {GenericOptions} options\n * @param {number|string} value\n * @param {number} x\n * @param {number} y\n * @param {number} max\n */\nfunction drawValueBox(context, options, value, x, y, max) {\n if (!options.valueBox) return;\n\n var text = options.valueText || padValue(value, options);\n\n context.shadowOffsetX = null;\n context.shadowOffsetY = null;\n context.shadowBlur = null;\n context.shadowColor = '';\n context.strokeStyle = null;\n context.lineWidth = 0;\n context.save();\n\n context.font = font(options, 'Value', max / 200);\n context.save();\n context.beginPath();\n\n var th = 0.12 * max;\n var bs = parseFloat(options.valueBoxStroke) || 0;\n var bmax = max * 2 - bs * 2;\n var tw = context.measureText(options.valueText ? text : '-' + padValue(0, options)).width;\n var bw = tw + 0.05 * max;\n var bh = th + 0.07 * max;\n var br = max * options.valueBoxBorderRadius / 100;\n var obw = (parseFloat(options.valueBoxWidth) || 0) / 100 * bmax;\n\n obw > bw && (bw = obw);\n bw > bmax && (bw = bmax);\n\n var bx = x - bw / 2;\n var by = y - th - 0.04 * max;\n\n if (br) roundRect(context, bx, by, bw, bh, br);else context.rect(bx, by, bw, bh);\n\n var gy = y - 0.12 * max - 0.025 * max + (0.12 * max + 0.045 * max) / 2;\n\n if (options.valueBoxStroke) {\n var grd = context.createRadialGradient(x, gy, max / 10, x, gy, max / 5);\n\n grd.addColorStop(0, options.colorValueBoxRect);\n grd.addColorStop(1, options.colorValueBoxRectEnd);\n\n context.strokeStyle = grd;\n context.lineWidth = max * options.valueBoxStroke / 100;\n context.stroke();\n }\n\n if (options.colorValueBoxShadow) {\n context.shadowBlur = 0.012 * max;\n context.shadowColor = options.colorValueBoxShadow;\n }\n\n if (options.colorValueBoxBackground) {\n context.fillStyle = options.colorValueBoxBackground;\n context.fill();\n }\n\n context.closePath();\n context.restore();\n\n if (options.valueTextShadow) {\n context.shadowOffsetX = 0.004 * max;\n context.shadowOffsetY = 0.004 * max;\n context.shadowBlur = 0.012 * max;\n context.shadowColor = options.colorValueTextShadow;\n }\n\n context.fillStyle = options.colorValueText;\n context.textAlign = 'center';\n context.fillText(text, bx + bw / 2, y);\n context.restore();\n}\n\nvar drawings = {\n roundRect: roundRect,\n padValue: padValue,\n formatMajorTickNumber: formatMajorTickNumber,\n radians: radians,\n radialPoint: radialPoint,\n linearGradient: linearGradient,\n drawNeedleShadow: drawNeedleShadow,\n drawValueBox: drawValueBox,\n verifyError: verifyError,\n prepareTicks: prepareTicks,\n drawShadow: drawShadow,\n font: font\n};\n\ndrawings;\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nvar PI = Math.PI;\nvar HPI = PI / 2;\n\n/**\n * Gauge configuration options\n *\n * @typedef {GenericOptions|{ticksAngle: number, startAngle: number, colorNeedleCircleOuter: string, colorNeedleCircleOuterEnd: string, colorNeedleCircleInner: string, colorNeedleCircleInnerEnd: string, needleCircleSize: number, needleCircleInner: boolean, needleCircleOuter: boolean, animationTarget: string}} RadialGaugeOptions\n */\n\n/**\n * Default gauge configuration options\n *\n * @access private\n * @type {RadialGaugeOptions}\n */\nvar defaultRadialGaugeOptions = Object.assign({}, GenericOptions, {\n // basic options\n ticksAngle: 270,\n startAngle: 45,\n\n // colors\n colorNeedleCircleOuter: '#f0f0f0',\n colorNeedleCircleOuterEnd: '#ccc',\n colorNeedleCircleInner: '#e8e8e8',\n colorNeedleCircleInnerEnd: '#f5f5f5',\n\n // needle\n needleCircleSize: 10,\n needleCircleInner: true,\n needleCircleOuter: true,\n\n // custom animations\n animationTarget: 'needle' // 'needle' or 'plate'\n});\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gradient-filled circle on a canvas\n *\n * @access private\n * @param {number} radius\n * @param {number} width\n * @param {Canvas2DContext} context\n * @param {string} start gradient start color\n * @param {string} end gradient end color\n */\nfunction drawRadialBorder(radius, width, context, start, end) {\n context.beginPath();\n //noinspection JSUnresolvedFunction\n context.arc(0, 0, abs(radius), 0, PI * 2, true);\n context.lineWidth = width;\n context.strokeStyle = end ? drawings.linearGradient(context, start, end, radius) : start;\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Returns max radius without borders for the gauge\n *\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n * @return {number}\n */\nfunction maxRadialRadius(context, options) {\n if (!context.maxRadius) {\n context.maxRadius = context.max - options.borderShadowWidth - options.borderOuterWidth - options.borderMiddleWidth - options.borderInnerWidth + (options.borderOuterWidth ? 0.5 : 0) + (options.borderMiddleWidth ? 0.5 : 0) + (options.borderInnerWidth ? 0.5 : 0);\n }\n\n return context.maxRadius;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge plate on the canvas\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialPlate(context, options) {\n var d0 = options.borderShadowWidth;\n var r0 = context.max - d0 - options.borderOuterWidth / 2;\n var r1 = r0 - options.borderOuterWidth / 2 - options.borderMiddleWidth / 2 + 0.5;\n var r2 = r1 - options.borderMiddleWidth / 2 - options.borderInnerWidth / 2 + 0.5;\n var r3 = maxRadialRadius(context, options);\n var grad = void 0;\n var shadowDrawn = false;\n\n context.save();\n\n if (options.borderOuterWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawRadialBorder(r0, options.borderOuterWidth, context, options.colorBorderOuter, options.colorBorderOuterEnd);\n }\n\n if (options.borderMiddleWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawRadialBorder(r1, options.borderMiddleWidth, context, options.colorBorderMiddle, options.colorBorderMiddleEnd);\n }\n\n if (options.borderInnerWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawRadialBorder(r2, options.borderInnerWidth, context, options.colorBorderInner, options.colorBorderInnerEnd);\n }\n\n drawings.drawShadow(context, options, shadowDrawn);\n\n context.beginPath();\n //noinspection JSUnresolvedFunction\n context.arc(0, 0, abs(r3), 0, PI * 2, true);\n\n if (options.colorPlateEnd) {\n grad = context.createRadialGradient(0, 0, r3 / 2, 0, 0, r3);\n grad.addColorStop(0, options.colorPlate);\n grad.addColorStop(1, options.colorPlateEnd);\n } else {\n grad = options.colorPlate;\n }\n\n context.fillStyle = grad;\n\n context.fill();\n context.closePath();\n\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge highlight areas on a canvas\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialHighlights(context, options) {\n var hlWidth = context.max * (parseFloat(options.highlightsWidth) || 0) / 100;\n\n if (!hlWidth) return;\n\n //noinspection JSUnresolvedFunction\n var r = abs(radialTicksRadius(context, options) - hlWidth / 2);\n var i = 0,\n s = options.highlights.length;\n var vd = (options.maxValue - options.minValue) / options.ticksAngle;\n\n context.save();\n\n for (; i < s; i++) {\n var hlt = options.highlights[i];\n\n context.beginPath();\n\n context.rotate(HPI);\n context.arc(0, 0, r, drawings.radians(options.startAngle + (hlt.from - options.minValue) / vd), drawings.radians(options.startAngle + (hlt.to - options.minValue) / vd), false);\n context.strokeStyle = hlt.color;\n context.lineWidth = hlWidth;\n context.stroke();\n context.closePath();\n\n context.restore();\n context.save();\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws minor ticks bar on a canvas\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialMinorTicks(context, options) {\n var radius = radialTicksRadius(context, options);\n\n context.lineWidth = SmartCanvas.pixelRatio;\n context.strokeStyle = options.colorMinorTicks;\n\n context.save();\n\n var s = options.minorTicks * (options.majorTicks.length - 1);\n var i = 0;\n\n for (; i < s; ++i) {\n var angle = options.startAngle + i * (options.ticksAngle / s);\n\n context.rotate(drawings.radians(angle));\n\n context.beginPath();\n context.moveTo(0, radius);\n context.lineTo(0, radius - context.max * 0.075);\n closeStrokedPath(context);\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Returns ticks radius\n *\n * @access private\n * @param context\n * @param options\n * @return {number}\n */\nfunction radialTicksRadius(context, options) {\n return maxRadialRadius(context, options) - context.max * 0.05;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge major ticks bar on a canvas\n *\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialMajorTicks(context, options) {\n drawings.prepareTicks(options);\n\n //noinspection JSUnresolvedFunction\n var r = abs(radialTicksRadius(context, options));\n var i = void 0,\n colors = void 0;\n var s = options.majorTicks.length;\n var pixelRatio = SmartCanvas.pixelRatio;\n\n context.lineWidth = 2 * pixelRatio;\n context.save();\n\n colors = options.colorMajorTicks instanceof Array ? options.colorMajorTicks : new Array(s).fill(options.colorMajorTicks);\n\n i = 0;\n for (; i < s; ++i) {\n context.strokeStyle = colors[i];\n context.rotate(drawings.radians(radialNextAngle(options, i, s)));\n\n context.beginPath();\n context.moveTo(0, r);\n context.lineTo(0, r - context.max * 0.15);\n closeStrokedPath(context);\n }\n\n if (options.strokeTicks) {\n context.strokeStyle = colors[0];\n context.rotate(HPI);\n\n context.beginPath();\n context.arc(0, 0, r, drawings.radians(options.startAngle), drawings.radians(options.startAngle + options.ticksAngle), false);\n closeStrokedPath(context);\n }\n}\n\n/* istanbul ignore next: private, not testable */\nfunction radialNextAngle(options, i, s) {\n return options.startAngle + i * (options.ticksAngle / (s - 1));\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Strokes, closes path and restores previous context state\n *\n * @param {Canvas2DContext} context\n */\nfunction closeStrokedPath(context) {\n context.stroke();\n context.restore();\n context.closePath();\n context.save();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge bar numbers\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialNumbers(context, options) {\n var radius = maxRadialRadius(context, options) - context.max * 0.35;\n var points = {};\n var i = 0;\n var s = options.majorTicks.length;\n var isAnimated = options.animationTarget !== 'needle';\n var colors = options.colorNumbers instanceof Array ? options.colorNumbers : new Array(s).fill(options.colorNumbers);\n\n var plateValueAngle = isAnimated ? -(options.value - options.minValue) / (options.maxValue - options.minValue) * options.ticksAngle : 0;\n\n if (isAnimated) {\n context.save();\n context.rotate(-drawings.radians(plateValueAngle));\n }\n\n for (; i < s; ++i) {\n var angle = plateValueAngle + radialNextAngle(options, i, s);\n var point = drawings.radialPoint(radius, drawings.radians(angle));\n\n if (angle === 360) angle = 0;\n\n if (points[angle]) {\n continue; //already drawn at this place, skipping\n }\n\n points[angle] = true;\n\n context.font = drawings.font(options, 'Numbers', context.max / 200);\n context.fillStyle = colors[i];\n context.lineWidth = 0;\n context.textAlign = 'center';\n context.fillText(options.majorTicks[i], point.x, point.y + 3);\n }\n\n isAnimated && context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge title\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialTitle(context, options) {\n if (!options.title) return;\n\n context.save();\n context.font = drawings.font(options, 'Title', context.max / 200);\n context.fillStyle = options.colorTitle;\n context.textAlign = 'center';\n context.fillText(options.title, 0, -context.max / 4.25, context.max * 0.8);\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws units name on the gauge\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialUnits(context, options) {\n if (!options.units) return;\n\n context.save();\n context.font = drawings.font(options, 'Units', context.max / 200);\n context.fillStyle = options.colorUnits;\n context.textAlign = 'center';\n context.fillText(options.units, 0, context.max / 3.25, context.max * 0.8);\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge needle\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialNeedle(context, options) {\n if (!options.needle) return;\n\n var value = options.value;\n var max = maxRadialRadius(context, options);\n //noinspection JSUnresolvedFunction\n var r1 = abs(max / 100 * options.needleCircleSize);\n //noinspection JSUnresolvedFunction\n var r2 = abs(max / 100 * options.needleCircleSize * 0.75);\n //noinspection JSUnresolvedFunction\n var rIn = abs(max / 100 * options.needleEnd);\n //noinspection JSUnresolvedFunction\n var rStart = abs(options.needleStart ? max / 100 * options.needleStart : 0);\n //noinspection JSUnresolvedFunction\n var rOut = abs(max * 0.2);\n var pad1 = max / 100 * options.needleWidth;\n var pad2 = max / 100 * options.needleWidth / 2;\n var pixelRatio = SmartCanvas.pixelRatio;\n var isFixed = options.animationTarget !== 'needle';\n\n context.save();\n\n drawings.drawNeedleShadow(context, options);\n\n context.rotate(drawings.radians(isFixed ? options.startAngle : options.startAngle + (value - options.minValue) / (options.maxValue - options.minValue) * options.ticksAngle));\n\n context.fillStyle = drawings.linearGradient(context, options.colorNeedle, options.colorNeedleEnd, rIn - rOut);\n\n if (options.needleType === 'arrow') {\n context.beginPath();\n context.moveTo(-pad2, -rOut);\n context.lineTo(-pad1, 0);\n context.lineTo(-1 * pixelRatio, rIn);\n context.lineTo(pixelRatio, rIn);\n context.lineTo(pad1, 0);\n context.lineTo(pad2, -rOut);\n context.closePath();\n context.fill();\n\n context.beginPath();\n context.lineTo(-0.5 * pixelRatio, rIn);\n context.lineTo(-1 * pixelRatio, rIn);\n context.lineTo(-pad1, 0);\n context.lineTo(-pad2, -rOut);\n context.lineTo(pad2 / 2 * pixelRatio - 2 * pixelRatio, -rOut);\n context.closePath();\n context.fillStyle = options.colorNeedleShadowUp;\n context.fill();\n } else {\n // simple line needle\n context.beginPath();\n context.moveTo(-pad2, rIn);\n context.lineTo(-pad2, rStart);\n context.lineTo(pad2, rStart);\n context.lineTo(pad2, rIn);\n context.closePath();\n context.fill();\n }\n\n if (options.needleCircleSize) {\n context.restore();\n\n drawings.drawNeedleShadow(context, options);\n\n if (options.needleCircleOuter) {\n context.beginPath();\n context.arc(0, 0, r1, 0, PI * 2, true);\n context.fillStyle = drawings.linearGradient(context, options.colorNeedleCircleOuter, options.colorNeedleCircleOuterEnd, r1);\n context.fill();\n context.closePath();\n }\n\n if (options.needleCircleInner) {\n context.beginPath();\n context.arc(0, 0, r2, 0, PI * 2, true);\n context.fillStyle = drawings.linearGradient(context, options.colorNeedleCircleInner, options.colorNeedleCircleInnerEnd, r2);\n context.fill();\n context.closePath();\n }\n\n context.restore();\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge value box\n *\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n * @param {number} value\n */\nfunction drawRadialValueBox(context, options, value) {\n drawings.drawValueBox(context, options, value, 0, context.max - context.max * 0.33, context.max);\n}\n\n/**\n * Minimalistic HTML5 Canvas Gauge\n * @example\n * var gauge = new RadialGauge({\n * renderTo: 'gauge-id', // identifier of HTML canvas element or element itself\n * width: 400,\n * height: 400,\n * units: 'Km/h',\n * title: false,\n * value: 0,\n * minValue: 0,\n * maxValue: 220,\n * majorTicks: [\n * '0','20','40','60','80','100','120','140','160','180','200','220'\n * ],\n * minorTicks: 2,\n * strokeTicks: false,\n * highlights: [\n * { from: 0, to: 50, color: 'rgba(0,255,0,.15)' },\n * { from: 50, to: 100, color: 'rgba(255,255,0,.15)' },\n * { from: 100, to: 150, color: 'rgba(255,30,0,.25)' },\n * { from: 150, to: 200, color: 'rgba(255,0,225,.25)' },\n * { from: 200, to: 220, color: 'rgba(0,0,255,.25)' }\n * ],\n * colorPlate: '#222',\n * colorMajorTicks: '#f5f5f5',\n * colorMinorTicks: '#ddd',\n * colorTitle: '#fff',\n * colorUnits: '#ccc',\n * colorNumbers: '#eee',\n * colorNeedleStart: 'rgba(240, 128, 128, 1)',\n * colorNeedleEnd: 'rgba(255, 160, 122, .9)',\n * valueBox: true,\n * animationRule: 'bounce'\n * });\n * // draw initially\n * gauge.draw();\n * // animate\n * setInterval(() => {\n * gauge.value = Math.random() * -220 + 220;\n * }, 1000);\n */\n\nvar RadialGauge = function (_BaseGauge) {\n _inherits(RadialGauge, _BaseGauge);\n\n /**\n * @constructor\n * @param {RadialGaugeOptions} options\n */\n function RadialGauge(options) {\n _classCallCheck(this, RadialGauge);\n\n options = Object.assign({}, defaultRadialGaugeOptions, options || {});\n\n /* istanbul ignore if */\n if (isNaN(options.startAngle)) options.startAngle = 45;\n /* istanbul ignore if */\n if (isNaN(options.ticksAngle)) options.ticksAngle = 270;\n\n /* istanbul ignore if */\n if (options.ticksAngle > 360) options.ticksAngle = 360;\n /* istanbul ignore if */\n if (options.ticksAngle < 0) options.ticksAngle = 0;\n\n /* istanbul ignore if */\n if (options.startAngle < 0) options.startAngle = 0;\n /* istanbul ignore if */\n if (options.startAngle > 360) options.startAngle = 360;\n\n return _possibleConstructorReturn(this, (RadialGauge.__proto__ || Object.getPrototypeOf(RadialGauge)).call(this, options));\n }\n\n /* */\n /**\n * Triggering gauge render on a canvas.\n *\n * @returns {RadialGauge}\n */\n\n\n _createClass(RadialGauge, [{\n key: 'draw',\n value: function draw() {\n try {\n var canvas = this.canvas;\n var _ref = [-canvas.drawX, -canvas.drawY, canvas.drawWidth, canvas.drawHeight];\n var x = _ref[0];\n var y = _ref[1];\n var w = _ref[2];\n var h = _ref[3];\n\n var options = this.options;\n\n if (options.animationTarget === 'needle') {\n if (!canvas.elementClone.initialized) {\n var context = canvas.contextClone;\n\n // clear the cache\n context.clearRect(x, y, w, h);\n context.save();\n\n drawRadialPlate(context, options);\n drawRadialHighlights(context, options);\n drawRadialMinorTicks(context, options);\n drawRadialMajorTicks(context, options);\n drawRadialNumbers(context, options);\n drawRadialTitle(context, options);\n drawRadialUnits(context, options);\n\n canvas.elementClone.initialized = true;\n }\n\n this.canvas.commit();\n\n // clear the canvas\n canvas.context.clearRect(x, y, w, h);\n canvas.context.save();\n\n canvas.context.drawImage(canvas.elementClone, x, y, w, h);\n canvas.context.save();\n\n drawRadialValueBox(canvas.context, options, options.animatedValue ? this.options.value : this.value);\n drawRadialNeedle(canvas.context, options);\n } else {\n var plateValueAngle = -drawings.radians((options.value - options.minValue) / (options.maxValue - options.minValue) * options.ticksAngle);\n\n // clear the canvas\n canvas.context.clearRect(x, y, w, h);\n canvas.context.save();\n\n drawRadialPlate(canvas.context, options);\n\n canvas.context.rotate(plateValueAngle);\n\n // animated\n drawRadialHighlights(canvas.context, options);\n drawRadialMinorTicks(canvas.context, options);\n drawRadialMajorTicks(canvas.context, options);\n drawRadialNumbers(canvas.context, options);\n\n // non-animated\n canvas.context.rotate(-plateValueAngle);\n canvas.context.save();\n\n if (!canvas.elementClone.initialized) {\n var _context = canvas.contextClone;\n\n // clear the cache\n _context.clearRect(x, y, w, h);\n _context.save();\n\n drawRadialTitle(_context, options);\n drawRadialUnits(_context, options);\n drawRadialNeedle(_context, options);\n\n canvas.elementClone.initialized = true;\n }\n\n canvas.context.drawImage(canvas.elementClone, x, y, w, h);\n }\n\n // value box animations\n drawRadialValueBox(canvas.context, options, options.animatedValue ? this.options.value : this.value);\n\n _get(RadialGauge.prototype.__proto__ || Object.getPrototypeOf(RadialGauge.prototype), 'draw', this).call(this);\n } catch (err) {\n drawings.verifyError(err);\n }\n\n return this;\n }\n }]);\n\n return RadialGauge;\n}(BaseGauge);\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n/* istanbul ignore if */\n\n\nif (typeof ns !== 'undefined') {\n ns['RadialGauge'] = RadialGauge;\n}\n\nBaseGauge.initialize('RadialGauge', defaultRadialGaugeOptions);\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Linear gauge configuration options\n *\n * @typedef {GenericOptions|{borderRadius: number, barBeginCircle: number, barWidth: number, barStrokeWidth: number, barProgress: boolean, colorBar: string, colorBarEnd: string, colorBarStroke: string, colorBarProgress: string, colorBarProgressEnd: string, tickSide: string, needleSide: string, numberSide: string, ticksWidth: number, ticksWidthMinor: number, ticksPadding: number, barLength: number}} LinearGaugeOptions\n */\n\n/**\n * Default linear gauge configuration options\n *\n * @type {LinearGaugeOptions}\n */\nvar defaultLinearGaugeOptions = Object.assign({}, GenericOptions, {\n // basic options\n borderRadius: 0,\n // width: 150,\n // height: 400,\n\n // bar\n barBeginCircle: 30, // percents\n barWidth: 20, // percents\n barStrokeWidth: 0, // pixels\n barProgress: true,\n\n colorBarStroke: '#222',\n colorBar: '#ccc',\n colorBarEnd: '',\n colorBarProgress: '#888',\n colorBarProgressEnd: '',\n\n needleWidth: 6,\n\n tickSide: 'both', // available: 'left', 'right', 'both'\n needleSide: 'both', // available: 'left', 'right', 'both'\n\n numberSide: 'both', // available: 'left', 'right', 'both'\n\n ticksWidth: 10,\n ticksWidthMinor: 5,\n ticksPadding: 5,\n barLength: 85,\n fontTitleSize: 26,\n\n highlightsWidth: 10\n});\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws rectangle on a canvas\n *\n * @param {Canvas2DContext} context\n * @param {number} r radius for founded corner rectangle if 0 or less won't be drawn\n * @param {number} x x-coordinate of the top-left corner\n * @param {number} y y-coordinate of the top-left corner\n * @param {number} w width of the rectangle\n * @param {number} h height of the rectangle\n * @param {string} colorStart base fill color of the rectangle\n * @param {string} [colorEnd] gradient color of the rectangle\n */\nfunction drawRectangle(context, r, x, y, w, h, colorStart, colorEnd) {\n context.beginPath();\n context.fillStyle = colorEnd ? drawings.linearGradient(context, colorStart, colorEnd, w > h ? w : h, h > w, w > h ? x : y) : colorStart;\n\n r > 0 ? drawings.roundRect(context, x, y, w, h, r) : context.rect(x, y, w, h);\n\n context.fill();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws rectangle on a canvas\n *\n * @param {Canvas2DContext} context\n * @param {number} width width of the border\n * @param {number} r radius for founded corner rectangle if 0 or less won't be drawn\n * @param {number} x x-coordinate of the top-left corner\n * @param {number} y y-coordinate of the top-left corner\n * @param {number} w width of the rectangle\n * @param {number} h height of the rectangle\n * @param {string} colorStart base fill color of the rectangle\n * @param {string} [colorEnd] gradient color of the rectangle\n */\nfunction drawLinearBorder(context, width, r, x, y, w, h, colorStart, colorEnd) {\n context.beginPath();\n context.lineWidth = width;\n context.strokeStyle = colorEnd ? drawings.linearGradient(context, colorStart, colorEnd, h, true, y) : colorStart;\n\n r > 0 ? drawings.roundRect(context, x, y, w, h, r) : context.rect(x, y, w, h);\n\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge plate\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n */\nfunction drawLinearPlate(context, options, x, y, w, h) {\n context.save();\n\n var r = options.borderRadius;\n var w1 = w - options.borderShadowWidth - options.borderOuterWidth;\n var w2 = w1 - options.borderOuterWidth - options.borderMiddleWidth;\n var w3 = w2 - options.borderMiddleWidth - options.borderInnerWidth;\n var w4 = w3 - options.borderInnerWidth;\n\n var h1 = h - options.borderShadowWidth - options.borderOuterWidth;\n var h2 = h1 - options.borderOuterWidth - options.borderMiddleWidth;\n var h3 = h2 - options.borderMiddleWidth - options.borderInnerWidth;\n var h4 = h3 - options.borderInnerWidth;\n\n var x2 = x - (w2 - w1) / 2;\n var x3 = x2 - (w3 - w2) / 2;\n var x4 = x3 - (w4 - w3) / 2;\n\n var y2 = y - (h2 - h1) / 2;\n var y3 = y2 - (h3 - h2) / 2;\n var y4 = y3 - (h4 - h3) / 2;\n var aliasingOffset = 0;\n var shadowDrawn = false;\n\n if (options.borderOuterWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawLinearBorder(context, options.borderOuterWidth, r, x + options.borderOuterWidth / 2 - aliasingOffset, y + options.borderOuterWidth / 2 - aliasingOffset, w1, h1, options.colorBorderOuter, options.colorBorderOuterEnd);\n aliasingOffset += 0.5;\n }\n\n if (options.borderMiddleWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawLinearBorder(context, options.borderMiddleWidth, r -= 1 + aliasingOffset * 2, x2 + options.borderMiddleWidth / 2 - aliasingOffset, y2 + options.borderMiddleWidth / 2 - aliasingOffset, w2 + aliasingOffset * 2, h2 + aliasingOffset * 2, options.colorBorderMiddle, options.colorBorderMiddleEnd);\n aliasingOffset += 0.5;\n }\n\n if (options.borderInnerWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawLinearBorder(context, options.borderInnerWidth, r -= 1 + aliasingOffset * 2, x3 + options.borderInnerWidth / 2 - aliasingOffset, y3 + options.borderInnerWidth / 2 - aliasingOffset, w3 + aliasingOffset * 2, h3 + aliasingOffset * 2, options.colorBorderInner, options.colorBorderInnerEnd);\n aliasingOffset += 0.5;\n }\n\n drawings.drawShadow(context, options, shadowDrawn);\n\n drawRectangle(context, r, x4, y4, w4 + aliasingOffset * 2, h4 + aliasingOffset * 2, options.colorPlate, options.colorPlateEnd);\n\n context.restore();\n\n return [x4, y4, w4, h4];\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Calculates and returns linear gauge base bar dimensions.\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions|{barStrokeWidth: number, barBeginCircle: number, barWidth: number, hasLeft: boolean, hasRight: boolean}} options\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @return {{isVertical: boolean, width: number, length: number, barWidth: number, barLength: number, strokeWidth: number, barMargin: number, radius: number, x0: number, y0: number, barOffset: number, titleMargin: number, unitsMargin: number, X: number, Y: number, baseX: number, baseY: number, ticksPadding: number}}\n */\nfunction barDimensions(context, options, x, y, w, h) {\n var pixelRatio = SmartCanvas.pixelRatio;\n var isVertical = h >= w;\n var width = isVertical ? w * 0.85 : h;\n var length = isVertical ? h : w;\n\n //noinspection JSUnresolvedFunction\n x = isVertical ? round(x + (w - width) / 2) : x;\n\n var hasTitle = !!options.title;\n var hasUnits = !!options.units;\n var hasValue = !!options.valueBox;\n\n var titleMargin = void 0;\n var unitsMargin = void 0;\n var valueMargin = void 0;\n\n if (isVertical) {\n //noinspection JSUnresolvedFunction\n unitsMargin = round(length * 0.05);\n //noinspection JSUnresolvedFunction\n titleMargin = round(length * 0.075);\n //noinspection JSUnresolvedFunction\n valueMargin = round(length * 0.075);\n\n if (hasTitle) {\n length -= titleMargin;\n y += titleMargin;\n }\n\n if (hasUnits) length -= unitsMargin;\n if (hasValue) length -= valueMargin;\n } else {\n //noinspection JSUnresolvedFunction\n unitsMargin = titleMargin = round(width * 0.15);\n\n if (hasTitle) {\n width -= titleMargin;\n y += titleMargin;\n }\n\n if (hasUnits) width -= unitsMargin;\n }\n\n var strokeWidth = options.barStrokeWidth * 2;\n //noinspection JSUnresolvedFunction\n var radius = options.barBeginCircle ? round(width * options.barBeginCircle / 200 - strokeWidth / 2) : 0;\n //noinspection JSUnresolvedFunction\n var barWidth = round(width * options.barWidth / 100 - strokeWidth);\n //noinspection JSUnresolvedFunction\n var barLength = round(length * options.barLength / 100 - strokeWidth);\n //noinspection JSUnresolvedFunction\n var barMargin = round((length - barLength) / 2);\n\n // coordinates for arc of the bar if configured\n //noinspection JSUnresolvedFunction\n var x0 = round(x + (isVertical ? width / 2 : barMargin + radius));\n //noinspection JSUnresolvedFunction\n var y0 = round(y + (isVertical ? length - barMargin - radius + strokeWidth / 2 : width / 2));\n var dx = isVertical && !(options.hasLeft && options.hasRight) ? (options.hasRight ? -1 : 1) * options.ticksWidth / 100 * width : 0;\n var dy = !isVertical && !(options.hasLeft && options.hasRight) ? (options.hasRight ? -1 : 1) * options.ticksWidth / 100 * width : 0;\n\n //noinspection JSUndefinedPropertyAssignment\n context.barDimensions = {\n isVertical: isVertical,\n width: width,\n length: length,\n barWidth: barWidth,\n barLength: barLength,\n strokeWidth: strokeWidth,\n barMargin: barMargin,\n radius: radius,\n pixelRatio: pixelRatio,\n barOffset: null,\n titleMargin: hasTitle ? titleMargin : 0,\n unitsMargin: hasUnits ? unitsMargin : 0,\n get ticksLength() {\n return this.barLength - this.barOffset - this.strokeWidth;\n },\n X: x + dx,\n Y: y + dy,\n x0: x0 + dx,\n y0: y0 + dy,\n baseX: x,\n baseY: y,\n ticksPadding: options.ticksPadding / 100\n };\n\n return context.barDimensions;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws bar shape from the given options on a given canvas context\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {string} type\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n */\nfunction drawLinearBarShape(context, options, type, x, y, w, h) {\n var _barDimensions = barDimensions(context, options, x, y, w, h);\n\n var isVertical = _barDimensions.isVertical;\n var width = _barDimensions.width;\n var barWidth = _barDimensions.barWidth;\n var barLength = _barDimensions.barLength;\n var strokeWidth = _barDimensions.strokeWidth;\n var barMargin = _barDimensions.barMargin;\n var radius = _barDimensions.radius;\n var x0 = _barDimensions.x0;\n var y0 = _barDimensions.y0;\n var X = _barDimensions.X;\n var Y = _barDimensions.Y;\n\n var fullBarLength = barLength;\n\n context.save();\n context.beginPath();\n\n if (options.barBeginCircle) {\n var direction = drawings.radians(isVertical ? 270 : 0);\n var alpha = Math.asin(barWidth / 2 / radius);\n var cosAlpha = Math.cos(alpha);\n var sinAlpha = Math.sin(alpha);\n\n var x1 = x0 + (isVertical ? radius * sinAlpha : radius * cosAlpha - strokeWidth / 2);\n var y1 = isVertical ? y0 - radius * cosAlpha : y0 + radius * sinAlpha;\n //noinspection JSUnresolvedFunction\n var cutRadius = isVertical ? abs(y1 - y0) : abs(x1 - x0);\n\n //noinspection JSUnresolvedFunction\n context.barDimensions.barOffset = round(cutRadius + radius);\n\n // bottom point\n //noinspection JSUnresolvedFunction\n var x2 = isVertical ? round(x0 - radius * sinAlpha) : x1;\n //noinspection JSUnresolvedFunction\n var y2 = isVertical ? y1 : round(y0 - radius * sinAlpha);\n\n if (type === 'progress') {\n barLength = context.barDimensions.barOffset + (barLength - context.barDimensions.barOffset) * (options.value - options.minValue) / (options.maxValue - options.minValue);\n }\n\n // bar ends at\n //noinspection JSUnresolvedFunction\n var x3 = round(x1 + barLength - context.barDimensions.barOffset + strokeWidth / 2); // h\n //noinspection JSUnresolvedFunction\n var y3 = round(y1 - barLength + context.barDimensions.barOffset - strokeWidth / 2); // v\n\n context.arc(x0, y0, radius, direction + alpha, direction - alpha);\n\n if (isVertical) {\n context.moveTo(x1, y2);\n context.lineTo(x1, y3);\n context.lineTo(x2, y3);\n context.lineTo(x2, y2);\n } else {\n context.moveTo(x1, y2);\n context.lineTo(x3, y2);\n context.lineTo(x3, y1);\n context.lineTo(x1, y1);\n }\n } else {\n // simply rectangle\n //noinspection JSUnresolvedFunction\n var rx = round(isVertical ? X + (width - barWidth) / 2 : X + barMargin);\n //noinspection JSUnresolvedFunction\n var ry = round(isVertical ? Y + barLength + barMargin : Y + (width - barWidth) / 2);\n\n if (type === 'progress') {\n barLength *= (options.value - options.minValue) / (options.maxValue - options.minValue);\n }\n\n if (isVertical) context.rect(rx, ry, barWidth, -barLength);else context.rect(rx, ry, barLength, barWidth);\n }\n\n if (type !== 'progress' && options.barStrokeWidth) {\n context.lineWidth = strokeWidth;\n context.strokeStyle = options.colorBarStroke;\n //context.lineJoin = 'round';\n context.stroke();\n }\n\n if (type !== 'progress' && options.colorBar) {\n context.fillStyle = options.colorBarEnd ? drawings.linearGradient(context, options.colorBar, options.colorBarEnd, barLength, isVertical, isVertical ? Y : X) : options.colorBar;\n context.fill();\n } else if (type === 'progress' && options.colorBarProgress) {\n context.fillStyle = options.colorBarProgressEnd ? drawings.linearGradient(context, options.colorBarProgress, options.colorBarProgressEnd, fullBarLength, isVertical, isVertical ? Y : X) : options.colorBarProgress;\n context.fill();\n }\n\n context.closePath();\n\n // fix dimensions for further usage\n if (options.barBeginCircle) context.barDimensions.radius += strokeWidth;\n\n context.barDimensions.barWidth += strokeWidth;\n context.barDimensions.barLength += strokeWidth;\n}\n\n/**\n * Draws gauge bar\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} x x-coordinate of the top-left corner of the gauge\n * @param {number} y y-coordinate of the top-left corner of the gauge\n * @param {number} w width of the gauge\n * @param {number} h height of the gauge\n */\nfunction drawLinearBar(context, options, x, y, w, h) {\n drawLinearBarShape(context, options, '', x, y, w, h);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Helper function to calculate bar ticks presence on the sides\n *\n * @param {string} notWhich\n * @param {LinearGaugeOptions} options\n * @return {boolean}\n */\nfunction hasTicksBar(notWhich, options) {\n return options.needleSide !== notWhich || options.tickSide !== notWhich || options.numberSide !== notWhich;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge bar progress\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} x x-coordinate of the top-left corner of the gauge\n * @param {number} y y-coordinate of the top-left corner of the gauge\n * @param {number} w width of the gauge\n * @param {number} h height of the gauge\n */\nfunction drawLinearBarProgress(context, options, x, y, w, h) {\n options.barProgress && drawLinearBarShape(context, options, 'progress', x, y, w, h);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge bar highlighted areas\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearBarHighlights(context, options) {\n var _context$barDimension = context.barDimensions;\n var isVertical = _context$barDimension.isVertical;\n var width = _context$barDimension.width;\n var length = _context$barDimension.length;\n var barWidth = _context$barDimension.barWidth;\n var barOffset = _context$barDimension.barOffset;\n var barMargin = _context$barDimension.barMargin;\n var X = _context$barDimension.X;\n var Y = _context$barDimension.Y;\n var ticksLength = _context$barDimension.ticksLength;\n var ticksPadding = _context$barDimension.ticksPadding;\n\n var hlWidth = width * (parseFloat(options.highlightsWidth) || 0) / 100;\n\n if (!options.highlights || !hlWidth) return;\n\n var hasLeft = options.tickSide !== 'right';\n var hasRight = options.tickSide !== 'left';\n var i = 0;\n var s = options.highlights.length;\n var tickOffset = (width - barWidth) / 2;\n var interval = options.maxValue - options.minValue;\n //noinspection JSUnresolvedFunction\n var eX = round(isVertical ? X + tickOffset : X + barMargin + barOffset);\n var eH = hlWidth;\n var eY = isVertical ? Y + length - barMargin - barOffset : Y + tickOffset;\n //noinspection JSUnresolvedFunction\n var hLeft = round((options.ticksWidth / 100 + ticksPadding) * width) + (hlWidth - options.ticksWidth / 100 * width);\n //noinspection JSUnresolvedFunction\n var hRight = round(barWidth + ticksPadding * width);\n\n context.save();\n\n for (; i < s; i++) {\n var entry = options.highlights[i];\n //noinspection JSUnresolvedFunction\n var eStart = ticksLength * abs(entry.from) / interval;\n //noinspection JSUnresolvedFunction\n var eW = ticksLength * abs((entry.to - entry.from) / interval);\n\n context.beginPath();\n context.fillStyle = entry.color;\n\n if (isVertical) {\n if (hasLeft) context.rect(eX - hLeft, eY - eStart, eH, -eW);\n\n if (hasRight) context.rect(eX + hRight, eY - eStart, eH, -eW);\n } else {\n if (hasLeft) context.rect(eX + eStart, eY - hLeft, eW, eH);\n\n if (hasRight) context.rect(eX + eStart, eY + hRight, eW, eH);\n }\n\n context.fill();\n context.closePath();\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws a tick line on a linear gauge\n *\n * @param {Canvas2DContext} context\n * @param x1\n * @param y1\n * @param x2\n * @param y2\n */\nfunction drawLinearTick(context, x1, y1, x2, y2) {\n context.beginPath();\n\n context.moveTo(x1, y1);\n context.lineTo(x2, y2);\n context.stroke();\n\n context.closePath();\n context.save();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws ticks\n *\n * @param {Canvas2DContext} context\n * @param {string} color\n * @param {number} ticksSize\n * @param {number} deltaLen\n * @param {boolean} hasLeft\n * @param {boolean} hasRight\n * @param {number} lineWidth\n * @param {number} lineLength\n */\nfunction drawLinearTicks(context, color, ticksSize, deltaLen, hasLeft, hasRight, lineWidth, lineLength) {\n var _context$barDimension2 = context.barDimensions;\n var isVertical = _context$barDimension2.isVertical;\n var length = _context$barDimension2.length;\n var barWidth = _context$barDimension2.barWidth;\n var barOffset = _context$barDimension2.barOffset;\n var barMargin = _context$barDimension2.barMargin;\n var pixelRatio = _context$barDimension2.pixelRatio;\n var width = _context$barDimension2.width;\n var X = _context$barDimension2.X;\n var Y = _context$barDimension2.Y;\n var ticksLength = _context$barDimension2.ticksLength;\n var ticksPadding = _context$barDimension2.ticksPadding;\n\n var tickOffset = (width - barWidth) / 2;\n var tickX = void 0,\n tickY = void 0;\n var i = 0;\n var tickLen = lineLength * width;\n var tickLeft = tickOffset - ticksPadding * width;\n var tickRight = tickOffset + barWidth + tickLen + ticksPadding * width;\n var tickSpace = ticksLength / (ticksSize - deltaLen);\n var colors = color instanceof Array ? color : new Array(ticksSize).fill(color);\n\n context.lineWidth = lineWidth * pixelRatio;\n context.save();\n\n for (; i < ticksSize; i++) {\n context.strokeStyle = colors[i];\n\n if (isVertical) {\n tickY = Y + length - barMargin - barOffset - i * tickSpace;\n\n if (hasLeft) {\n tickX = X + tickLeft;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, tickY, round(tickX - tickLen), tickY);\n }\n\n if (hasRight) {\n tickX = X + tickRight;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, tickY, round(tickX - tickLen), tickY);\n }\n } else {\n tickX = X + barMargin + barOffset + i * tickSpace;\n\n if (hasLeft) {\n tickY = Y + tickLeft;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, tickY, tickX, round(tickY - tickLen));\n }\n\n if (hasRight) {\n tickY = Y + tickRight;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, round(tickY), tickX, tickY - tickLen);\n }\n }\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws major ticks\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearMajorTicks(context, options) {\n var _drawings$prepareTick = drawings.prepareTicks(options);\n\n var _drawings$prepareTick2 = _slicedToArray(_drawings$prepareTick, 2);\n\n var hasLeft = _drawings$prepareTick2[0];\n var hasRight = _drawings$prepareTick2[1];\n\n var lineWidth = 2;\n var colors = options.colorMajorTicks instanceof Array ? options.colorMajorTicks : new Array(options.colorMajorTicks.length).fill(options.colorMajorTicks);\n\n drawLinearTicks(context, options.colorMajorTicks, options.majorTicks.length, 1, hasLeft, hasRight, lineWidth, options.ticksWidth / 100);\n\n if (options.strokeTicks) {\n var _context$barDimension3 = context.barDimensions;\n var isVertical = _context$barDimension3.isVertical;\n var length = _context$barDimension3.length;\n var width = _context$barDimension3.width;\n var barWidth = _context$barDimension3.barWidth;\n var barMargin = _context$barDimension3.barMargin;\n var barOffset = _context$barDimension3.barOffset;\n var X = _context$barDimension3.X;\n var Y = _context$barDimension3.Y;\n var ticksLength = _context$barDimension3.ticksLength;\n var pixelRatio = _context$barDimension3.pixelRatio;\n var ticksPadding = _context$barDimension3.ticksPadding;\n\n var rightTicks = (width - barWidth) / 2 + barWidth + ticksPadding * width;\n var leftTicks = (width - barWidth) / 2 - ticksPadding * width;\n var sX = void 0,\n sY = void 0,\n eX = void 0,\n eY = void 0;\n\n context.strokeStyle = colors[0];\n\n lineWidth *= pixelRatio;\n\n if (isVertical) {\n sY = Y + length - barMargin - barOffset + lineWidth / 2;\n eY = sY - ticksLength - lineWidth;\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n eX = sX = round(X + leftTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n eX = sX = round(X + rightTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n } else {\n sX = X + barMargin + barOffset - lineWidth / 2;\n eX = sX + ticksLength + lineWidth;\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n eY = sY = round(Y + leftTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n eY = sY = round(Y + rightTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n }\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws ticks stroke\n *\n * @param {Canvas2DContext} context\n * @param {number} sX\n * @param {number} sY\n * @param {number} eX\n * @param {number} eY\n */\nfunction drawLinearTickStroke(context, sX, sY, eX, eY) {\n context.beginPath();\n context.moveTo(sX, sY);\n context.lineTo(eX, eY);\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws minor ticks\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearMinorTicks(context, options) {\n var _drawings$prepareTick3 = drawings.prepareTicks(options);\n\n var _drawings$prepareTick4 = _slicedToArray(_drawings$prepareTick3, 2);\n\n var hasLeft = _drawings$prepareTick4[0];\n var hasRight = _drawings$prepareTick4[1];\n\n\n drawLinearTicks(context, options.colorMinorTicks, options.minorTicks * (options.majorTicks.length - 1), 0, hasLeft, hasRight, 1, options.ticksWidthMinor / 100);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws major tick numbers\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearMajorTicksNumbers(context, options) {\n var _context$barDimension4 = context.barDimensions;\n var isVertical = _context$barDimension4.isVertical;\n var length = _context$barDimension4.length;\n var width = _context$barDimension4.width;\n var barWidth = _context$barDimension4.barWidth;\n var barMargin = _context$barDimension4.barMargin;\n var barOffset = _context$barDimension4.barOffset;\n var X = _context$barDimension4.X;\n var Y = _context$barDimension4.Y;\n var ticksLength = _context$barDimension4.ticksLength;\n var ticksPadding = _context$barDimension4.ticksPadding;\n\n var ticks = options.majorTicks.length;\n var hasLeft = options.numberSide !== 'right';\n var hasRight = options.numberSide !== 'left';\n var textHeight = options.fontNumbersSize * width / 200;\n var i = 0;\n var ticksWidth = (options.ticksWidth / 100 + ticksPadding * 2) * width;\n var numLeft = (width - barWidth) / 2 - ticksWidth;\n var numRight = (width - barWidth) / 2 + barWidth + ticksWidth;\n var textX = void 0,\n textY = void 0,\n textWidth = void 0,\n numberOffset = void 0,\n tick = void 0;\n var colors = options.colorNumbers instanceof Array ? options.colorNumbers : new Array(ticks).fill(options.colorNumbers);\n\n context.font = drawings.font(options, 'Numbers', width / 200);\n context.lineWidth = 0;\n context.textAlign = 'center';\n\n for (; i < ticks; i++) {\n context.fillStyle = colors[i];\n tick = options.majorTicks[i];\n numberOffset = i * ticksLength / (ticks - 1);\n\n if (isVertical) {\n textY = Y + length - barMargin - barOffset - numberOffset + textHeight / 3;\n\n if (hasLeft) {\n context.textAlign = 'right';\n context.fillText(tick, X + numLeft, textY);\n }\n\n if (hasRight) {\n context.textAlign = 'left';\n context.fillText(tick, X + numRight, textY);\n }\n } else {\n textWidth = context.measureText(tick).width;\n textX = X + barMargin + barOffset + numberOffset;\n\n if (hasLeft) {\n context.fillText(tick, textX, Y + numLeft);\n }\n\n if (hasRight) {\n context.fillText(tick, textX, Y + numRight + textHeight);\n }\n }\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge title\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearTitle(context, options) {\n if (!options.title) return;\n\n var _context$barDimension5 = context.barDimensions;\n var isVertical = _context$barDimension5.isVertical;\n var width = _context$barDimension5.width;\n var length = _context$barDimension5.length;\n var baseX = _context$barDimension5.baseX;\n var baseY = _context$barDimension5.baseY;\n var titleMargin = _context$barDimension5.titleMargin;\n\n var textHeight = options.fontTitleSize * width / 200;\n //noinspection JSUnresolvedFunction\n var textX = round(baseX + (isVertical ? width : length) / 2);\n //noinspection JSUnresolvedFunction\n var textY = round(baseY + titleMargin / 2 - (isVertical ? textHeight : textHeight / 2) - 0.025 * (isVertical ? length : width));\n\n context.save();\n context.textAlign = 'center';\n context.fillStyle = options.colorTitle;\n context.font = drawings.font(options, 'Title', width / 200);\n context.lineWidth = 0;\n context.fillText(options.title, textX, textY, isVertical ? width : length);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge units\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearUnits(context, options) {\n if (!options.units) return;\n\n var _context$barDimension6 = context.barDimensions;\n var isVertical = _context$barDimension6.isVertical;\n var width = _context$barDimension6.width;\n var length = _context$barDimension6.length;\n var baseX = _context$barDimension6.baseX;\n var baseY = _context$barDimension6.baseY;\n var unitsMargin = _context$barDimension6.unitsMargin;\n\n var textHeight = options.fontUnitsSize * width / 200;\n //noinspection JSUnresolvedFunction\n var textX = round(baseX + (isVertical ? width : length) / 2);\n //noinspection JSUnresolvedFunction\n var textY = round(baseY + (isVertical ? length : width) + unitsMargin / 2 - textHeight / 2);\n\n context.save();\n context.textAlign = 'center';\n context.fillStyle = options.colorTitle;\n context.font = drawings.font(options, 'Units', width / 200);\n context.lineWidth = 0;\n context.fillText(options.units, textX, textY, isVertical ? width : length);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge needles\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearBarNeedle(context, options) {\n if (!options.needle) return;\n\n var _context$barDimension7 = context.barDimensions;\n var isVertical = _context$barDimension7.isVertical;\n var width = _context$barDimension7.width;\n var length = _context$barDimension7.length;\n var barWidth = _context$barDimension7.barWidth;\n var barOffset = _context$barDimension7.barOffset;\n var barMargin = _context$barDimension7.barMargin;\n var ticksLength = _context$barDimension7.ticksLength;\n var X = _context$barDimension7.X;\n var Y = _context$barDimension7.Y;\n var ticksPadding = _context$barDimension7.ticksPadding;\n\n var hasLeft = options.needleSide !== 'right';\n var hasRight = options.needleSide !== 'left';\n var position = ticksLength * (options.value - options.minValue) / (options.maxValue - options.minValue);\n var tickWidth = (options.ticksWidth / 100 + ticksPadding) * width;\n var baseLength = barWidth / 2 + tickWidth;\n var needleLength = baseLength * (options.needleEnd / 100);\n var sX = void 0,\n eX = void 0,\n sY = void 0,\n eY = void 0;\n var draw = options.needleType.toLowerCase() === 'arrow' ? drawLinearArrowNeedle : drawLinearLineNeedle;\n var barStart = (width - barWidth) / 2;\n var needleStart = baseLength * (options.needleStart / 100);\n var nLeft = barStart - tickWidth - needleStart;\n var nRight = barStart + barWidth + tickWidth + needleStart;\n\n context.save();\n\n drawings.drawNeedleShadow(context, options);\n\n if (isVertical) {\n //noinspection JSUnresolvedFunction\n sY = round(Y + length - barMargin - barOffset - position);\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n sX = round(X + nLeft);\n eX = sX + needleLength;\n draw(context, options, sX, sY, eX, sY, needleLength);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n sX = round(X + nRight);\n eX = sX - needleLength;\n draw(context, options, sX, sY, eX, sY, needleLength, true);\n }\n } else {\n //noinspection JSUnresolvedFunction\n sX = round(X + barMargin + barOffset + position);\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n sY = round(Y + nLeft);\n eY = sY + needleLength;\n draw(context, options, sX, sY, sX, eY, needleLength);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n sY = round(Y + nRight);\n eY = sY - needleLength;\n draw(context, options, sX, sY, sX, eY, needleLength, true);\n }\n }\n\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Returns needle color style\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} length\n * @param {boolean} [isRight]\n * @return {CanvasGradient|string}\n */\nfunction needleStyle(context, options, length, isRight) {\n return options.colorNeedleEnd ? drawings.linearGradient(context, isRight ? options.colorNeedleEnd : options.colorNeedle, isRight ? options.colorNeedle : options.colorNeedleEnd, length, !context.barDimensions.isVertical) : options.colorNeedle;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws line needle shape\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} sX\n * @param {number} sY\n * @param {number} eX\n * @param {number} eY\n * @param {number} length\n * @param {boolean} [isRight]\n */\nfunction drawLinearLineNeedle(context, options, sX, sY, eX, eY, length, isRight) {\n context.lineWidth = options.needleWidth;\n context.strokeStyle = needleStyle(context, options, length, isRight);\n\n context.beginPath();\n context.moveTo(sX, sY);\n context.lineTo(eX, eY);\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws arrow needle shape\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} sX\n * @param {number} sY\n * @param {number} eX\n * @param {number} eY\n * @param {number} length\n * @param {boolean} [isRight]\n */\nfunction drawLinearArrowNeedle(context, options, sX, sY, eX, eY, length, isRight) {\n //noinspection JSUnresolvedFunction\n var peakLength = round(length * 0.4);\n var bodyLength = length - peakLength;\n var isVertical = sX === eX;\n var halfWidth = options.needleWidth / 2;\n\n context.fillStyle = needleStyle(context, options, length, isRight);\n\n context.beginPath();\n\n if (isVertical) {\n if (sY > eY) bodyLength *= -1;\n\n context.moveTo(sX - halfWidth, sY);\n context.lineTo(sX + halfWidth, sY);\n context.lineTo(sX + halfWidth, sY + bodyLength);\n context.lineTo(sX, eY);\n context.lineTo(sX - halfWidth, sY + bodyLength);\n context.lineTo(sX - halfWidth, sY);\n } else {\n if (sX > eX) bodyLength *= -1;\n\n context.moveTo(sX, sY - halfWidth);\n context.lineTo(sX, sY + halfWidth);\n context.lineTo(sX + bodyLength, sY + halfWidth);\n context.lineTo(eX, sY);\n context.lineTo(sX + bodyLength, sY - halfWidth);\n context.lineTo(sX, sY - halfWidth);\n }\n\n context.fill();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws value box for linear gauge\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} value\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n */\nfunction drawLinearValueBox(context, options, value, x, y, w, h) {\n // currently value box is available only for vertical linear gauge,\n // as far as by design it is hard to find a proper place for\n // horizontal ones\n context.barDimensions.isVertical && drawings.drawValueBox(context, options, value, x + w / 2, y + h - 40 * (w / 300), w);\n}\n\n/**\n * Minimalistic HTML5 Canvas Linear Gauge\n */\n\nvar LinearGauge = function (_BaseGauge2) {\n _inherits(LinearGauge, _BaseGauge2);\n\n /**\n * @constructor\n * @param {LinearGaugeOptions} options\n */\n function LinearGauge(options) {\n _classCallCheck(this, LinearGauge);\n\n options = Object.assign({}, defaultLinearGaugeOptions, options || {});\n\n /* istanbul ignore else */\n if (options.barStrokeWidth >= options.barWidth) {\n //noinspection JSUnresolvedFunction\n options.barStrokeWidth = round(options.barWidth / 2);\n }\n\n //noinspection JSUndefinedPropertyAssignment\n options.hasLeft = hasTicksBar('right', options);\n //noinspection JSUndefinedPropertyAssignment\n options.hasRight = hasTicksBar('left', options);\n\n return _possibleConstructorReturn(this, (LinearGauge.__proto__ || Object.getPrototypeOf(LinearGauge)).call(this, options));\n }\n\n /* istanbul ignore next */\n /**\n * Triggering linear gauge render on a canvas.\n *\n * @returns {LinearGauge}\n */\n\n\n _createClass(LinearGauge, [{\n key: 'draw',\n value: function draw() {\n try {\n var canvas = this.canvas;\n var _ref2 = [-canvas.drawX, -canvas.drawY, canvas.drawWidth, canvas.drawHeight];\n var x = _ref2[0];\n var y = _ref2[1];\n var w = _ref2[2];\n var h = _ref2[3];\n\n var options = this.options;\n\n if (!canvas.elementClone.initialized) {\n var context = canvas.contextClone;\n\n // clear the cache\n context.clearRect(x, y, w, h);\n context.save();\n\n this.drawBox = drawLinearPlate(context, options, x, y, w, h);\n\n drawLinearBar.apply(undefined, [context, options].concat(_toConsumableArray(this.drawBox)));\n\n canvas.context.barDimensions = context.barDimensions;\n\n drawLinearBarHighlights(context, options);\n drawLinearMinorTicks(context, options);\n drawLinearMajorTicks(context, options);\n drawLinearMajorTicksNumbers(context, options);\n drawLinearTitle(context, options);\n drawLinearUnits(context, options);\n\n canvas.elementClone.initialized = true;\n }\n\n this.canvas.commit();\n\n // clear the canvas\n canvas.context.clearRect(x, y, w, h);\n canvas.context.save();\n\n canvas.context.drawImage(canvas.elementClone, x, y, w, h);\n canvas.context.save();\n\n drawLinearBarProgress.apply(undefined, [canvas.context, options].concat(_toConsumableArray(this.drawBox)));\n drawLinearBarNeedle(canvas.context, options);\n drawLinearValueBox.apply(undefined, [canvas.context, options, options.animatedValue ? this.options.value : this.value].concat(_toConsumableArray(this.drawBox)));\n\n _get(LinearGauge.prototype.__proto__ || Object.getPrototypeOf(LinearGauge.prototype), 'draw', this).call(this);\n } catch (err) {\n drawings.verifyError(err);\n }\n\n return this;\n }\n }]);\n\n return LinearGauge;\n}(BaseGauge);\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n/* istanbul ignore if */\n\n\nif (typeof ns !== 'undefined') {\n ns['LinearGauge'] = LinearGauge;\n}\n\nBaseGauge.initialize('LinearGauge', defaultLinearGaugeOptions);;typeof module !== \"undefined\" && Object.assign(ns, {Collection: Collection,GenericOptions: GenericOptions,Animation: Animation,BaseGauge: BaseGauge,drawings: drawings,SmartCanvas: SmartCanvas,vendorize: vendorize});}(typeof module !== \"undefined\" ? module.exports : window));"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["gauge.min.js"],"names":["ns","_toConsumableArray","arr","Array","isArray","i","arr2","length","from","_possibleConstructorReturn","self","call","ReferenceError","_inherits","subClass","superClass","TypeError","prototype","Object","create","constructor","value","enumerable","writable","configurable","setPrototypeOf","__proto__","_classCallCheck","instance","Constructor","vendorize","prop","window","global","vendors","s","capitalized","charAt","toUpperCase","substr","vendorProp","step","time","draw","start","rule","duration","end","anim","progress","percent","frame","requestAnimationFrame","Collection","apply","this","arguments","verifyError","err","DOMException","result","prepareTicks","options","majorTicks","push","drawings","formatMajorTickNumber","minValue","maxValue","tickSide","roundRect","context","x","y","w","h","r","beginPath","moveTo","lineTo","quadraticCurveTo","closePath","padValue","val","dec","valueDec","int","valueInt","strVal","n","parseFloat","Math","abs","toFixed","toString","split","round","num","right","hasDec","majorTicksDec","majorTicksInt","indexOf","join","replace","radians","degrees","PI","radialPoint","radius","angle","sin","cos","linearGradient","colorFrom","colorTo","isVertical","undefined","grad","createLinearGradient","addColorStop","drawShadow","shadowDrawn","restore","save","borderShadowWidth","shadowBlur","shadowColor","colorBorderShadow","drawNeedleShadow","needleShadow","shadowOffsetX","shadowOffsetY","colorNeedleShadowDown","font","target","baseSize","reset","strokeStyle","lineWidth","drawValueTextShadow","offset","blur","valueTextShadow","colorValueTextShadow","drawValueBox","max","valueBox","text","valueText","tunit","runit","tw","measureText","width","th","fontValueSize","sw","valueBoxStroke","bmax","bw","bh","br","valueBoxBorderRadius","obw","valueBoxWidth","bx","by","gy","rect","grd","createRadialGradient","colorValueBoxRect","colorValueBoxRectEnd","stroke","colorValueBoxShadow","colorValueBoxBackground","fillStyle","fill","colorValueText","textAlign","textBaseline","fillText","normalizedValue","min","dt","normal","indented","drawRadialBorder","arc","maxRadialRadius","maxRadius","borderOuterWidth","borderMiddleWidth","borderInnerWidth","drawRadialPlate","d0","r0","r1","r2","r3","colorBorderOuter","colorBorderOuterEnd","colorBorderMiddle","colorBorderMiddleEnd","colorBorderInner","colorBorderInnerEnd","colorPlateEnd","colorPlate","drawRadialHighlights","hlWidth","highlightsWidth","radialTicksRadius","highlights","vd","ticksAngle","hlt","rotate","HPI","startAngle","to","color","drawRadialMinorTicks","SmartCanvas","pixelRatio","colorMinorTicks","minorTicks","closeStrokedPath","unit","barWidth","barStrokeWidth","drawRadialMajorTicks","colors","colorMajorTicks","radialNextAngle","strokeTicks","drawRadialNumbers","points","isAnimated","animationTarget","colorNumbers","plateValueAngle","point","drawRadialTitle","title","colorTitle","drawRadialUnits","units","colorUnits","drawRadialNeedle","needle","needleCircleSize","rIn","needleEnd","rStart","needleStart","rOut","pad1","needleWidth","pad2","isFixed","colorNeedle","colorNeedleEnd","needleType","colorNeedleShadowUp","needleCircleOuter","colorNeedleCircleOuter","colorNeedleCircleOuterEnd","needleCircleInner","colorNeedleCircleInner","colorNeedleCircleInnerEnd","drawRadialValueBox","drawRadialProgressBar","rMax","rMin","half","delta","sa","ea","colorBarStroke","colorBar","barShadow","clip","colorBarShadow","barProgress","colorBarProgress","displayValue","gauge","animatedValue","drawRectangle","colorStart","colorEnd","drawLinearBorder","drawLinearPlate","borderRadius","w1","w2","w3","w4","h1","h2","h3","h4","x2","x3","x4","y2","y3","y4","aliasingOffset","barDimensions","hasTitle","hasUnits","hasValue","titleMargin","unitsMargin","valueMargin","strokeWidth","barBeginCircle","barLength","barMargin","x0","y0","dx","hasLeft","hasRight","ticksWidth","dy","barOffset","ticksLength","X","Y","baseX","baseY","ticksPadding","drawLinearBarShape","type","_barDimensions","fullBarLength","direction","alpha","asin","cosAlpha","sinAlpha","x1","y1","cutRadius","rx","ry","colorBarEnd","colorBarProgressEnd","drawLinearBar","hasTicksBar","notWhich","needleSide","numberSide","drawLinearBarProgress","drawLinearBarHighlights","_context$barDimension","tickOffset","interval","eX","eH","eY","hLeft","hRight","entry","eStart","eW","drawLinearTick","drawLinearTicks","ticksSize","deltaLen","lineLength","_context$barDimension2","tickX","tickY","tickLen","tickLeft","tickRight","tickSpace","drawLinearMajorTicks","_drawings$prepareTick","_drawings$prepareTick2","_slicedToArray","_context$barDimension3","rightTicks","leftTicks","sX","sY","drawLinearTickStroke","drawLinearMinorTicks","_drawings$prepareTick3","_drawings$prepareTick4","ticksWidthMinor","drawLinearMajorTicksNumbers","_context$barDimension4","ticks","textHeight","fontNumbersSize","numLeft","numRight","textX","textY","textWidth","numberOffset","tick","drawLinearTitle","_context$barDimension5","fontTitleSize","drawLinearUnits","_context$barDimension6","fontUnitsSize","drawLinearBarNeedle","_context$barDimension7","position","tickWidth","baseLength","needleLength","toLowerCase","drawLinearArrowNeedle","drawLinearLineNeedle","barStart","nLeft","nRight","needleStyle","isRight","peakLength","bodyLength","halfWidth","drawLinearValueBox","boxWidth","sliceIterator","_arr","_n","_d","_e","_s","_i","Symbol","iterator","next","done","_get","get","object","property","receiver","Function","desc","getOwnPropertyDescriptor","parent","getPrototypeOf","getter","_set","set","setter","_createClass","defineProperties","props","descriptor","defineProperty","key","protoProps","staticProps","assign","firstSource","nextSource","keysArray","keys","nextIndex","len","nextKey","searchElement","fromIndex","k","O","Infinity","relativeStart","relativeEnd","final","EventEmitter","_events","addListener","on","removeListener","off","event","_len","args","_key","_len2","handlers","_key2","_loop","handler","wrapper","concat","_handler","index","splice","callback","setTimeout","Date","getTime","rules","linear","p","quad","pow","dequad","quint","dequint","cycle","acos","decycle","bounce","debounce","a","b","elastic","delastic","Animation","_this","performance","now","cancelAnimationFrame","id","DomObserver","element","toDashed","Type","mutationsObserved","isObservable","MutationObserver","GAUGES_NO_AUTO_INIT","domReady","traverse","bind","node","tagName","getAttribute","elements","document","getElementsByTagName","process","observe","body","childList","subtree","attributes","characterData","attributeOldValue","characterDataOldValue","records","record","attributeName","isValidNode","oldValue","addedNodes","ii","ss","_this2","JSON","parse","stringify","hasOwnProperty","toAttributeName","attributeValue","renderTo","observer","forEach","attr","disconnect","destroy","_prop","map","part","_options","update","test","e","camelCase","str","dashed","readyState","addEventListener","attachEvent","canvas","height","collection","init","style","elementClone","cloneNode","getContext","contextClone","drawWidth","drawHeight","drawX","drawY","minSide","initialized","translate","clearRect","onRedraw","scale","redraw","devicePixelRatio","matchMedia","GenericOptions","animateOnInit","borders","animation","animationDuration","animationRule","fontNumbers","fontTitle","fontUnits","fontValue","fontNumbersStyle","fontTitleStyle","fontUnitsStyle","fontValueStyle","fontNumbersWeight","fontTitleWeight","fontUnitsWeight","fontValueWeight","getElementById","version","gauges","BaseGauge","_EventEmitter","_this3","className","name","HTMLCanvasElement","parentNode","offsetWidth","offsetHeight","_value","configure","emit","_this4","ensureValue","fromValue","animate","toCamelCase","isNaN","isFinite","defaultRadialGaugeOptions","useMinPath","RadialGauge","_BaseGauge","_ref","commit","drawImage","_context","initialize","defaultLinearGaugeOptions","LinearGauge","_BaseGauge2","_ref2","drawBox","module","exports"],"mappings":"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","file":"gauge.min.js","sourcesContent":["/*!\n * The MIT License (MIT)\n * \n * Copyright (c) 2016 Mykhailo Stadnyk \n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * @version 2.1.0\n */\n(function(ns) {'use strict';\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nvar _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if (\"value\" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };\n\nvar _set = function set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent !== null) { set(parent, property, value, receiver); } } else if (\"value\" in desc && desc.writable) { desc.value = value; } else { var setter = desc.set; if (setter !== undefined) { setter.call(receiver, value); } } return value; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * @external {Object.assign} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n */\n/* istanbul ignore next */\nif (!Object.assign) {\n Object.defineProperty(Object, 'assign', {\n enumerable: false,\n configurable: true,\n writable: true,\n value: function value(target, firstSource) {\n 'use strict';\n\n if (target === undefined || target === null) {\n throw new TypeError('Cannot convert first argument to object');\n }\n\n var to = Object(target);\n var i = 1;\n\n for (; i < arguments.length; i++) {\n var nextSource = arguments[i];\n\n if (nextSource === undefined || nextSource === null) {\n continue;\n }\n\n var keysArray = Object.keys(Object(nextSource));\n var nextIndex = 0,\n len = keysArray.length;\n\n for (; nextIndex < len; nextIndex++) {\n var nextKey = keysArray[nextIndex];\n var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);\n\n if (desc !== undefined && desc.enumerable) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n\n return to;\n }\n });\n}\n\n/**\n * @external {Array.indexOf} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf\n */\n/* istanbul ignore next */\nif (!Array.prototype.indexOf) {\n Array.prototype.indexOf = function (searchElement, fromIndex) {\n var k;\n\n if (this === null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n var O = Object(this);\n var len = O.length >>> 0;\n\n if (len === 0) {\n return -1;\n }\n\n var n = +fromIndex || 0;\n\n if (Math.abs(n) === Infinity) {\n n = 0;\n }\n\n if (n >= len) {\n return -1;\n }\n\n k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n while (k < len) {\n if (k in O && O[k] === searchElement) {\n return k;\n }\n\n k++;\n }\n\n return -1;\n };\n}\n\n/**\n * @external {Array.fill} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/fill\n */\n/* istanbul ignore next */\nif (!Array.prototype.fill) {\n Array.prototype.fill = function (value) {\n if (this === null) {\n throw new TypeError('this is null or not defined');\n }\n\n var O = Object(this);\n var len = O.length >>> 0;\n var start = arguments[1];\n var relativeStart = start >> 0;\n var k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);\n var end = arguments[2];\n var relativeEnd = end === undefined ? len : end >> 0;\n var final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);\n while (k < final) {\n O[k] = value;\n k++;\n }\n\n return O;\n };\n}\n\n/**\n * mocking window\n */\nif (typeof window === 'undefined') {\n window = typeof global === 'undefined' ? {} : global;\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/**\n * Look-ups for a proper vendor-specific property and returns its value\n *\n * @example\n * var requestAnimationFrame = vendorize('requestAnimationFrame');\n * // it will refer properly to:\n * // - window.requestAnimationFrame by default or to\n * // - window.webkitRequestAnimationFrame or to\n * // - window.mozRequestAnimationFrame or to\n * // - window.msRequestAnimationFrame or to\n * // - window.oRequestAnimationFrame\n * // depending on the current browser vendor\n *\n * @author Mykhailo Stadnyk \n * @param {string} prop\n * @param {HTMLElement|Window|object} [from] - default is window\n * @returns {*}\n */\nfunction vendorize(prop, from) {\n /* istanbul ignore else: no reason to cover */\n if (!from) {\n from = typeof window === 'undefined' ? global : window;\n }\n\n if (typeof from[prop] !== 'undefined') {\n return from[prop];\n }\n\n var vendors = ['webkit', 'moz', 'ms', 'o'];\n var i = 0;\n var s = vendors.length;\n var capitalized = prop.charAt(0).toUpperCase() + prop.substr(1);\n\n for (; i < s; i++) {\n var vendorProp = from[vendors[i] + capitalized];\n\n /* istanbul ignore if: requires very complex environment to test (specific browser version) */\n if (typeof vendorProp !== 'undefined') {\n return vendorProp;\n }\n }\n\n return null;\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Class EventEmitter - base event manager\n */\n\nvar EventEmitter = function () {\n /**\n * @constructor\n */\n function EventEmitter() {\n _classCallCheck(this, EventEmitter);\n\n this._events = {};\n\n this.addListener = this.on;\n this.removeListener = this.off;\n }\n\n /**\n * Returns all event listeners\n *\n * @return {object}\n */\n\n\n _createClass(EventEmitter, [{\n key: 'emit',\n\n\n /**\n * Emits given event bypassing to each registered handler given args\n *\n * @param {string} event\n * @param {...*} args\n */\n value: function emit(event) {\n if (this._events[event]) {\n var i = 0;\n var s = this._events[event].length;\n\n for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n for (; i < s; i++) {\n this._events[event][i] && this._events[event][i].apply(this, args);\n }\n }\n }\n\n /**\n * Registers given handler for given event to be called only once when\n * event is emitted\n *\n * @param {string} event\n * @param {...function} handlers\n */\n\n }, {\n key: 'once',\n value: function once(event) {\n for (var _len2 = arguments.length, handlers = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n handlers[_key2 - 1] = arguments[_key2];\n }\n\n var i = 0;\n var s = handlers.length;\n var self = this;\n\n var _loop = function _loop() {\n var handler = handlers[i];\n var wrapper = function wrapper() {\n self.off(event, wrapper);\n handler.apply(self, arguments);\n };\n\n handlers[i] = wrapper;\n };\n\n for (; i < s; i++) {\n _loop();\n }\n\n this.on.apply(this, [event].concat(handlers));\n }\n\n /**\n * Registers given handlers for a given events to be called each time event\n * is emitted\n *\n * @param {string} event\n * @param {...function} handlers\n */\n\n }, {\n key: 'on',\n value: function on(event) {\n if (!this._events[event]) {\n this._events[event] = [];\n }\n\n var i = 0;\n var s = arguments.length <= 1 ? 0 : arguments.length - 1;\n\n for (; i < s; i++) {\n this._events[event].push(arguments.length <= i + 1 ? undefined : arguments[i + 1]);\n }\n }\n\n /**\n * Un-registers previously registered event handlers\n *\n * @param {string} event\n * @param {...function} handlers\n */\n\n }, {\n key: 'off',\n value: function off(event) {\n if (!this._events[event]) {\n return;\n }\n\n var i = 0;\n var s = arguments.length <= 1 ? 0 : arguments.length - 1;\n\n for (; i < s; i++) {\n var _handler = arguments.length <= i + 1 ? undefined : arguments[i + 1];\n var index = void 0;\n\n while (~(index = this._events[event].indexOf(_handler))) {\n this._events[event].splice(index, 1);\n }\n }\n }\n\n /**\n * Removes all listeners for a given event\n *\n * @param {string} event\n */\n\n }, {\n key: 'removeAllListeners',\n value: function removeAllListeners(event) {\n delete this._events[event];\n }\n }, {\n key: 'listeners',\n get: function get() {\n return this._events;\n }\n }]);\n\n return EventEmitter;\n}();\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/* jshint -W079 */\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n\n/* istanbul ignore next */\n/**\n * @type {function(callback: function(time: number): number, element?: HTMLElement)}\n * @access private\n */\n\n\nvar requestAnimationFrame = vendorize('requestAnimationFrame') || function (callback) {\n return setTimeout(function () {\n return callback(new Date().getTime());\n }, 1000 / 60);\n};\n\n/**\n * Generic AnimationRule function interface\n *\n * @typedef {function(percent: number): number} AnimationRule\n */\n\n/**\n * Callback for animation step draw event.\n * It will be called each time animation step is executed, bypassing\n * as first argument a percent of animation completeness. It is expected\n * that this callback will do an actual work of animating an elements or\n * whatever, as far as animation engine is just calculating and executing\n * animation steps without any knowledge about things under animation.\n *\n * @typedef {function(percent: number): *} DrawEventCallback\n */\n\n/**\n * Callback for animation complete event.\n * It is called once each animation is complete.\n *\n * @typedef {function(): *} EndEventCallback\n */\n\n/**\n * Predefined known animation rules.\n * It's a simple collection of math for some most used animations.\n *\n * @typedef {{linear: AnimationRule, quad: AnimationRule, dequad: AnimationRule, quint: AnimationRule, dequint: AnimationRule, cycle: AnimationRule, decycle: AnimationRule, bounce: AnimationRule, debounce: AnimationRule, elastic: AnimationRule, delastic: AnimationRule}} AnimationRules\n */\n\n/* istanbul ignore next: no reason covering this */\nvar rules = {\n linear: function linear(p) {\n return p;\n },\n quad: function quad(p) {\n return Math.pow(p, 2);\n },\n dequad: function dequad(p) {\n return 1 - rules.quad(1 - p);\n },\n quint: function quint(p) {\n return Math.pow(p, 5);\n },\n dequint: function dequint(p) {\n return 1 - Math.pow(1 - p, 5);\n },\n cycle: function cycle(p) {\n return 1 - Math.sin(Math.acos(p));\n },\n decycle: function decycle(p) {\n return Math.sin(Math.acos(1 - p));\n },\n bounce: function bounce(p) {\n return 1 - rules.debounce(1 - p);\n },\n debounce: function debounce(p) {\n var a = 0,\n b = 1;\n for (; 1; a += b, b /= 2) {\n if (p >= (7 - 4 * a) / 11) {\n return -Math.pow((11 - 6 * a - 11 * p) / 4, 2) + Math.pow(b, 2);\n }\n }\n },\n elastic: function elastic(p) {\n return 1 - rules.delastic(1 - p);\n },\n delastic: function delastic(p) {\n var x = 1.5;\n return Math.pow(2, 10 * (p - 1)) * Math.cos(20 * Math.PI * x / 3 * p);\n }\n};\n\n/* istanbul ignore next: private, not testable */\n/**\n * Evaluates animation step and decides if the next step required or\n * stops animation calling a proper events.\n *\n * @access private\n * @param {number} time\n * @param {DrawEventCallback} draw\n * @param {number} start\n * @param {AnimationRule} rule\n * @param {number} duration\n * @param {EndEventCallback} end\n * @param {Animation} anim\n */\nfunction step(time, draw, start, rule, duration, end, anim) {\n if (typeof rule !== 'function') {\n throw new TypeError('Invalid animation rule:', rule);\n }\n\n var progress = time - start;\n var percent = progress / duration;\n\n if (percent > 1) {\n percent = 1;\n }\n\n draw && draw(percent === 1 ? percent : rule(percent));\n\n if (progress < duration) {\n anim.frame = requestAnimationFrame(function (time) {\n return step(time, draw, start, rule, duration, end, anim);\n });\n } else {\n end && end();\n }\n}\n\n/**\n * Animation engine API for JavaScript-based animations.\n * This is simply an animation core framework which simplifies creation\n * of various animations for generic purposes.\n *\n * @example\n * // create 'linear' animation engine, 500ms duration\n * let linear = new Animation('linear', 500);\n *\n * // create 'elastic' animation engine\n * let elastic = new Animation('elastic');\n *\n * // define animation behavior\n * let bounced = new Animation('bounce', 500, percent => {\n * let value = parseInt(percent * 100, 10);\n *\n * $('div.bounced').css({\n * width: value + '%',\n * height: value + '%'\n * });\n * });\n *\n * // execute animation\n * bounced.animate();\n *\n * // execute animation and handle when its finished\n * bounced.animate(null, () => {\n * console.log('Animation finished!');\n * });\n */\n\nvar Animation = function () {\n\n /**\n * @constructor\n * @param {string|AnimationRule} rule\n * @param {number} duration\n * @param {DrawEventCallback} [draw]\n * @param {EndEventCallback} [end]\n */\n function Animation() {\n var rule = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'linear';\n var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 250;\n var draw = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};\n var end = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};\n\n _classCallCheck(this, Animation);\n\n /**\n * Overall animation duration in milliseconds.\n * By default is equal to 250 ms.\n *\n * @type {number}\n */\n this.duration = duration;\n\n /**\n * Animation rule. By default is linear animation.\n * Animation rule is a subject to animation rules, which are\n * a simple object containing math-based methods for calculating\n * animation steps.\n *\n * @type {string|AnimationRule}\n */\n this.rule = rule;\n\n /**\n * Callback function for the animation step draw event.\n *\n * @type {DrawEventCallback}\n */\n this.draw = draw;\n\n /**\n * Callback for the animation complete event.\n *\n * @type {EndEventCallback}\n */\n this.end = end;\n\n if (typeof this.draw !== 'function') {\n throw new TypeError('Invalid animation draw callback:', draw);\n }\n\n if (typeof this.end !== 'function') {\n throw new TypeError('Invalid animation end callback:', end);\n }\n }\n\n /* istanbul ignore next: non-testable */\n /**\n * Performs animation calling each animation step draw callback and\n * end callback at the end of animation. Callbacks are optional to this\n * method call. If them are not bypassed will be used that ones which\n * was pre-set on constructing an Animation object or pre-set after\n * construction.\n *\n * @example\n * function draw(percent) {\n * $('.my-animated-divs').css({\n * width: parseInt(percent * 100, 10) + '%'\n * });\n * }\n * function done() {\n * console.log('Animation complete!');\n * }\n *\n * // Define 'draw' and 'end' callbacks on construction\n * var animation = new Animation('cycle', 500, draw, done);\n * animation.animate();\n *\n * // Define 'draw' and 'end' callbacks after construction\n * var animation = new Animation('cycle', 500);\n * animation.draw = draw;\n * animation.end = done;\n * animation.animate();\n *\n * // Define 'draw' and 'end' callbacks at animation\n * var animation = new Animation('cycle', 500);\n * animation.animate(draw, done);\n *\n * @param {DrawEventCallback} [draw]\n * @param {EndEventCallback} [end]\n */\n\n\n _createClass(Animation, [{\n key: 'animate',\n value: function animate(draw, end) {\n var _this = this;\n\n //noinspection JSUnresolvedVariable\n var start = window.performance && window.performance.now ? window.performance.now() : vendorize('animationStartTime') || Date.now();\n\n draw = draw || this.draw;\n end = end || this.end;\n\n /**\n * Current requested animation frame identifier\n *\n * @type {number}\n */\n this.frame = requestAnimationFrame(function (time) {\n return step(time, draw, start, rules[_this.rule] || _this.rule, _this.duration, end, _this);\n });\n }\n\n /**\n * Destroys this object properly\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n if (this.frame) {\n var cancelAnimationFrame = vendorize('cancelAnimationFrame') ||\n /* istanbul ignore next */\n function (id) {};\n\n cancelAnimationFrame(this.frame);\n this.frame = null;\n }\n\n this.draw = null;\n this.end = null;\n }\n }]);\n\n return Animation;\n}();\n\n/**\n * Animation rules bound statically to Animation constructor.\n *\n * @type {AnimationRules}\n * @static\n */\n\n\nAnimation.rules = rules;\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/**\n * @typedef {{ constructor: function(options: GenericOptions): GaugeInterface, draw: function(): GaugeInterface, destroy: function, update: function(options: GenericOptions) }} GaugeInterface\n */\n/**\n * @typedef {{parse: function, stringify: function}} JSON\n * @external {JSON} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON\n */\n/**\n * @ignore\n * @typedef {{MutationObserver: function}} ns\n */\n\n/**\n * DOM Observer.\n * It will observe DOM document for a configured element types and\n * instantiate associated Types for an existing or newly added DOM elements\n *\n * @example\n * class ProgressBar {\n * constructor(options) {}\n * draw() {}\n * }\n *\n * // It will observe DOM document for elements
\n * // having attribute 'data-type=\"progress\"'\n * // and instantiate for each new instance of ProgressBar\n *\n * new DomParser({color: 'red'}, 'div', 'progress', ProgressBar);\n *\n * // assume we could have HTML like this\n * //
\n * // in this case all matching attributes names for a given options will be\n * // parsed and bypassed to an instance from HTML attributes\n */\n\nvar DomObserver = function () {\n\n /**\n * @constructor\n * @param {object} options\n * @param {string} element\n * @param {string} type\n */\n function DomObserver(options, element, type) {\n _classCallCheck(this, DomObserver);\n\n //noinspection JSUnresolvedVariable\n /**\n * Default instantiation options for the given type\n *\n * @type {Object}\n */\n this.options = options;\n\n /**\n * Name of an element to lookup/observe\n *\n * @type {string}\n */\n this.element = element.toLowerCase();\n\n /**\n * data-type attribute value to lookup\n *\n * @type {string}\n */\n this.type = DomObserver.toDashed(type);\n\n /**\n * Actual type constructor to instantiate for each found element\n *\n * @type {Function}\n */\n this.Type = ns[type];\n\n /**\n * Signals if mutations observer for this type or not\n *\n * @type {boolean}\n */\n this.mutationsObserved = false;\n\n /**\n * Flag specifies whenever the browser supports observing\n * of DOM tree mutations or not\n *\n * @type {boolean}\n */\n this.isObservable = !!window.MutationObserver;\n\n /* istanbul ignore next: this should be tested with end-to-end tests */\n if (!window.GAUGES_NO_AUTO_INIT) {\n DomObserver.domReady(this.traverse.bind(this));\n }\n }\n\n /**\n * Checks if given node is valid node to process\n *\n * @param {Node|HTMLElement} node\n * @returns {boolean}\n */\n\n\n _createClass(DomObserver, [{\n key: 'isValidNode',\n value: function isValidNode(node) {\n //noinspection JSUnresolvedVariable\n return !!(node.tagName && node.tagName.toLowerCase() === this.element && node.getAttribute('data-type') === this.type);\n }\n\n /**\n * Traverse entire current DOM tree and process matching nodes.\n * Usually it should be called only once on document initialization.\n */\n\n }, {\n key: 'traverse',\n value: function traverse() {\n var elements = document.getElementsByTagName(this.element);\n var i = 0,\n s = elements.length;\n\n /* istanbul ignore next: this should be tested with end-to-end tests */\n for (; i < s; i++) {\n this.process(elements[i]);\n }\n\n if (this.isObservable && !this.mutationsObserved) {\n new MutationObserver(this.observe.bind(this)).observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n attributeOldValue: true,\n characterDataOldValue: true\n });\n\n this.mutationsObserved = true;\n }\n }\n\n /**\n * Observes given mutation records for an elements to process\n *\n * @param {MutationRecord[]} records\n */\n\n }, {\n key: 'observe',\n value: function observe(records) {\n var i = 0;\n var s = records.length;\n\n /* istanbul ignore next: this should be tested with end-to-end tests */\n for (; i < s; i++) {\n var record = records[i];\n\n if (record.type === 'attributes' && record.attributeName === 'data-type' && this.isValidNode(record.target) && record.oldValue !== this.type) // skip false-positive mutations\n {\n setTimeout(this.process.bind(this, record.target));\n } else if (record.addedNodes && record.addedNodes.length) {\n var ii = 0;\n var ss = record.addedNodes.length;\n\n for (; ii < ss; ii++) {\n setTimeout(this.process.bind(this, record.addedNodes[ii]));\n }\n }\n }\n }\n\n /**\n * Parses given attribute value to a proper JavaScript value.\n * For example it will parse some stringified value to a proper type\n * value, e.g. 'true' => true, 'null' => null, '{\"prop\": 20}' => {prop: 20}\n *\n * @param {*} value\n * @return {*}\n */\n\n }, {\n key: 'process',\n\n\n /**\n * Processes a given node, instantiating a proper type constructor for it\n *\n * @param {Node|HTMLElement} node\n * @returns {GaugeInterface|null}\n */\n value: function process(node) {\n var _this2 = this;\n\n if (!this.isValidNode(node)) return null;\n\n var prop = void 0;\n var options = JSON.parse(JSON.stringify(this.options));\n var instance = null;\n\n for (prop in options) {\n /* istanbul ignore else: non-testable in most cases */\n if (options.hasOwnProperty(prop)) {\n var attributeName = DomObserver.toAttributeName(prop);\n var attributeValue = DomObserver.parse(node.getAttribute(attributeName));\n\n if (attributeValue !== null && attributeValue !== undefined) {\n options[prop] = attributeValue;\n }\n }\n }\n\n options.renderTo = node;\n instance = new this.Type(options);\n instance.draw && instance.draw();\n\n if (!this.isObservable) return instance;\n\n instance.observer = new MutationObserver(function (records) {\n records.forEach(function (record) {\n if (record.type === 'attributes') {\n var attr = record.attributeName.toLowerCase();\n var type = node.getAttribute(attr).toLowerCase();\n\n if (attr === 'data-type' && type && type !== _this2.type) {\n instance.observer.disconnect();\n delete instance.observer;\n instance.destroy && instance.destroy();\n } else if (attr.substr(0, 5) === 'data-') {\n var _prop = attr.substr(5).split('-').map(function (part, i) {\n return !i ? part : part.charAt(0).toUpperCase() + part.substr(1);\n }).join('');\n var _options = {};\n\n _options[_prop] = DomObserver.parse(node.getAttribute(record.attributeName));\n\n instance.update && instance.update(_options);\n }\n }\n });\n });\n\n //noinspection JSCheckFunctionSignatures\n instance.observer.observe(node, { attributes: true });\n\n return instance;\n }\n\n /**\n * Transforms camelCase string to dashed string\n *\n * @static\n * @param {string} camelCase\n * @return {string}\n */\n\n }], [{\n key: 'parse',\n value: function parse(value) {\n // parse boolean\n if (value === 'true') return true;\n if (value === 'false') return false;\n\n // parse undefined\n if (value === 'undefined') return undefined;\n\n // parse null\n if (value === 'null') return null;\n\n // Comma-separated strings to array parsing.\n // It won't match strings which contains non alphanumeric characters to\n // prevent strings like 'rgba(0,0,0,0)' or JSON-like from being parsed.\n // Typically it simply allows easily declare arrays as comma-separated\n // numbers or plain strings. If something more complicated is\n // required it can be declared using JSON format syntax\n if (/^[-+#.\\w\\d\\s]+(?:,[-+#.\\w\\d\\s]*)+$/.test(value)) {\n return value.split(',');\n }\n\n // parse JSON\n try {\n return JSON.parse(value);\n } catch (e) {}\n\n // plain value - no need to parse\n return value;\n }\n }, {\n key: 'toDashed',\n value: function toDashed(camelCase) {\n var arr = camelCase.split(/(?=[A-Z])/);\n var i = 1;\n var s = arr.length;\n var str = arr[0].toLowerCase();\n\n for (; i < s; i++) {\n str += '-' + arr[i].toLowerCase();\n }\n\n return str;\n }\n\n /**\n * Transforms dashed string to CamelCase representation\n *\n * @param {string} dashed\n * @param {boolean} [capitalized]\n * @return {string}\n */\n\n }, {\n key: 'toCamelCase',\n value: function toCamelCase(dashed) {\n var capitalized = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n\n var arr = dashed.split(/-/);\n var i = 0;\n var s = arr.length;\n var str = '';\n\n for (; i < s; i++) {\n if (!(i || capitalized)) {\n str += arr[i].toLowerCase();\n } else {\n str += arr[i][0].toUpperCase() + arr[i].substr(1).toLowerCase();\n }\n }\n\n return str;\n }\n\n /**\n * Transforms camel case property name to dash separated attribute name\n *\n * @static\n * @param {string} str\n * @returns {string}\n */\n\n }, {\n key: 'toAttributeName',\n value: function toAttributeName(str) {\n return 'data-' + DomObserver.toDashed(str);\n }\n\n /**\n * Cross-browser DOM ready handler\n *\n * @static\n * @param {Function} handler\n */\n\n }, {\n key: 'domReady',\n value: function domReady(handler) {\n if (/comp|inter|loaded/.test((window.document || {}).readyState + '')) return handler();\n\n if (window.addEventListener) window.addEventListener('DOMContentLoaded', handler, false);else if (window.attachEvent) window.attachEvent('onload', handler);\n }\n }]);\n\n return DomObserver;\n}();\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n\n/**\n * Drawings on canvas using hidden canvas as a cache for better\n * performance drawings during canvas animations. SmartCanvas also\n * adopts a canvas to\n */\n\n\nvar SmartCanvas = function () {\n\n /**\n * @constructor\n * @param {HTMLCanvasElement} canvas\n * @param {number} [width]\n * @param {number} [height]\n */\n function SmartCanvas(canvas, width, height) {\n _classCallCheck(this, SmartCanvas);\n\n SmartCanvas.collection.push(this);\n\n /**\n * Canvas base width\n *\n * @type {number}\n */\n this.width = width || 0;\n\n /**\n * Canvas base height\n *\n * @type {number}\n */\n this.height = height || 0;\n\n /**\n * Target drawings canvas element\n *\n * @type {HTMLCanvasElement}\n */\n this.element = canvas;\n\n this.init();\n }\n\n /**\n * Initializes canvases and contexts\n */\n\n\n _createClass(SmartCanvas, [{\n key: 'init',\n value: function init() {\n var pixelRatio = SmartCanvas.pixelRatio;\n\n this.element.width = this.width * pixelRatio;\n this.element.height = this.height * pixelRatio;\n\n this.element.style.width = this.width + 'px';\n this.element.style.height = this.height + 'px';\n\n /**\n * Canvas caching element\n *\n * @type {HTMLCanvasElement|Node}\n */\n this.elementClone = this.element.cloneNode(true);\n\n //noinspection JSUnresolvedVariable\n /**\n * Target drawings canvas element 2D context\n *\n * @type {CanvasRenderingContext2D}\n */\n this.context = this.element.getContext('2d');\n\n /**\n * Canvas caching element 2D context\n *\n * @type {CanvasRenderingContext2D}\n */\n this.contextClone = this.elementClone.getContext('2d');\n\n /**\n * Actual drawings width\n *\n * @type {number}\n */\n this.drawWidth = this.element.width;\n\n /**\n * Actual drawings height\n *\n * @type {number}\n */\n this.drawHeight = this.element.height;\n\n /**\n * X-coordinate of drawings zero point\n *\n * @type {number}\n */\n this.drawX = this.drawWidth / 2;\n\n /**\n * Y-coordinate of drawings zero point\n *\n * @type {number}\n */\n this.drawY = this.drawHeight / 2;\n\n /**\n * Minimal side length in pixels of the drawing\n *\n * @type {number}\n */\n this.minSide = this.drawX < this.drawY ? this.drawX : this.drawY;\n\n this.elementClone.initialized = false;\n\n this.contextClone.translate(this.drawX, this.drawY);\n this.contextClone.save();\n\n this.context.translate(this.drawX, this.drawY);\n this.context.save();\n\n this.context.max = this.contextClone.max = this.minSide;\n this.context.maxRadius = this.contextClone.maxRadius = null;\n }\n\n /**\n * Destroys this object, removing the references from memory\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n var index = SmartCanvas.collection.indexOf(this);\n\n /* istanbul ignore else */\n if (~index) {\n SmartCanvas.collection.splice(index, 1);\n }\n\n this.context.clearRect(-this.drawX, -this.drawY, this.drawWidth, this.drawHeight);\n\n // dereference all created elements\n this.context.max = null;\n delete this.context.max;\n\n this.context.maxRadius = null;\n delete this.context.maxRadius;\n\n this.context = null;\n this.contextClone = null;\n this.elementClone = null;\n this.element = null;\n\n /**\n * On canvas redraw event callback\n *\n * @type {function|null|undefined}\n */\n this.onRedraw = null;\n }\n\n /**\n * Commits the drawings\n */\n\n }, {\n key: 'commit',\n value: function commit() {\n var scale = SmartCanvas.pixelRatio;\n\n if (scale !== 1) {\n this.contextClone.scale(scale, scale);\n this.contextClone.save();\n }\n\n return this;\n }\n\n /**\n * Redraw this object\n */\n\n }, {\n key: 'redraw',\n value: function redraw() {\n this.init();\n\n /**\n * On canvas redraw event callback\n *\n * @type {function(): *}\n */\n this.onRedraw && this.onRedraw();\n\n return this;\n }\n\n /**\n * Returns current device pixel ratio\n *\n * @returns {number}\n */\n\n }], [{\n key: 'redraw',\n\n\n /**\n * Forces redraw all canvas in the current collection\n */\n value: function redraw() {\n var i = 0;\n var s = SmartCanvas.collection.length;\n\n for (; i < s; i++) {\n SmartCanvas.collection[i].redraw();\n }\n }\n }, {\n key: 'pixelRatio',\n get: function get() {\n /* istanbul ignore next */\n //noinspection JSUnresolvedVariable\n return window.devicePixelRatio || 1;\n }\n }]);\n\n return SmartCanvas;\n}();\n\nSmartCanvas.collection = [];\n\n/* istanbul ignore next: very browser-specific testing required to cover */\n//noinspection JSUnresolvedVariable\nif (window.matchMedia) {\n //noinspection JSUnresolvedFunction\n window.matchMedia('screen and (min-resolution: 2dppx)').addListener(SmartCanvas.redraw);\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Describes rendering target element. Can be either string identifier of\n * the element or the element itself.\n *\n * @typedef {HTMLElement|string} RenderTarget\n */\n\n/**\n * Highlight area definition.\n * It describes highlight area starting from value to value using\n * color. Color can be describes with hex, rgb or rgba value.\n *\n * @typedef {{ from: number, to: number, color: string}} Highlight\n */\n\n/**\n * Shared generic gauges options\n *\n * @type {{renderTo: RenderTarget, width: number, height: number, minValue: number, maxValue: number, value: number, units: string|boolean, majorTicks: number[]|string[], minorTicks: number, strokeTicks: boolean, animatedValue: boolean, animateOnInit: boolean, title: string|boolean, borders: boolean, valueInt: number, valueDec: number, majorTicksInt: number, majorTicksDec: number, animation: boolean, animationDuration: number, animationRule: string|AnimationRule, colorPlate: string, colorPlateEnd: string, colorMajorTicks: string, colorMinorTicks: string, colorTitle: string, colorUnits: string, colorNumbers: string, colorNeedle: string, colorNeedleEnd: string, colorValueText: string, colorValueTextShadow: string, colorBorderShadow: string, colorBorderOuter: string, colorBorderOuterEnd: string, colorBorderMiddle: string, colorBorderMiddleEnd: string, colorBorderInner: string, colorBorderInnerEnd: string, colorValueBoxRect: string, colorValueBoxRectEnd: string, colorValueBoxBackground: string, colorValueBoxShadow: string, colorNeedleShadowUp: string, colorNeedleShadowDown: string, needle: boolean, needleShadow: boolean, needleType: string, needleStart: number, needleEnd: number, needleWidth: number, borderOuterWidth: number, borderMiddleWidth: number, borderInnerWidth: number, borderShadowWidth: number, valueBox: boolean, valueBoxWidth: number, valueBoxStroke: number, valueText: string, valueTextShadow: boolean, valueBoxBorderRadius: number, highlights: Highlight[], highlightsWidth: number, fontNumbers: string, fontTitle: string, fontUnits: string, fontValue: string, fontTitleSize: number, fontValueSize: number, fontUnitsSize: number, fontNumbersSize: number, fontNumbersStyle: string, fontTitleStyle: string, fontUnitsStyle: string, fontValueStyle: string, fontNumbersWeight: string, fontTitleWeight: string, fontUnitsWeight: string, fontValueWeight: string, barWidth: number, barStrokeWidth: number, barProgress: boolean, colorBar: string, colorBarStroke: string, colorBarProgress: string, colorBarShadow: string, barShadow: number}} GenericOptions\n */\nvar GenericOptions = {\n // basic options\n renderTo: null,\n width: 0,\n height: 0,\n minValue: 0,\n maxValue: 100,\n value: 0,\n units: false,\n majorTicks: [0, 20, 40, 60, 80, 100],\n minorTicks: 10,\n strokeTicks: true,\n animatedValue: false,\n animateOnInit: false,\n title: false,\n borders: true,\n\n // number formats\n valueInt: 3,\n valueDec: 2,\n majorTicksInt: 1,\n majorTicksDec: 0,\n\n // animations\n animation: true,\n animationDuration: 500,\n animationRule: 'cycle',\n\n // colors\n colorPlate: '#fff',\n colorPlateEnd: '',\n colorMajorTicks: '#444',\n colorMinorTicks: '#666',\n colorTitle: '#888',\n colorUnits: '#888',\n colorNumbers: '#444',\n colorNeedle: 'rgba(240,128,128,1)',\n colorNeedleEnd: 'rgba(255,160,122,.9)',\n colorValueText: '#444',\n colorValueTextShadow: 'rgba(0,0,0,0.3)',\n colorBorderShadow: 'rgba(0,0,0,0.5)',\n colorBorderOuter: '#ddd',\n colorBorderOuterEnd: '#aaa',\n colorBorderMiddle: '#eee',\n colorBorderMiddleEnd: '#f0f0f0',\n colorBorderInner: '#fafafa',\n colorBorderInnerEnd: '#ccc',\n colorValueBoxRect: '#888',\n colorValueBoxRectEnd: '#666',\n colorValueBoxBackground: '#babab2',\n colorValueBoxShadow: 'rgba(0,0,0,1)',\n colorNeedleShadowUp: 'rgba(2,255,255,0.2)',\n colorNeedleShadowDown: 'rgba(188,143,143,0.45)',\n colorBarStroke: '#222',\n colorBar: '#ccc',\n colorBarProgress: '#888',\n colorBarShadow: '#000',\n\n fontNumbers: 'Arial',\n fontTitle: 'Arial',\n fontUnits: 'Arial',\n fontValue: 'Arial',\n\n fontNumbersSize: 20,\n fontTitleSize: 24,\n fontUnitsSize: 22,\n fontValueSize: 26,\n\n fontNumbersStyle: 'normal',\n fontTitleStyle: 'normal',\n fontUnitsStyle: 'normal',\n fontValueStyle: 'normal',\n\n fontNumbersWeight: 'normal',\n fontTitleWeight: 'normal',\n fontUnitsWeight: 'normal',\n fontValueWeight: 'normal',\n\n // needle\n needle: true,\n needleShadow: true,\n needleType: 'arrow',\n needleStart: 5,\n needleEnd: 85,\n needleWidth: 4,\n\n // borders\n borderOuterWidth: 3,\n borderMiddleWidth: 3,\n borderInnerWidth: 3,\n borderShadowWidth: 3,\n\n // value and highlights\n valueBox: true,\n valueBoxStroke: 5,\n valueBoxWidth: 0,\n valueText: '',\n valueTextShadow: true,\n valueBoxBorderRadius: 2.5,\n\n // highlights\n highlights: [{ from: 20, to: 60, color: '#eee' }, { from: 60, to: 80, color: '#ccc' }, { from: 80, to: 100, color: '#999' }],\n highlightsWidth: 15,\n\n // progress bar\n barWidth: 20, // percents\n barStrokeWidth: 0, // pixels\n barProgress: true,\n barShadow: 0\n};\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Gauge collections type.\n *\n * It is used ES5 declaration here, because babel\n * transpiles inheritance incorrectly in this case.\n *\n * @class Collection\n * @constructor\n */\nfunction Collection() {\n Array.prototype.constructor.apply(this, arguments);\n}\n\nCollection.prototype = Object.create(Array.prototype);\nCollection.prototype.constructor = Collection;\n\n/**\n * Returns gauge object by its identifier or index in the collection\n *\n * @param {string|number} id\n * @return {*}\n */\nCollection.prototype.get = function (id) {\n if (typeof id === 'string') {\n var i = 0;\n var s = this.length;\n\n for (; i < s; i++) {\n var canvas = this[i].options.renderTo.tagName ? this[i].options.renderTo :\n /* istanbul ignore next: should be tested with e2e tests */\n document.getElementById(this[i].options.renderTo || '');\n\n if (canvas.getAttribute('id') === id) {\n return this[i];\n }\n }\n } else if (typeof id === 'number') {\n return this[id];\n }\n\n return null;\n};\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nvar version = '2.1.0';\n\nvar round = Math.round;\nvar abs = Math.abs;\n\nvar gauges = new Collection();\n\ngauges.version = version;\n\n/**\n * Basic abstract BaseGauge class implementing common functionality\n * for different type of gauges.\n *\n * It should not be instantiated directly but must be extended by a final\n * gauge implementation.\n *\n * @abstract\n * @example\n *\n * class MyCoolGauge extends BaseGauge {\n *\n * // theses methods below MUST be implemented:\n *\n * constructor(options) {\n * // ... do something with options\n * super(options);\n * // ... implement anything else\n * }\n *\n * draw() {\n * // ... some implementation here\n * return this;\n * }\n * }\n */\n\nvar BaseGauge = function (_EventEmitter) {\n _inherits(BaseGauge, _EventEmitter);\n\n /**\n * Fired each time gauge is initialized on a page\n *\n * @event BaseGauge#init\n */\n\n /**\n * Fired each time gauge scene is rendered\n *\n * @event BaseGauge#render\n */\n\n /**\n * Fired each time gauge object is destroyed\n *\n * @event BaseGauge#destroy\n */\n\n /**\n * Fired each time before animation is started on the gauge\n *\n * @event BaseGauge#animationStart\n */\n\n /**\n * Fired each time animation scene is complete\n *\n * @event BaseGauge#animate\n * @type {number} percent\n * @type {number} value\n */\n\n /**\n * Fired each time animation is complete on the gauge\n *\n * @event BaseGauge#animationEnd\n */\n\n /**\n * @constructor\n * @abstract\n * @param {GenericOptions} options\n */\n function BaseGauge(options) {\n _classCallCheck(this, BaseGauge);\n\n var _this3 = _possibleConstructorReturn(this, (BaseGauge.__proto__ || Object.getPrototypeOf(BaseGauge)).call(this));\n\n var className = _this3.constructor.name;\n\n if (className === 'BaseGauge') {\n throw new TypeError('Attempt to instantiate abstract class!');\n }\n\n gauges.push(_this3);\n\n //noinspection JSUnresolvedVariable\n /**\n * Gauges version string\n *\n * @type {string}\n */\n _this3.version = version;\n\n /**\n * Gauge type class\n *\n * @type {BaseGauge} type\n */\n _this3.type = ns[className] || BaseGauge;\n\n /**\n * True if gauge has been drawn for the first time, false otherwise.\n *\n * @type {boolean}\n */\n _this3.initialized = false;\n\n options.minValue = parseFloat(options.minValue);\n options.maxValue = parseFloat(options.maxValue);\n options.value = parseFloat(options.value) || 0;\n\n if (!options.borders) {\n options.borderInnerWidth = options.borderMiddleWidth = options.borderOuterWidth = 0;\n }\n\n if (!options.renderTo) {\n throw TypeError('Canvas element was not specified when creating ' + 'the Gauge object!');\n }\n\n var canvas = options.renderTo.tagName ? options.renderTo :\n /* istanbul ignore next: to be tested with e2e tests */\n document.getElementById(options.renderTo);\n\n if (!(canvas instanceof HTMLCanvasElement)) {\n throw TypeError('Given gauge canvas element is invalid!');\n }\n\n options.width = parseFloat(options.width) || 0;\n options.height = parseFloat(options.height) || 0;\n\n if (!options.width || !options.height) {\n if (!options.width) options.width = canvas.parentNode ? canvas.parentNode.offsetWidth : canvas.offsetWidth;\n if (!options.height) options.height = canvas.parentNode ? canvas.parentNode.offsetHeight : canvas.offsetHeight;\n }\n\n /**\n * Gauge options\n *\n * @type {GenericOptions} options\n */\n _this3.options = options || {};\n\n if (_this3.options.animateOnInit) {\n _this3._value = _this3.options.value;\n _this3.options.value = _this3.options.minValue;\n }\n\n /**\n * @type {SmartCanvas} canvas\n */\n _this3.canvas = new SmartCanvas(canvas, options.width, options.height);\n _this3.canvas.onRedraw = _this3.draw.bind(_this3);\n\n /**\n * @type {Animation} animation\n */\n _this3.animation = new Animation(options.animationRule, options.animationDuration);\n return _this3;\n }\n\n /**\n * Sets new value for this gauge.\n * If gauge is animated by configuration it will trigger a proper animation.\n * Upsetting a value triggers gauge redraw.\n *\n * @param {number} value\n */\n\n\n _createClass(BaseGauge, [{\n key: 'update',\n\n\n /**\n * Updates gauge configuration options at runtime and redraws the gauge\n *\n * @param {RadialGaugeOptions} options\n * @returns {BaseGauge}\n */\n value: function update(options) {\n Object.assign(this.options, this.type.configure(options || {}));\n\n this.canvas.width = this.options.width;\n this.canvas.height = this.options.height;\n\n this.animation.rule = this.options.animationRule;\n this.animation.duration = this.options.animationDuration;\n\n this.canvas.redraw();\n\n return this;\n }\n\n /**\n * Performs destruction of this object properly\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n var index = gauges.indexOf(this);\n\n /* istanbul ignore else */\n if (~index) {\n //noinspection JSUnresolvedFunction\n gauges.splice(index, 1);\n }\n\n this.canvas.destroy();\n this.canvas = null;\n\n this.animation.destroy();\n this.animation = null;\n\n this.emit('destroy');\n }\n\n /**\n * Returns gauges version string\n *\n * @return {string}\n */\n\n }, {\n key: 'draw',\n\n\n /**\n * Triggering gauge render on a canvas.\n *\n * @abstract\n * @returns {BaseGauge}\n */\n value: function draw() {\n if (this.options.animateOnInit && !this.initialized) {\n this.value = this._value;\n this.initialized = true;\n this.emit('init');\n }\n\n this.emit('render');\n\n return this;\n }\n\n /**\n * Inject given gauge object into DOM\n *\n * @param {string} type\n * @param {GenericOptions} options\n */\n\n }, {\n key: 'value',\n set: function set(value) {\n var _this4 = this;\n\n value = BaseGauge.ensureValue(value, this.options.minValue);\n\n var fromValue = this.options.value;\n\n if (value === fromValue) return;\n\n if (this.options.animation) {\n /**\n * @type {number}\n * @access private\n */\n if (this._value === undefined) {\n this._value = value;\n }\n\n this.emit('animationStart');\n\n this.animation.animate(function (percent) {\n _this4.options.value = fromValue + (value - fromValue) * percent;\n\n _this4.draw();\n\n _this4.emit('animate', percent, _this4.options.value);\n }, function () {\n if (_this4._value !== undefined) {\n _this4.options.value = _this4._value;\n delete _this4._value;\n }\n\n _this4.draw();\n _this4.emit('animationEnd');\n });\n } else {\n this.options.value = value;\n this.draw();\n }\n }\n\n /**\n * Returns current value of the gauge\n *\n * @return {number}\n */\n ,\n get: function get() {\n return typeof this._value === 'undefined' ? this.options.value : this._value;\n }\n\n /**\n * Updates gauge options\n *\n * @param {*} options\n * @return {BaseGauge}\n * @access protected\n */\n\n }], [{\n key: 'configure',\n value: function configure(options) {\n return options;\n }\n }, {\n key: 'initialize',\n value: function initialize(type, options) {\n return new DomObserver(options, 'canvas', type);\n }\n\n /**\n * Initializes gauge from a given HTML element\n * (given element should be valid HTML canvas gauge definition)\n *\n * @param {HTMLElement} element\n */\n\n }, {\n key: 'fromElement',\n value: function fromElement(element) {\n var type = DomObserver.toCamelCase(element.getAttribute('data-type'));\n var attributes = element.attributes;\n var i = 0;\n var s = attributes.length;\n var options = {};\n\n if (!type) {\n return;\n }\n\n if (!/Gauge$/.test(type)) {\n type += 'Gauge';\n }\n\n for (; i < s; i++) {\n options[DomObserver.toCamelCase(attributes[i].name.replace(/^data-/, ''), false)] = DomObserver.parse(attributes[i].value);\n }\n\n new DomObserver(options, element.tagName, type).process(element);\n }\n\n /**\n * Ensures value is proper number\n *\n * @param {*} value\n * @param {number} min\n * @return {number}\n */\n\n }, {\n key: 'ensureValue',\n value: function ensureValue(value) {\n var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n\n value = parseFloat(value);\n\n if (isNaN(value) || !isFinite(value)) {\n value = parseFloat(min) || 0;\n }\n\n return value;\n }\n }, {\n key: 'version',\n get: function get() {\n return version;\n }\n }]);\n\n return BaseGauge;\n}(EventEmitter);\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n/* istanbul ignore if */\n\n\nif (typeof ns !== 'undefined') {\n ns['BaseGauge'] = BaseGauge;\n ns['gauges'] = (window.document || {})['gauges'] = gauges;\n}\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @access private\n * @typedef {CanvasRenderingContext2D|{max: number, maxRadius: number, barDimensions: object}} Canvas2DContext\n */\n\n/* istanbul ignore next: private, not testable */\n/**\n * Examines if a given error is something to throw or to ignore\n *\n * @param {Error} err\n */\nfunction verifyError(err) {\n // there is some unpredictable error in FF in some circumstances\n // which we found simply safe to ignore than to fight with it\n // noinspection JSUnresolvedVariable\n if (err instanceof DOMException && err.result === 0x8053000b) {\n return; // ignore it\n }\n\n throw err;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Prepares major ticks data\n *\n * @access private\n * @param {GenericOptions|{ tickSide: string }} options\n * @return {[boolean, boolean]}\n */\nfunction prepareTicks(options) {\n if (!(options.majorTicks instanceof Array)) {\n options.majorTicks = options.majorTicks ? [options.majorTicks] : [];\n }\n\n if (!options.majorTicks.length) {\n options.majorTicks.push(drawings.formatMajorTickNumber(options.minValue, options));\n options.majorTicks.push(drawings.formatMajorTickNumber(options.maxValue, options));\n }\n\n return [options.tickSide !== 'right', options.tickSide !== 'left'];\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws rounded corners rectangle\n *\n * @param {Canvas2DContext} context\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {number} r\n */\nfunction roundRect(context, x, y, w, h, r) {\n context.beginPath();\n\n context.moveTo(x + r, y);\n context.lineTo(x + w - r, y);\n\n context.quadraticCurveTo(x + w, y, x + w, y + r);\n context.lineTo(x + w, y + h - r);\n\n context.quadraticCurveTo(x + w, y + h, x + w - r, y + h);\n context.lineTo(x + r, y + h);\n\n context.quadraticCurveTo(x, y + h, x, y + h - r);\n context.lineTo(x, y + r);\n\n context.quadraticCurveTo(x, y, x + r, y);\n\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Pads a given value with leading zeros using the given options\n *\n * @param {number} val\n * @param {RadialGaugeOptions|{valueInt: number, valueDec: number}} options\n * @returns {string}\n */\nfunction padValue(val, options) {\n var dec = options.valueDec;\n var int = options.valueInt;\n var i = 0;\n var s = void 0,\n strVal = void 0,\n n = void 0;\n\n val = parseFloat(val);\n n = val < 0;\n val = Math.abs(val);\n\n if (dec > 0) {\n strVal = val.toFixed(dec).toString().split('.');\n s = int - strVal[0].length;\n\n for (; i < s; ++i) {\n strVal[0] = '0' + strVal[0];\n }\n\n strVal = (n ? '-' : '') + strVal[0] + '.' + strVal[1];\n } else {\n strVal = Math.round(val).toString();\n s = int - strVal.length;\n\n for (; i < s; ++i) {\n strVal = '0' + strVal;\n }\n\n strVal = (n ? '-' : '') + strVal;\n }\n\n return strVal;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Formats a number for display on the dial's plate using the majorTicksFormat\n * config option.\n *\n * @param {number} num number to format\n * @param {object} options\n * @returns {string} formatted number\n */\nfunction formatMajorTickNumber(num, options) {\n var right = void 0,\n hasDec = false;\n\n // First, force the correct number of digits right of the decimal.\n if (options.majorTicksDec === 0) {\n right = Math.round(num).toString();\n } else {\n right = num.toFixed(options.majorTicksDec);\n }\n\n // Second, force the correct number of digits left of the decimal.\n if (options.majorTicksInt > 1) {\n // Does this number have a decimal?\n hasDec = ~right.indexOf('.');\n\n // Is this number a negative number?\n if (~right.indexOf('-')) {\n return '-' + [options.majorTicksInt + options.majorTicksDec + 2 + (hasDec ? 1 : 0) - right.length].join('0') + right.replace('-', '');\n } else {\n return [options.majorTicksInt + options.majorTicksDec + 1 + (hasDec ? 1 : 0) - right.length].join('0') + right;\n }\n }\n\n return right;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Transforms degrees to radians\n *\n * @param {number} degrees\n * @returns {number}\n */\nfunction radians(degrees) {\n return degrees * Math.PI / 180;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Calculates and returns radial point coordinates\n *\n * @param {number} radius\n * @param {number} angle\n * @returns {{x: number, y: number}}\n */\nfunction radialPoint(radius, angle) {\n return { x: -radius * Math.sin(angle), y: radius * Math.cos(angle) };\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Creates and returns linear gradient canvas object\n *\n * @param {Canvas2DContext} context\n * @param {string} colorFrom\n * @param {string} colorTo\n * @param {number} length\n * @param {boolean} [isVertical]\n * @param {number} [from]\n * @returns {CanvasGradient}\n */\nfunction linearGradient(context, colorFrom, colorTo, length) {\n var isVertical = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;\n var from = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;\n\n var grad = context.createLinearGradient(isVertical ? 0 : from, isVertical ? from : 0, isVertical ? 0 : length, isVertical ? length : 0);\n\n grad.addColorStop(0, colorFrom);\n grad.addColorStop(1, colorTo);\n\n return grad;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws the shadow if it was not drawn\n *\n * @param {Canvas2DContext} context\n * @param {GenericOptions} options\n * @param {boolean} shadowDrawn\n * @return {boolean}\n */\nfunction drawShadow(context, options) {\n var shadowDrawn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n if (shadowDrawn) {\n context.restore();\n return true;\n }\n\n context.save();\n\n var w = options.borderShadowWidth;\n\n if (w) {\n context.shadowBlur = w;\n context.shadowColor = options.colorBorderShadow;\n }\n\n return true;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge needle shadow\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawNeedleShadow(context, options) {\n if (!options.needleShadow) return;\n\n context.shadowOffsetX = 2;\n context.shadowOffsetY = 2;\n context.shadowBlur = 10;\n context.shadowColor = options.colorNeedleShadowDown;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Constructs font styles for canvas fonts\n *\n * @param {GenericOptions} options\n * @param {string} target\n * @param {number} baseSize\n */\nfunction font(options, target, baseSize) {\n return options['font' + target + 'Style'] + ' ' + options['font' + target + 'Weight'] + ' ' + options['font' + target + 'Size'] * baseSize + 'px ' + options['font' + target];\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Resets some context settings\n *\n * @param {Canvas2DContext} context\n */\nfunction reset(context) {\n context.shadowOffsetX = null;\n context.shadowOffsetY = null;\n context.shadowBlur = null;\n context.shadowColor = '';\n context.strokeStyle = null;\n context.lineWidth = 0;\n context.save();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Declares to drow value text shadow if configured\n *\n * @param context\n * @param options\n * @param offset\n * @param blur\n */\nfunction drawValueTextShadow(context, options, offset, blur) {\n if (options.valueTextShadow) {\n context.shadowOffsetX = offset;\n context.shadowOffsetY = offset;\n context.shadowBlur = blur;\n context.shadowColor = options.colorValueTextShadow;\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws value box at given position\n *\n * @param {Canvas2DContext} context\n * @param {GenericOptions} options\n * @param {number|string} value\n * @param {number} x\n * @param {number} y\n * @param {number} max\n */\nfunction drawValueBox(context, options, value, x, y, max) {\n if (!options.valueBox) return;\n\n reset(context);\n\n var text = options.valueText || padValue(value, options);\n var tunit = max / 200;\n var runit = max / 100;\n var offset = 0.4 * runit;\n var blur = 1.2 * runit;\n\n context.font = font(options, 'Value', tunit);\n drawValueTextShadow(context, options, offset, blur);\n\n var tw = context.measureText(options.valueText ? text : '-' + padValue(0, options)).width;\n\n reset(context);\n\n var th = parseFloat(options.fontValueSize) * tunit + offset + blur;\n var sw = runit * parseFloat(options.valueBoxStroke);\n var bmax = max * 2 - sw * 2;\n\n var bw = tw + 10 * runit;\n var bh = 1.1 * th + offset + blur;\n var br = runit * options.valueBoxBorderRadius;\n var obw = (parseFloat(options.valueBoxWidth) || 0) / 100 * bmax;\n\n obw > bw && (bw = obw);\n bw > bmax && (bw = bmax);\n\n var bx = x - bw / 2;\n var by = y - bh / 2;\n var gy = y - 5.75 * runit;\n\n context.beginPath();\n\n if (br) roundRect(context, bx, by, bw, bh, br);else context.rect(bx, by, bw, bh);\n\n if (sw) {\n var grd = context.createRadialGradient(x, gy, runit * 10, x, gy, runit * 20);\n\n grd.addColorStop(0, options.colorValueBoxRect);\n grd.addColorStop(1, options.colorValueBoxRectEnd);\n\n context.strokeStyle = grd;\n context.lineWidth = sw;\n context.stroke();\n }\n\n if (options.colorValueBoxShadow) {\n context.shadowBlur = 1.2 * runit;\n context.shadowColor = options.colorValueBoxShadow;\n }\n\n if (options.colorValueBoxBackground) {\n context.fillStyle = options.colorValueBoxBackground;\n context.fill();\n }\n\n context.closePath();\n context.restore();\n\n drawValueTextShadow(context, options, offset, blur);\n\n context.fillStyle = options.colorValueText;\n context.textAlign = 'center';\n context.textBaseline = 'alphabetic';\n context.fillText(text, bx + bw / 2, y + bh / 2 - th / 3);\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Returns normalized value\n *\n * @param {GenericOptions} options\n * @return {{normal: number, indented: number}}\n */\nfunction normalizedValue(options) {\n var value = options.value;\n var min = options.minValue;\n var max = options.maxValue;\n var dt = (max - min) * 0.01;\n\n return {\n normal: value < min ? min : value > max ? max : value,\n indented: value < min ? min - dt : value > max ? max + dt : value\n };\n}\n\nvar drawings = {\n roundRect: roundRect,\n padValue: padValue,\n formatMajorTickNumber: formatMajorTickNumber,\n radians: radians,\n radialPoint: radialPoint,\n linearGradient: linearGradient,\n drawNeedleShadow: drawNeedleShadow,\n drawValueBox: drawValueBox,\n verifyError: verifyError,\n prepareTicks: prepareTicks,\n drawShadow: drawShadow,\n font: font,\n normalizedValue: normalizedValue\n};\n\ndrawings;\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nvar PI = Math.PI;\nvar HPI = PI / 2;\n\n/**\n * Gauge configuration options\n *\n * @typedef {GenericOptions|{ticksAngle: number, startAngle: number, colorNeedleCircleOuter: string, colorNeedleCircleOuterEnd: string, colorNeedleCircleInner: string, colorNeedleCircleInnerEnd: string, needleCircleSize: number, needleCircleInner: boolean, needleCircleOuter: boolean, animationTarget: string, useMinPath: boolean}} RadialGaugeOptions\n */\n\n/**\n * Default gauge configuration options\n *\n * @access private\n * @type {RadialGaugeOptions}\n */\nvar defaultRadialGaugeOptions = Object.assign({}, GenericOptions, {\n // basic options\n ticksAngle: 270,\n startAngle: 45,\n\n // colors\n colorNeedleCircleOuter: '#f0f0f0',\n colorNeedleCircleOuterEnd: '#ccc',\n colorNeedleCircleInner: '#e8e8e8',\n colorNeedleCircleInnerEnd: '#f5f5f5',\n\n // needle\n needleCircleSize: 10,\n needleCircleInner: true,\n needleCircleOuter: true,\n\n // custom animations\n animationTarget: 'needle', // 'needle' or 'plate'\n useMinPath: false,\n\n barWidth: 0\n});\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gradient-filled circle on a canvas\n *\n * @access private\n * @param {number} radius\n * @param {number} width\n * @param {Canvas2DContext} context\n * @param {string} start gradient start color\n * @param {string} end gradient end color\n */\nfunction drawRadialBorder(radius, width, context, start, end) {\n context.beginPath();\n //noinspection JSUnresolvedFunction\n context.arc(0, 0, abs(radius), 0, PI * 2, true);\n context.lineWidth = width;\n context.strokeStyle = end ? drawings.linearGradient(context, start, end, radius) : start;\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Returns max radius without borders for the gauge\n *\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n * @return {number}\n */\nfunction maxRadialRadius(context, options) {\n if (!context.maxRadius) {\n context.maxRadius = context.max - options.borderShadowWidth - options.borderOuterWidth - options.borderMiddleWidth - options.borderInnerWidth + (options.borderOuterWidth ? 0.5 : 0) + (options.borderMiddleWidth ? 0.5 : 0) + (options.borderInnerWidth ? 0.5 : 0);\n }\n\n return context.maxRadius;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge plate on the canvas\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialPlate(context, options) {\n var d0 = options.borderShadowWidth;\n var r0 = context.max - d0 - options.borderOuterWidth / 2;\n var r1 = r0 - options.borderOuterWidth / 2 - options.borderMiddleWidth / 2 + 0.5;\n var r2 = r1 - options.borderMiddleWidth / 2 - options.borderInnerWidth / 2 + 0.5;\n var r3 = maxRadialRadius(context, options);\n var grad = void 0;\n var shadowDrawn = false;\n\n context.save();\n\n if (options.borderOuterWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawRadialBorder(r0, options.borderOuterWidth, context, options.colorBorderOuter, options.colorBorderOuterEnd);\n }\n\n if (options.borderMiddleWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawRadialBorder(r1, options.borderMiddleWidth, context, options.colorBorderMiddle, options.colorBorderMiddleEnd);\n }\n\n if (options.borderInnerWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawRadialBorder(r2, options.borderInnerWidth, context, options.colorBorderInner, options.colorBorderInnerEnd);\n }\n\n drawings.drawShadow(context, options, shadowDrawn);\n\n context.beginPath();\n //noinspection JSUnresolvedFunction\n context.arc(0, 0, abs(r3), 0, PI * 2, true);\n\n if (options.colorPlateEnd) {\n grad = context.createRadialGradient(0, 0, r3 / 2, 0, 0, r3);\n grad.addColorStop(0, options.colorPlate);\n grad.addColorStop(1, options.colorPlateEnd);\n } else {\n grad = options.colorPlate;\n }\n\n context.fillStyle = grad;\n\n context.fill();\n context.closePath();\n\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge highlight areas on a canvas\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialHighlights(context, options) {\n var hlWidth = context.max * (parseFloat(options.highlightsWidth) || 0) / 100;\n\n if (!hlWidth) return;\n\n //noinspection JSUnresolvedFunction\n var r = abs(radialTicksRadius(context, options) - hlWidth / 2);\n var i = 0,\n s = options.highlights.length;\n var vd = (options.maxValue - options.minValue) / options.ticksAngle;\n\n context.save();\n\n for (; i < s; i++) {\n var hlt = options.highlights[i];\n\n context.beginPath();\n\n context.rotate(HPI);\n context.arc(0, 0, r, drawings.radians(options.startAngle + (hlt.from - options.minValue) / vd), drawings.radians(options.startAngle + (hlt.to - options.minValue) / vd), false);\n context.strokeStyle = hlt.color;\n context.lineWidth = hlWidth;\n context.stroke();\n context.closePath();\n\n context.restore();\n context.save();\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws minor ticks bar on a canvas\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialMinorTicks(context, options) {\n var radius = radialTicksRadius(context, options);\n\n context.lineWidth = SmartCanvas.pixelRatio;\n context.strokeStyle = options.colorMinorTicks;\n\n context.save();\n\n var s = options.minorTicks * (options.majorTicks.length - 1);\n var i = 0;\n\n for (; i < s; ++i) {\n var angle = options.startAngle + i * (options.ticksAngle / s);\n\n context.rotate(drawings.radians(angle));\n\n context.beginPath();\n context.moveTo(0, radius);\n context.lineTo(0, radius - context.max * 0.075);\n closeStrokedPath(context);\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Returns ticks radius\n *\n * @access private\n * @param context\n * @param options\n * @return {number}\n */\nfunction radialTicksRadius(context, options) {\n var unit = context.max / 100;\n\n return maxRadialRadius(context, options) - 5 * unit - (options.barWidth ? (parseFloat(options.barStrokeWidth) || 0) * 2 + ((parseFloat(options.barWidth) || 0) + 5) * unit : 0);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge major ticks bar on a canvas\n *\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialMajorTicks(context, options) {\n drawings.prepareTicks(options);\n\n //noinspection JSUnresolvedFunction\n var r = abs(radialTicksRadius(context, options));\n var i = void 0,\n colors = void 0;\n var s = options.majorTicks.length;\n var pixelRatio = SmartCanvas.pixelRatio;\n\n context.lineWidth = 2 * pixelRatio;\n context.save();\n\n colors = options.colorMajorTicks instanceof Array ? options.colorMajorTicks : new Array(s).fill(options.colorMajorTicks);\n\n i = 0;\n for (; i < s; ++i) {\n context.strokeStyle = colors[i];\n context.rotate(drawings.radians(radialNextAngle(options, i, s)));\n\n context.beginPath();\n context.moveTo(0, r);\n context.lineTo(0, r - context.max * 0.15);\n closeStrokedPath(context);\n }\n\n if (options.strokeTicks) {\n context.strokeStyle = colors[0];\n context.rotate(HPI);\n\n context.beginPath();\n context.arc(0, 0, r, drawings.radians(options.startAngle), drawings.radians(options.startAngle + options.ticksAngle), false);\n closeStrokedPath(context);\n }\n}\n\n/* istanbul ignore next: private, not testable */\nfunction radialNextAngle(options, i, s) {\n return options.startAngle + i * (options.ticksAngle / (s - 1));\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Strokes, closes path and restores previous context state\n *\n * @param {Canvas2DContext} context\n */\nfunction closeStrokedPath(context) {\n context.stroke();\n context.restore();\n context.closePath();\n context.save();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge bar numbers\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialNumbers(context, options) {\n var radius = radialTicksRadius(context, options) - context.max * 0.25;\n var points = {};\n var i = 0;\n var s = options.majorTicks.length;\n var isAnimated = options.animationTarget !== 'needle';\n var colors = options.colorNumbers instanceof Array ? options.colorNumbers : new Array(s).fill(options.colorNumbers);\n\n var plateValueAngle = isAnimated ? -(options.value - options.minValue) / (options.maxValue - options.minValue) * options.ticksAngle : 0;\n\n if (isAnimated) {\n context.save();\n context.rotate(-drawings.radians(plateValueAngle));\n }\n\n for (; i < s; ++i) {\n var angle = plateValueAngle + radialNextAngle(options, i, s);\n var point = drawings.radialPoint(radius, drawings.radians(angle));\n\n if (angle === 360) angle = 0;\n\n if (points[angle]) {\n continue; //already drawn at this place, skipping\n }\n\n points[angle] = true;\n\n context.font = drawings.font(options, 'Numbers', context.max / 200);\n context.fillStyle = colors[i];\n context.lineWidth = 0;\n context.textAlign = 'center';\n context.fillText(options.majorTicks[i], point.x, point.y + 3);\n }\n\n isAnimated && context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge title\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialTitle(context, options) {\n if (!options.title) return;\n\n context.save();\n context.font = drawings.font(options, 'Title', context.max / 200);\n context.fillStyle = options.colorTitle;\n context.textAlign = 'center';\n context.fillText(options.title, 0, -context.max / 4.25, context.max * 0.8);\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws units name on the gauge\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialUnits(context, options) {\n if (!options.units) return;\n\n context.save();\n context.font = drawings.font(options, 'Units', context.max / 200);\n context.fillStyle = options.colorUnits;\n context.textAlign = 'center';\n context.fillText(options.units, 0, context.max / 3.25, context.max * 0.8);\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge needle\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialNeedle(context, options) {\n if (!options.needle) return;\n\n var value = options.ticksAngle < 360 ? drawings.normalizedValue(options).indented : options.value;\n var max = maxRadialRadius(context, options);\n //noinspection JSUnresolvedFunction\n var r1 = abs(max / 100 * options.needleCircleSize);\n //noinspection JSUnresolvedFunction\n var r2 = abs(max / 100 * options.needleCircleSize * 0.75);\n //noinspection JSUnresolvedFunction\n var rIn = abs(max / 100 * options.needleEnd);\n //noinspection JSUnresolvedFunction\n var rStart = abs(options.needleStart ? max / 100 * options.needleStart : 0);\n //noinspection JSUnresolvedFunction\n var rOut = abs(max * 0.2);\n var pad1 = max / 100 * options.needleWidth;\n var pad2 = max / 100 * options.needleWidth / 2;\n var pixelRatio = SmartCanvas.pixelRatio;\n var isFixed = options.animationTarget !== 'needle';\n\n context.save();\n\n drawings.drawNeedleShadow(context, options);\n\n context.rotate(drawings.radians(isFixed ? options.startAngle : options.startAngle + (value - options.minValue) / (options.maxValue - options.minValue) * options.ticksAngle));\n\n context.fillStyle = drawings.linearGradient(context, options.colorNeedle, options.colorNeedleEnd, rIn - rOut);\n\n if (options.needleType === 'arrow') {\n context.beginPath();\n context.moveTo(-pad2, -rOut);\n context.lineTo(-pad1, 0);\n context.lineTo(-1 * pixelRatio, rIn);\n context.lineTo(pixelRatio, rIn);\n context.lineTo(pad1, 0);\n context.lineTo(pad2, -rOut);\n context.closePath();\n context.fill();\n\n context.beginPath();\n context.lineTo(-0.5 * pixelRatio, rIn);\n context.lineTo(-1 * pixelRatio, rIn);\n context.lineTo(-pad1, 0);\n context.lineTo(-pad2, -rOut);\n context.lineTo(pad2 / 2 * pixelRatio - 2 * pixelRatio, -rOut);\n context.closePath();\n context.fillStyle = options.colorNeedleShadowUp;\n context.fill();\n } else {\n // simple line needle\n context.beginPath();\n context.moveTo(-pad2, rIn);\n context.lineTo(-pad2, rStart);\n context.lineTo(pad2, rStart);\n context.lineTo(pad2, rIn);\n context.closePath();\n context.fill();\n }\n\n if (options.needleCircleSize) {\n context.restore();\n\n drawings.drawNeedleShadow(context, options);\n\n if (options.needleCircleOuter) {\n context.beginPath();\n context.arc(0, 0, r1, 0, PI * 2, true);\n context.fillStyle = drawings.linearGradient(context, options.colorNeedleCircleOuter, options.colorNeedleCircleOuterEnd, r1);\n context.fill();\n context.closePath();\n }\n\n if (options.needleCircleInner) {\n context.beginPath();\n context.arc(0, 0, r2, 0, PI * 2, true);\n context.fillStyle = drawings.linearGradient(context, options.colorNeedleCircleInner, options.colorNeedleCircleInnerEnd, r2);\n context.fill();\n context.closePath();\n }\n\n context.restore();\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge value box\n *\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n * @param {number} value\n */\nfunction drawRadialValueBox(context, options, value) {\n drawings.drawValueBox(context, options, value, 0, context.max - context.max * 0.33, context.max);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge progress bar\n *\n * @param {Canvas2DContext} context\n * @param {RadialGaugeOptions} options\n */\nfunction drawRadialProgressBar(context, options) {\n var unit = context.max / 100;\n var rMax = maxRadialRadius(context, options) - 5 * unit;\n var sw = parseFloat(options.barStrokeWidth) || 0;\n var w = (parseFloat(options.barWidth) || 0) * unit;\n var rMin = rMax - sw * 2 - w;\n var half = (rMax - rMin) / 2;\n var r = rMin + half;\n var delta = sw / r;\n var sa = options.startAngle;\n var ea = options.startAngle + options.ticksAngle;\n\n context.save();\n context.rotate(HPI);\n\n if (sw) {\n // draw stroke\n context.beginPath();\n context.arc(0, 0, r, drawings.radians(sa) - delta, drawings.radians(ea) + delta, false);\n context.strokeStyle = options.colorBarStroke;\n context.lineWidth = half * 2;\n context.stroke();\n context.closePath();\n }\n\n if (w) {\n // draw bar\n context.beginPath();\n context.arc(0, 0, r, drawings.radians(sa), drawings.radians(ea), false);\n context.strokeStyle = options.colorBar;\n context.lineWidth = w;\n context.stroke();\n context.closePath();\n\n if (options.barShadow) {\n // draw shadow\n context.beginPath();\n context.arc(0, 0, rMax, drawings.radians(sa), drawings.radians(ea), false);\n context.clip();\n\n context.beginPath();\n context.strokeStyle = options.colorBar;\n context.lineWidth = 1;\n context.shadowBlur = options.barShadow;\n context.shadowColor = options.colorBarShadow;\n context.shadowOffsetX = 0;\n context.shadowOffsetY = 0;\n context.arc(0, 0, rMax, drawings.radians(options.startAngle), drawings.radians(options.startAngle + options.ticksAngle), false);\n context.stroke();\n context.closePath();\n\n context.restore();\n context.rotate(HPI);\n }\n\n // draw bar progress\n if (options.barProgress) {\n context.beginPath();\n context.arc(0, 0, r, drawings.radians(sa), drawings.radians(sa + (drawings.normalizedValue(options).normal - options.minValue) / (options.maxValue - options.minValue) * options.ticksAngle), false);\n context.strokeStyle = options.colorBarProgress;\n context.lineWidth = w;\n context.stroke();\n context.closePath();\n }\n }\n\n context.restore();\n}\n\n/**\n * Find and return gauge value to display\n *\n * @param {RadialGauge} gauge\n */\nfunction displayValue(gauge) {\n if (gauge.options.animatedValue) {\n return gauge.options.value;\n }\n\n return gauge.value;\n}\n\n/**\n * Minimalistic HTML5 Canvas Gauge\n * @example\n * var gauge = new RadialGauge({\n * renderTo: 'gauge-id', // identifier of HTML canvas element or element itself\n * width: 400,\n * height: 400,\n * units: 'Km/h',\n * title: false,\n * value: 0,\n * minValue: 0,\n * maxValue: 220,\n * majorTicks: [\n * '0','20','40','60','80','100','120','140','160','180','200','220'\n * ],\n * minorTicks: 2,\n * strokeTicks: false,\n * highlights: [\n * { from: 0, to: 50, color: 'rgba(0,255,0,.15)' },\n * { from: 50, to: 100, color: 'rgba(255,255,0,.15)' },\n * { from: 100, to: 150, color: 'rgba(255,30,0,.25)' },\n * { from: 150, to: 200, color: 'rgba(255,0,225,.25)' },\n * { from: 200, to: 220, color: 'rgba(0,0,255,.25)' }\n * ],\n * colorPlate: '#222',\n * colorMajorTicks: '#f5f5f5',\n * colorMinorTicks: '#ddd',\n * colorTitle: '#fff',\n * colorUnits: '#ccc',\n * colorNumbers: '#eee',\n * colorNeedleStart: 'rgba(240, 128, 128, 1)',\n * colorNeedleEnd: 'rgba(255, 160, 122, .9)',\n * valueBox: true,\n * animationRule: 'bounce'\n * });\n * // draw initially\n * gauge.draw();\n * // animate\n * setInterval(() => {\n * gauge.value = Math.random() * -220 + 220;\n * }, 1000);\n */\n\nvar RadialGauge = function (_BaseGauge) {\n _inherits(RadialGauge, _BaseGauge);\n\n /**\n * Fired each time before gauge plate is drawn\n *\n * @event RadialGauge#beforePlate\n */\n\n /**\n * Fired each time before gauge highlight areas are drawn\n *\n * @event RadialGauge#beforeHighlights\n */\n\n /**\n * Fired each time before gauge minor ticks are drawn\n *\n * @event RadialGauge#beforeMinorTicks\n */\n\n /**\n * Fired each time before gauge major ticks are drawn\n *\n * @event RadialGauge#beforeMajorTicks\n */\n\n /**\n * Fired each time before gauge tick numbers are drawn\n *\n * @event RadialGauge#beforeNumbers\n */\n\n /**\n * Fired each time before gauge title is drawn\n *\n * @event RadialGauge#beforeTitle\n */\n\n /**\n * Fired each time before gauge units text is drawn\n *\n * @event RadialGauge#beforeUnits\n */\n\n /**\n * Fired each time before gauge progress bar is drawn\n *\n * @event RadialGauge#beforeProgressBar\n */\n\n /**\n * Fired each time before gauge value box is drawn\n *\n * @event RadialGauge#beforeValueBox\n */\n\n /**\n * Fired each time before gauge needle is drawn\n *\n * @event RadialGauge#beforeNeedle\n */\n\n /**\n * @constructor\n * @param {RadialGaugeOptions} options\n */\n function RadialGauge(options) {\n _classCallCheck(this, RadialGauge);\n\n options = Object.assign({}, defaultRadialGaugeOptions, options || {});\n return _possibleConstructorReturn(this, (RadialGauge.__proto__ || Object.getPrototypeOf(RadialGauge)).call(this, RadialGauge.configure(options)));\n }\n\n /**\n * Checks and updates gauge options properly\n *\n * @param {*} options\n * @return {*}\n * @access protected\n */\n\n\n _createClass(RadialGauge, [{\n key: 'draw',\n\n\n /**\n * Triggering gauge render on a canvas.\n *\n * @returns {RadialGauge}\n */\n value: function draw() {\n try {\n var canvas = this.canvas;\n var _ref = [-canvas.drawX, -canvas.drawY, canvas.drawWidth, canvas.drawHeight];\n var x = _ref[0];\n var y = _ref[1];\n var w = _ref[2];\n var h = _ref[3];\n\n var options = this.options;\n\n if (options.animationTarget === 'needle') {\n if (!canvas.elementClone.initialized) {\n var context = canvas.contextClone;\n\n // clear the cache\n context.clearRect(x, y, w, h);\n context.save();\n\n this.emit('beforePlate');\n drawRadialPlate(context, options);\n this.emit('beforeHighlights');\n drawRadialHighlights(context, options);\n this.emit('beforeMinorTicks');\n drawRadialMinorTicks(context, options);\n this.emit('beforeMajorTicks');\n drawRadialMajorTicks(context, options);\n this.emit('beforeNumbers');\n drawRadialNumbers(context, options);\n this.emit('beforeTitle');\n drawRadialTitle(context, options);\n this.emit('beforeUnits');\n drawRadialUnits(context, options);\n\n canvas.elementClone.initialized = true;\n }\n\n this.canvas.commit();\n\n // clear the canvas\n canvas.context.clearRect(x, y, w, h);\n canvas.context.save();\n\n canvas.context.drawImage(canvas.elementClone, x, y, w, h);\n canvas.context.save();\n\n this.emit('beforeProgressBar');\n drawRadialProgressBar(canvas.context, options);\n this.emit('beforeValueBox');\n drawRadialValueBox(canvas.context, options, displayValue(this));\n this.emit('beforeNeedle');\n drawRadialNeedle(canvas.context, options);\n } else {\n var plateValueAngle = -drawings.radians((options.value - options.minValue) / (options.maxValue - options.minValue) * options.ticksAngle);\n\n // clear the canvas\n canvas.context.clearRect(x, y, w, h);\n canvas.context.save();\n\n this.emit('beforePlate');\n drawRadialPlate(canvas.context, options);\n\n canvas.context.rotate(plateValueAngle);\n\n // animated\n this.emit('beforeHighlights');\n drawRadialHighlights(canvas.context, options);\n this.emit('beforeMinorTicks');\n drawRadialMinorTicks(canvas.context, options);\n this.emit('beforeMajorTicks');\n drawRadialMajorTicks(canvas.context, options);\n this.emit('beforeNumbers');\n drawRadialNumbers(canvas.context, options);\n this.emit('beforeProgressBar');\n drawRadialProgressBar(canvas.context, options);\n\n // non-animated\n canvas.context.rotate(-plateValueAngle);\n canvas.context.save();\n\n if (!canvas.elementClone.initialized) {\n var _context = canvas.contextClone;\n\n // clear the cache\n _context.clearRect(x, y, w, h);\n _context.save();\n\n this.emit('beforeTitle');\n drawRadialTitle(_context, options);\n this.emit('beforeUnits');\n drawRadialUnits(_context, options);\n this.emit('beforeNeedle');\n drawRadialNeedle(_context, options);\n\n canvas.elementClone.initialized = true;\n }\n\n canvas.context.drawImage(canvas.elementClone, x, y, w, h);\n }\n\n // value box animations\n this.emit('beforeValueBox');\n drawRadialValueBox(canvas.context, options, displayValue(this));\n\n _get(RadialGauge.prototype.__proto__ || Object.getPrototypeOf(RadialGauge.prototype), 'draw', this).call(this);\n } catch (err) {\n drawings.verifyError(err);\n }\n\n return this;\n }\n }, {\n key: 'value',\n\n\n /**\n * Sets the value for radial gauge\n *\n * @param {number} value\n */\n set: function set(value) {\n value = BaseGauge.ensureValue(value, this.options.minValue);\n\n if (this.options.animation && this.options.ticksAngle === 360 && this.options.useMinPath) {\n this._value = value;\n value = this.options.value + ((value - this.options.value) % 360 + 540) % 360 - 180;\n }\n\n _set(RadialGauge.prototype.__proto__ || Object.getPrototypeOf(RadialGauge.prototype), 'value', value, this);\n }\n\n /**\n * Returns current gauge value\n *\n * @return {number}\n */\n ,\n get: function get() {\n return _get(RadialGauge.prototype.__proto__ || Object.getPrototypeOf(RadialGauge.prototype), 'value', this);\n }\n }], [{\n key: 'configure',\n value: function configure(options) {\n if (options.barWidth > 50) options.barWidth = 50;\n\n /* istanbul ignore if */\n if (isNaN(options.startAngle)) options.startAngle = 45;\n /* istanbul ignore if */\n if (isNaN(options.ticksAngle)) options.ticksAngle = 270;\n\n /* istanbul ignore if */\n if (options.ticksAngle > 360) options.ticksAngle = 360;\n /* istanbul ignore if */\n if (options.ticksAngle < 0) options.ticksAngle = 0;\n\n /* istanbul ignore if */\n if (options.startAngle < 0) options.startAngle = 0;\n /* istanbul ignore if */\n if (options.startAngle > 360) options.startAngle = 360;\n\n return options;\n }\n }]);\n\n return RadialGauge;\n}(BaseGauge);\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n/* istanbul ignore if */\n\n\nif (typeof ns !== 'undefined') {\n ns['RadialGauge'] = RadialGauge;\n}\n\nBaseGauge.initialize('RadialGauge', defaultRadialGaugeOptions);\n\n/*!\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 Mykhailo Stadnyk \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Linear gauge configuration options\n *\n * @typedef {GenericOptions|{borderRadius: number, barBeginCircle: number, tickSide: string, needleSide: string, numberSide: string, ticksWidth: number, ticksWidthMinor: number, ticksPadding: number, barLength: number, colorBarEnd: string, colorBarProgressEnd: string}} LinearGaugeOptions\n */\n\n/**\n * Default linear gauge configuration options\n *\n * @type {LinearGaugeOptions}\n */\nvar defaultLinearGaugeOptions = Object.assign({}, GenericOptions, {\n // basic options\n borderRadius: 0,\n // width: 150,\n // height: 400,\n\n // bar\n barBeginCircle: 30, // percents\n colorBarEnd: '',\n colorBarProgressEnd: '',\n\n needleWidth: 6,\n\n tickSide: 'both', // available: 'left', 'right', 'both'\n needleSide: 'both', // available: 'left', 'right', 'both'\n\n numberSide: 'both', // available: 'left', 'right', 'both'\n\n ticksWidth: 10,\n ticksWidthMinor: 5,\n ticksPadding: 5,\n barLength: 85,\n fontTitleSize: 26,\n\n highlightsWidth: 10\n});\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws rectangle on a canvas\n *\n * @param {Canvas2DContext} context\n * @param {number} r radius for founded corner rectangle if 0 or less won't be drawn\n * @param {number} x x-coordinate of the top-left corner\n * @param {number} y y-coordinate of the top-left corner\n * @param {number} w width of the rectangle\n * @param {number} h height of the rectangle\n * @param {string} colorStart base fill color of the rectangle\n * @param {string} [colorEnd] gradient color of the rectangle\n */\nfunction drawRectangle(context, r, x, y, w, h, colorStart, colorEnd) {\n context.beginPath();\n context.fillStyle = colorEnd ? drawings.linearGradient(context, colorStart, colorEnd, w > h ? w : h, h > w, w > h ? x : y) : colorStart;\n\n r > 0 ? drawings.roundRect(context, x, y, w, h, r) : context.rect(x, y, w, h);\n\n context.fill();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws rectangle on a canvas\n *\n * @param {Canvas2DContext} context\n * @param {number} width width of the border\n * @param {number} r radius for founded corner rectangle if 0 or less won't be drawn\n * @param {number} x x-coordinate of the top-left corner\n * @param {number} y y-coordinate of the top-left corner\n * @param {number} w width of the rectangle\n * @param {number} h height of the rectangle\n * @param {string} colorStart base fill color of the rectangle\n * @param {string} [colorEnd] gradient color of the rectangle\n */\nfunction drawLinearBorder(context, width, r, x, y, w, h, colorStart, colorEnd) {\n context.beginPath();\n context.lineWidth = width;\n context.strokeStyle = colorEnd ? drawings.linearGradient(context, colorStart, colorEnd, h, true, y) : colorStart;\n\n r > 0 ? drawings.roundRect(context, x, y, w, h, r) : context.rect(x, y, w, h);\n\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge plate\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n */\nfunction drawLinearPlate(context, options, x, y, w, h) {\n context.save();\n\n var r = options.borderRadius;\n var w1 = w - options.borderShadowWidth - options.borderOuterWidth;\n var w2 = w1 - options.borderOuterWidth - options.borderMiddleWidth;\n var w3 = w2 - options.borderMiddleWidth - options.borderInnerWidth;\n var w4 = w3 - options.borderInnerWidth;\n\n var h1 = h - options.borderShadowWidth - options.borderOuterWidth;\n var h2 = h1 - options.borderOuterWidth - options.borderMiddleWidth;\n var h3 = h2 - options.borderMiddleWidth - options.borderInnerWidth;\n var h4 = h3 - options.borderInnerWidth;\n\n var x2 = x - (w2 - w1) / 2;\n var x3 = x2 - (w3 - w2) / 2;\n var x4 = x3 - (w4 - w3) / 2;\n\n var y2 = y - (h2 - h1) / 2;\n var y3 = y2 - (h3 - h2) / 2;\n var y4 = y3 - (h4 - h3) / 2;\n var aliasingOffset = 0;\n var shadowDrawn = false;\n\n if (options.borderOuterWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawLinearBorder(context, options.borderOuterWidth, r, x + options.borderOuterWidth / 2 - aliasingOffset, y + options.borderOuterWidth / 2 - aliasingOffset, w1, h1, options.colorBorderOuter, options.colorBorderOuterEnd);\n aliasingOffset += 0.5;\n }\n\n if (options.borderMiddleWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawLinearBorder(context, options.borderMiddleWidth, r -= 1 + aliasingOffset * 2, x2 + options.borderMiddleWidth / 2 - aliasingOffset, y2 + options.borderMiddleWidth / 2 - aliasingOffset, w2 + aliasingOffset * 2, h2 + aliasingOffset * 2, options.colorBorderMiddle, options.colorBorderMiddleEnd);\n aliasingOffset += 0.5;\n }\n\n if (options.borderInnerWidth) {\n shadowDrawn = drawings.drawShadow(context, options, shadowDrawn);\n drawLinearBorder(context, options.borderInnerWidth, r -= 1 + aliasingOffset * 2, x3 + options.borderInnerWidth / 2 - aliasingOffset, y3 + options.borderInnerWidth / 2 - aliasingOffset, w3 + aliasingOffset * 2, h3 + aliasingOffset * 2, options.colorBorderInner, options.colorBorderInnerEnd);\n aliasingOffset += 0.5;\n }\n\n drawings.drawShadow(context, options, shadowDrawn);\n\n drawRectangle(context, r, x4, y4, w4 + aliasingOffset * 2, h4 + aliasingOffset * 2, options.colorPlate, options.colorPlateEnd);\n\n context.restore();\n\n return [x4, y4, w4, h4];\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Calculates and returns linear gauge base bar dimensions.\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions|{barStrokeWidth: number, barBeginCircle: number, barWidth: number, hasLeft: boolean, hasRight: boolean}} options\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @return {{isVertical: boolean, width: number, length: number, barWidth: number, barLength: number, strokeWidth: number, barMargin: number, radius: number, x0: number, y0: number, barOffset: number, titleMargin: number, unitsMargin: number, X: number, Y: number, baseX: number, baseY: number, ticksPadding: number}}\n */\nfunction barDimensions(context, options, x, y, w, h) {\n var pixelRatio = SmartCanvas.pixelRatio;\n var isVertical = h >= w;\n var width = isVertical ? w * 0.85 : h;\n var length = isVertical ? h : w;\n\n //noinspection JSUnresolvedFunction\n x = isVertical ? round(x + (w - width) / 2) : x;\n\n var hasTitle = !!options.title;\n var hasUnits = !!options.units;\n var hasValue = !!options.valueBox;\n\n var titleMargin = void 0;\n var unitsMargin = void 0;\n var valueMargin = void 0;\n\n if (isVertical) {\n //noinspection JSUnresolvedFunction\n unitsMargin = round(length * 0.05);\n //noinspection JSUnresolvedFunction\n titleMargin = round(length * 0.075);\n //noinspection JSUnresolvedFunction\n valueMargin = round(length * 0.11);\n\n if (hasTitle) {\n length -= titleMargin;\n y += titleMargin;\n }\n\n if (hasUnits) length -= unitsMargin;\n if (hasValue) length -= valueMargin;\n } else {\n //noinspection JSUnresolvedFunction\n unitsMargin = titleMargin = round(width * 0.15);\n\n if (hasTitle) {\n width -= titleMargin;\n y += titleMargin;\n }\n\n if (hasUnits) width -= unitsMargin;\n }\n\n var strokeWidth = options.barStrokeWidth * 2;\n //noinspection JSUnresolvedFunction\n var radius = options.barBeginCircle ? round(width * options.barBeginCircle / 200 - strokeWidth / 2) : 0;\n //noinspection JSUnresolvedFunction\n var barWidth = round(width * options.barWidth / 100 - strokeWidth);\n //noinspection JSUnresolvedFunction\n var barLength = round(length * options.barLength / 100 - strokeWidth);\n //noinspection JSUnresolvedFunction\n var barMargin = round((length - barLength) / 2);\n\n // coordinates for arc of the bar if configured\n //noinspection JSUnresolvedFunction\n var x0 = round(x + (isVertical ? width / 2 : barMargin + radius));\n //noinspection JSUnresolvedFunction\n var y0 = round(y + (isVertical ? length - barMargin - radius + strokeWidth / 2 : width / 2));\n var dx = isVertical && !(options.hasLeft && options.hasRight) ? (options.hasRight ? -1 : 1) * options.ticksWidth / 100 * width : 0;\n var dy = !isVertical && !(options.hasLeft && options.hasRight) ? (options.hasRight ? -1 : 1) * options.ticksWidth / 100 * width : 0;\n\n //noinspection JSUndefinedPropertyAssignment\n context.barDimensions = {\n isVertical: isVertical,\n width: width,\n length: length,\n barWidth: barWidth,\n barLength: barLength,\n strokeWidth: strokeWidth,\n barMargin: barMargin,\n radius: radius,\n pixelRatio: pixelRatio,\n barOffset: null,\n titleMargin: hasTitle ? titleMargin : 0,\n unitsMargin: hasUnits ? unitsMargin : 0,\n get ticksLength() {\n return this.barLength - this.barOffset - this.strokeWidth;\n },\n X: x + dx,\n Y: y + dy,\n x0: x0 + dx,\n y0: y0 + dy,\n baseX: x,\n baseY: y,\n ticksPadding: options.ticksPadding / 100\n };\n\n return context.barDimensions;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws bar shape from the given options on a given canvas context\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {string} type\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n */\nfunction drawLinearBarShape(context, options, type, x, y, w, h) {\n var _barDimensions = barDimensions(context, options, x, y, w, h);\n\n var isVertical = _barDimensions.isVertical;\n var width = _barDimensions.width;\n var barWidth = _barDimensions.barWidth;\n var barLength = _barDimensions.barLength;\n var strokeWidth = _barDimensions.strokeWidth;\n var barMargin = _barDimensions.barMargin;\n var radius = _barDimensions.radius;\n var x0 = _barDimensions.x0;\n var y0 = _barDimensions.y0;\n var X = _barDimensions.X;\n var Y = _barDimensions.Y;\n\n var fullBarLength = barLength;\n\n context.save();\n context.beginPath();\n\n if (options.barBeginCircle) {\n var direction = drawings.radians(isVertical ? 270 : 0);\n var alpha = Math.asin(barWidth / 2 / radius);\n var cosAlpha = Math.cos(alpha);\n var sinAlpha = Math.sin(alpha);\n\n var x1 = x0 + (isVertical ? radius * sinAlpha : radius * cosAlpha - strokeWidth / 2);\n var y1 = isVertical ? y0 - radius * cosAlpha : y0 + radius * sinAlpha;\n //noinspection JSUnresolvedFunction\n var cutRadius = isVertical ? abs(y1 - y0) : abs(x1 - x0);\n\n //noinspection JSUnresolvedFunction\n context.barDimensions.barOffset = round(cutRadius + radius);\n\n // bottom point\n //noinspection JSUnresolvedFunction\n var x2 = isVertical ? round(x0 - radius * sinAlpha) : x1;\n //noinspection JSUnresolvedFunction\n var y2 = isVertical ? y1 : round(y0 - radius * sinAlpha);\n\n if (type === 'progress') {\n barLength = context.barDimensions.barOffset + (barLength - context.barDimensions.barOffset) * (drawings.normalizedValue(options).normal - options.minValue) / (options.maxValue - options.minValue);\n }\n\n // bar ends at\n //noinspection JSUnresolvedFunction\n var x3 = round(x1 + barLength - context.barDimensions.barOffset + strokeWidth / 2); // h\n //noinspection JSUnresolvedFunction\n var y3 = round(y1 - barLength + context.barDimensions.barOffset - strokeWidth / 2); // v\n\n context.arc(x0, y0, radius, direction + alpha, direction - alpha);\n\n if (isVertical) {\n context.moveTo(x1, y2);\n context.lineTo(x1, y3);\n context.lineTo(x2, y3);\n context.lineTo(x2, y2);\n } else {\n context.moveTo(x1, y2);\n context.lineTo(x3, y2);\n context.lineTo(x3, y1);\n context.lineTo(x1, y1);\n }\n } else {\n // simply rectangle\n //noinspection JSUnresolvedFunction\n var rx = round(isVertical ? X + (width - barWidth) / 2 : X + barMargin);\n //noinspection JSUnresolvedFunction\n var ry = round(isVertical ? Y + barLength + barMargin : Y + (width - barWidth) / 2);\n\n if (type === 'progress') {\n barLength *= (options.value - options.minValue) / (options.maxValue - options.minValue);\n }\n\n if (isVertical) context.rect(rx, ry, barWidth, -barLength);else context.rect(rx, ry, barLength, barWidth);\n }\n\n if (type !== 'progress' && options.barStrokeWidth) {\n context.lineWidth = strokeWidth;\n context.strokeStyle = options.colorBarStroke;\n //context.lineJoin = 'round';\n context.stroke();\n }\n\n if (type !== 'progress' && options.colorBar) {\n context.fillStyle = options.colorBarEnd ? drawings.linearGradient(context, options.colorBar, options.colorBarEnd, barLength, isVertical, isVertical ? Y : X) : options.colorBar;\n context.fill();\n } else if (type === 'progress' && options.colorBarProgress) {\n context.fillStyle = options.colorBarProgressEnd ? drawings.linearGradient(context, options.colorBarProgress, options.colorBarProgressEnd, fullBarLength, isVertical, isVertical ? Y : X) : options.colorBarProgress;\n context.fill();\n }\n\n context.closePath();\n\n // fix dimensions for further usage\n if (options.barBeginCircle) context.barDimensions.radius += strokeWidth;\n\n context.barDimensions.barWidth += strokeWidth;\n context.barDimensions.barLength += strokeWidth;\n}\n\n/**\n * Draws gauge bar\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} x x-coordinate of the top-left corner of the gauge\n * @param {number} y y-coordinate of the top-left corner of the gauge\n * @param {number} w width of the gauge\n * @param {number} h height of the gauge\n */\nfunction drawLinearBar(context, options, x, y, w, h) {\n drawLinearBarShape(context, options, '', x, y, w, h);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Helper function to calculate bar ticks presence on the sides\n *\n * @param {string} notWhich\n * @param {LinearGaugeOptions} options\n * @return {boolean}\n */\nfunction hasTicksBar(notWhich, options) {\n return options.needleSide !== notWhich || options.tickSide !== notWhich || options.numberSide !== notWhich;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge bar progress\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} x x-coordinate of the top-left corner of the gauge\n * @param {number} y y-coordinate of the top-left corner of the gauge\n * @param {number} w width of the gauge\n * @param {number} h height of the gauge\n */\nfunction drawLinearBarProgress(context, options, x, y, w, h) {\n options.barProgress && drawLinearBarShape(context, options, 'progress', x, y, w, h);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws gauge bar highlighted areas\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearBarHighlights(context, options) {\n var _context$barDimension = context.barDimensions;\n var isVertical = _context$barDimension.isVertical;\n var width = _context$barDimension.width;\n var length = _context$barDimension.length;\n var barWidth = _context$barDimension.barWidth;\n var barOffset = _context$barDimension.barOffset;\n var barMargin = _context$barDimension.barMargin;\n var X = _context$barDimension.X;\n var Y = _context$barDimension.Y;\n var ticksLength = _context$barDimension.ticksLength;\n var ticksPadding = _context$barDimension.ticksPadding;\n\n var hlWidth = width * (parseFloat(options.highlightsWidth) || 0) / 100;\n\n if (!options.highlights || !hlWidth) return;\n\n var hasLeft = options.tickSide !== 'right';\n var hasRight = options.tickSide !== 'left';\n var i = 0;\n var s = options.highlights.length;\n var tickOffset = (width - barWidth) / 2;\n var interval = options.maxValue - options.minValue;\n //noinspection JSUnresolvedFunction\n var eX = round(isVertical ? X + tickOffset : X + barMargin + barOffset);\n var eH = hlWidth;\n var eY = isVertical ? Y + length - barMargin - barOffset : Y + tickOffset;\n //noinspection JSUnresolvedFunction\n var hLeft = round((options.ticksWidth / 100 + ticksPadding) * width) + (hlWidth - options.ticksWidth / 100 * width);\n //noinspection JSUnresolvedFunction\n var hRight = round(barWidth + ticksPadding * width);\n\n context.save();\n\n for (; i < s; i++) {\n var entry = options.highlights[i];\n //noinspection JSUnresolvedFunction\n var eStart = ticksLength * abs(options.minValue - entry.from) / interval;\n //noinspection JSUnresolvedFunction\n var eW = ticksLength * abs((entry.to - entry.from) / interval);\n\n context.beginPath();\n context.fillStyle = entry.color;\n\n if (isVertical) {\n if (hasLeft) context.rect(eX - hLeft, eY - eStart, eH, -eW);\n\n if (hasRight) context.rect(eX + hRight, eY - eStart, eH, -eW);\n } else {\n if (hasLeft) context.rect(eX + eStart, eY - hLeft, eW, eH);\n\n if (hasRight) context.rect(eX + eStart, eY + hRight, eW, eH);\n }\n\n context.fill();\n context.closePath();\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws a tick line on a linear gauge\n *\n * @param {Canvas2DContext} context\n * @param x1\n * @param y1\n * @param x2\n * @param y2\n */\nfunction drawLinearTick(context, x1, y1, x2, y2) {\n context.beginPath();\n\n context.moveTo(x1, y1);\n context.lineTo(x2, y2);\n context.stroke();\n\n context.closePath();\n context.save();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws ticks\n *\n * @param {Canvas2DContext} context\n * @param {string} color\n * @param {number} ticksSize\n * @param {number} deltaLen\n * @param {boolean} hasLeft\n * @param {boolean} hasRight\n * @param {number} lineWidth\n * @param {number} lineLength\n */\nfunction drawLinearTicks(context, color, ticksSize, deltaLen, hasLeft, hasRight, lineWidth, lineLength) {\n var _context$barDimension2 = context.barDimensions;\n var isVertical = _context$barDimension2.isVertical;\n var length = _context$barDimension2.length;\n var barWidth = _context$barDimension2.barWidth;\n var barOffset = _context$barDimension2.barOffset;\n var barMargin = _context$barDimension2.barMargin;\n var pixelRatio = _context$barDimension2.pixelRatio;\n var width = _context$barDimension2.width;\n var X = _context$barDimension2.X;\n var Y = _context$barDimension2.Y;\n var ticksLength = _context$barDimension2.ticksLength;\n var ticksPadding = _context$barDimension2.ticksPadding;\n\n var tickOffset = (width - barWidth) / 2;\n var tickX = void 0,\n tickY = void 0;\n var i = 0;\n var tickLen = lineLength * width;\n var tickLeft = tickOffset - ticksPadding * width;\n var tickRight = tickOffset + barWidth + tickLen + ticksPadding * width;\n var tickSpace = ticksLength / (ticksSize - deltaLen);\n var colors = color instanceof Array ? color : new Array(ticksSize).fill(color);\n\n context.lineWidth = lineWidth * pixelRatio;\n context.save();\n\n for (; i < ticksSize; i++) {\n context.strokeStyle = colors[i];\n\n if (isVertical) {\n tickY = Y + length - barMargin - barOffset - i * tickSpace;\n\n if (hasLeft) {\n tickX = X + tickLeft;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, tickY, round(tickX - tickLen), tickY);\n }\n\n if (hasRight) {\n tickX = X + tickRight;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, tickY, round(tickX - tickLen), tickY);\n }\n } else {\n tickX = X + barMargin + barOffset + i * tickSpace;\n\n if (hasLeft) {\n tickY = Y + tickLeft;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, tickY, tickX, round(tickY - tickLen));\n }\n\n if (hasRight) {\n tickY = Y + tickRight;\n //noinspection JSUnresolvedFunction\n drawLinearTick(context, tickX, round(tickY), tickX, tickY - tickLen);\n }\n }\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws major ticks\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearMajorTicks(context, options) {\n var _drawings$prepareTick = drawings.prepareTicks(options);\n\n var _drawings$prepareTick2 = _slicedToArray(_drawings$prepareTick, 2);\n\n var hasLeft = _drawings$prepareTick2[0];\n var hasRight = _drawings$prepareTick2[1];\n\n var lineWidth = 2;\n var colors = options.colorMajorTicks instanceof Array ? options.colorMajorTicks : new Array(options.colorMajorTicks.length).fill(options.colorMajorTicks);\n\n drawLinearTicks(context, options.colorMajorTicks, options.majorTicks.length, 1, hasLeft, hasRight, lineWidth, options.ticksWidth / 100);\n\n if (options.strokeTicks) {\n var _context$barDimension3 = context.barDimensions;\n var isVertical = _context$barDimension3.isVertical;\n var length = _context$barDimension3.length;\n var width = _context$barDimension3.width;\n var barWidth = _context$barDimension3.barWidth;\n var barMargin = _context$barDimension3.barMargin;\n var barOffset = _context$barDimension3.barOffset;\n var X = _context$barDimension3.X;\n var Y = _context$barDimension3.Y;\n var ticksLength = _context$barDimension3.ticksLength;\n var pixelRatio = _context$barDimension3.pixelRatio;\n var ticksPadding = _context$barDimension3.ticksPadding;\n\n var rightTicks = (width - barWidth) / 2 + barWidth + ticksPadding * width;\n var leftTicks = (width - barWidth) / 2 - ticksPadding * width;\n var sX = void 0,\n sY = void 0,\n eX = void 0,\n eY = void 0;\n\n context.strokeStyle = colors[0];\n\n lineWidth *= pixelRatio;\n\n if (isVertical) {\n sY = Y + length - barMargin - barOffset + lineWidth / 2;\n eY = sY - ticksLength - lineWidth;\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n eX = sX = round(X + leftTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n eX = sX = round(X + rightTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n } else {\n sX = X + barMargin + barOffset - lineWidth / 2;\n eX = sX + ticksLength + lineWidth;\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n eY = sY = round(Y + leftTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n eY = sY = round(Y + rightTicks);\n drawLinearTickStroke(context, sX, sY, eX, eY);\n }\n }\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws ticks stroke\n *\n * @param {Canvas2DContext} context\n * @param {number} sX\n * @param {number} sY\n * @param {number} eX\n * @param {number} eY\n */\nfunction drawLinearTickStroke(context, sX, sY, eX, eY) {\n context.beginPath();\n context.moveTo(sX, sY);\n context.lineTo(eX, eY);\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws minor ticks\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearMinorTicks(context, options) {\n var _drawings$prepareTick3 = drawings.prepareTicks(options);\n\n var _drawings$prepareTick4 = _slicedToArray(_drawings$prepareTick3, 2);\n\n var hasLeft = _drawings$prepareTick4[0];\n var hasRight = _drawings$prepareTick4[1];\n\n\n drawLinearTicks(context, options.colorMinorTicks, options.minorTicks * (options.majorTicks.length - 1), 0, hasLeft, hasRight, 1, options.ticksWidthMinor / 100);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws major tick numbers\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearMajorTicksNumbers(context, options) {\n var _context$barDimension4 = context.barDimensions;\n var isVertical = _context$barDimension4.isVertical;\n var length = _context$barDimension4.length;\n var width = _context$barDimension4.width;\n var barWidth = _context$barDimension4.barWidth;\n var barMargin = _context$barDimension4.barMargin;\n var barOffset = _context$barDimension4.barOffset;\n var X = _context$barDimension4.X;\n var Y = _context$barDimension4.Y;\n var ticksLength = _context$barDimension4.ticksLength;\n var ticksPadding = _context$barDimension4.ticksPadding;\n\n var ticks = options.majorTicks.length;\n var hasLeft = options.numberSide !== 'right';\n var hasRight = options.numberSide !== 'left';\n var textHeight = options.fontNumbersSize * width / 200;\n var i = 0;\n var ticksWidth = (options.ticksWidth / 100 + ticksPadding * 2) * width;\n var numLeft = (width - barWidth) / 2 - ticksWidth;\n var numRight = (width - barWidth) / 2 + barWidth + ticksWidth;\n var textX = void 0,\n textY = void 0,\n textWidth = void 0,\n numberOffset = void 0,\n tick = void 0;\n var colors = options.colorNumbers instanceof Array ? options.colorNumbers : new Array(ticks).fill(options.colorNumbers);\n\n context.font = drawings.font(options, 'Numbers', width / 200);\n context.lineWidth = 0;\n context.textAlign = 'center';\n\n for (; i < ticks; i++) {\n context.fillStyle = colors[i];\n tick = options.majorTicks[i];\n numberOffset = i * ticksLength / (ticks - 1);\n\n if (isVertical) {\n textY = Y + length - barMargin - barOffset - numberOffset + textHeight / 3;\n\n if (hasLeft) {\n context.textAlign = 'right';\n context.fillText(tick, X + numLeft, textY);\n }\n\n if (hasRight) {\n context.textAlign = 'left';\n context.fillText(tick, X + numRight, textY);\n }\n } else {\n textWidth = context.measureText(tick).width;\n textX = X + barMargin + barOffset + numberOffset;\n\n if (hasLeft) {\n context.fillText(tick, textX, Y + numLeft);\n }\n\n if (hasRight) {\n context.fillText(tick, textX, Y + numRight + textHeight);\n }\n }\n }\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge title\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearTitle(context, options) {\n if (!options.title) return;\n\n var _context$barDimension5 = context.barDimensions;\n var isVertical = _context$barDimension5.isVertical;\n var width = _context$barDimension5.width;\n var length = _context$barDimension5.length;\n var baseX = _context$barDimension5.baseX;\n var baseY = _context$barDimension5.baseY;\n var titleMargin = _context$barDimension5.titleMargin;\n\n var textHeight = options.fontTitleSize * width / 200;\n //noinspection JSUnresolvedFunction\n var textX = round(baseX + (isVertical ? width : length) / 2);\n //noinspection JSUnresolvedFunction\n var textY = round(baseY + titleMargin / 2 - (isVertical ? textHeight : textHeight / 2) - 0.025 * (isVertical ? length : width));\n\n context.save();\n context.textAlign = 'center';\n context.fillStyle = options.colorTitle;\n context.font = drawings.font(options, 'Title', width / 200);\n context.lineWidth = 0;\n context.fillText(options.title, textX, textY, isVertical ? width : length);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge units\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearUnits(context, options) {\n if (!options.units) return;\n\n var _context$barDimension6 = context.barDimensions;\n var isVertical = _context$barDimension6.isVertical;\n var width = _context$barDimension6.width;\n var length = _context$barDimension6.length;\n var baseX = _context$barDimension6.baseX;\n var baseY = _context$barDimension6.baseY;\n var unitsMargin = _context$barDimension6.unitsMargin;\n\n var textHeight = options.fontUnitsSize * width / 200;\n //noinspection JSUnresolvedFunction\n var textX = round(baseX + (isVertical ? width : length) / 2);\n //noinspection JSUnresolvedFunction\n var textY = round(baseY + (isVertical ? length : width) + unitsMargin / 2 - textHeight / 2);\n\n context.save();\n context.textAlign = 'center';\n context.fillStyle = options.colorTitle;\n context.font = drawings.font(options, 'Units', width / 200);\n context.lineWidth = 0;\n context.fillText(options.units, textX, textY, isVertical ? width : length);\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws linear gauge needles\n *\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n */\nfunction drawLinearBarNeedle(context, options) {\n if (!options.needle) return;\n\n var _context$barDimension7 = context.barDimensions;\n var isVertical = _context$barDimension7.isVertical;\n var width = _context$barDimension7.width;\n var length = _context$barDimension7.length;\n var barWidth = _context$barDimension7.barWidth;\n var barOffset = _context$barDimension7.barOffset;\n var barMargin = _context$barDimension7.barMargin;\n var ticksLength = _context$barDimension7.ticksLength;\n var X = _context$barDimension7.X;\n var Y = _context$barDimension7.Y;\n var ticksPadding = _context$barDimension7.ticksPadding;\n\n var hasLeft = options.needleSide !== 'right';\n var hasRight = options.needleSide !== 'left';\n var position = ticksLength * (drawings.normalizedValue(options).indented - options.minValue) / (options.maxValue - options.minValue);\n var tickWidth = (options.ticksWidth / 100 + ticksPadding) * width;\n var baseLength = barWidth / 2 + tickWidth;\n var needleLength = baseLength * (options.needleEnd / 100);\n var sX = void 0,\n eX = void 0,\n sY = void 0,\n eY = void 0;\n var draw = options.needleType.toLowerCase() === 'arrow' ? drawLinearArrowNeedle : drawLinearLineNeedle;\n var barStart = (width - barWidth) / 2;\n var needleStart = baseLength * (options.needleStart / 100);\n var nLeft = barStart - tickWidth - needleStart;\n var nRight = barStart + barWidth + tickWidth + needleStart;\n\n context.save();\n\n drawings.drawNeedleShadow(context, options);\n\n if (isVertical) {\n //noinspection JSUnresolvedFunction\n sY = round(Y + length - barMargin - barOffset - position);\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n sX = round(X + nLeft);\n eX = sX + needleLength;\n draw(context, options, sX, sY, eX, sY, needleLength);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n sX = round(X + nRight);\n eX = sX - needleLength;\n draw(context, options, sX, sY, eX, sY, needleLength, true);\n }\n } else {\n //noinspection JSUnresolvedFunction\n sX = round(X + barMargin + barOffset + position);\n\n if (hasLeft) {\n //noinspection JSUnresolvedFunction\n sY = round(Y + nLeft);\n eY = sY + needleLength;\n draw(context, options, sX, sY, sX, eY, needleLength);\n }\n\n if (hasRight) {\n //noinspection JSUnresolvedFunction\n sY = round(Y + nRight);\n eY = sY - needleLength;\n draw(context, options, sX, sY, sX, eY, needleLength, true);\n }\n }\n\n context.restore();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Returns needle color style\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} length\n * @param {boolean} [isRight]\n * @return {CanvasGradient|string}\n */\nfunction needleStyle(context, options, length, isRight) {\n return options.colorNeedleEnd ? drawings.linearGradient(context, isRight ? options.colorNeedleEnd : options.colorNeedle, isRight ? options.colorNeedle : options.colorNeedleEnd, length, !context.barDimensions.isVertical) : options.colorNeedle;\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws line needle shape\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} sX\n * @param {number} sY\n * @param {number} eX\n * @param {number} eY\n * @param {number} length\n * @param {boolean} [isRight]\n */\nfunction drawLinearLineNeedle(context, options, sX, sY, eX, eY, length, isRight) {\n context.lineWidth = options.needleWidth;\n context.strokeStyle = needleStyle(context, options, length, isRight);\n\n context.beginPath();\n context.moveTo(sX, sY);\n context.lineTo(eX, eY);\n context.stroke();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws arrow needle shape\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} sX\n * @param {number} sY\n * @param {number} eX\n * @param {number} eY\n * @param {number} length\n * @param {boolean} [isRight]\n */\nfunction drawLinearArrowNeedle(context, options, sX, sY, eX, eY, length, isRight) {\n //noinspection JSUnresolvedFunction\n var peakLength = round(length * 0.4);\n var bodyLength = length - peakLength;\n var isVertical = sX === eX;\n var halfWidth = options.needleWidth / 2;\n\n context.fillStyle = needleStyle(context, options, length, isRight);\n\n context.beginPath();\n\n if (isVertical) {\n if (sY > eY) bodyLength *= -1;\n\n context.moveTo(sX - halfWidth, sY);\n context.lineTo(sX + halfWidth, sY);\n context.lineTo(sX + halfWidth, sY + bodyLength);\n context.lineTo(sX, eY);\n context.lineTo(sX - halfWidth, sY + bodyLength);\n context.lineTo(sX - halfWidth, sY);\n } else {\n if (sX > eX) bodyLength *= -1;\n\n context.moveTo(sX, sY - halfWidth);\n context.lineTo(sX, sY + halfWidth);\n context.lineTo(sX + bodyLength, sY + halfWidth);\n context.lineTo(eX, sY);\n context.lineTo(sX + bodyLength, sY - halfWidth);\n context.lineTo(sX, sY - halfWidth);\n }\n\n context.fill();\n context.closePath();\n}\n\n/* istanbul ignore next: private, not testable */\n/**\n * Draws value box for linear gauge\n *\n * @access private\n * @param {Canvas2DContext} context\n * @param {LinearGaugeOptions} options\n * @param {number} value\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n */\nfunction drawLinearValueBox(context, options, value, x, y, w, h) {\n // currently value box is available only for vertical linear gauge,\n // as far as by design it is hard to find a proper place for\n // horizontal ones\n var boxWidth = (parseFloat(options.fontValueSize) || 0) * w / 200;\n var dy = (0.11 * h - boxWidth) / 2;\n\n context.barDimensions.isVertical && drawings.drawValueBox(context, options, value, x + w / 2, y + h - boxWidth - dy, w);\n}\n\n/**\n * Minimalistic HTML5 Canvas Linear Gauge\n */\n\nvar LinearGauge = function (_BaseGauge2) {\n _inherits(LinearGauge, _BaseGauge2);\n\n /**\n * Fired each time before gauge plate is drawn\n *\n * @event LinearGauge#beforePlate\n */\n\n /**\n * Fired each time before gauge highlight areas are drawn\n *\n * @event LinearGauge#beforeHighlights\n */\n\n /**\n * Fired each time before gauge minor ticks are drawn\n *\n * @event LinearGauge#beforeMinorTicks\n */\n\n /**\n * Fired each time before gauge major ticks are drawn\n *\n * @event LinearGauge#beforeMajorTicks\n */\n\n /**\n * Fired each time before gauge tick numbers are drawn\n *\n * @event LinearGauge#beforeNumbers\n */\n\n /**\n * Fired each time before gauge title is drawn\n *\n * @event LinearGauge#beforeTitle\n */\n\n /**\n * Fired each time before gauge units text is drawn\n *\n * @event LinearGauge#beforeUnits\n */\n\n /**\n * Fired each time before gauge bar area is drawn\n *\n * @event LinearGauge#beforeBar\n */\n\n /**\n * Fired each time before gauge progress bar is drawn\n *\n * @event LinearGauge#beforeProgressBar\n */\n\n /**\n * Fired each time before gauge value box is drawn\n *\n * @event LinearGauge#beforeValueBox\n */\n\n /**\n * Fired each time before gauge needle is drawn\n *\n * @event LinearGauge#beforeNeedle\n */\n\n /**\n * @constructor\n * @param {LinearGaugeOptions} options\n */\n function LinearGauge(options) {\n _classCallCheck(this, LinearGauge);\n\n options = Object.assign({}, defaultLinearGaugeOptions, options || {});\n return _possibleConstructorReturn(this, (LinearGauge.__proto__ || Object.getPrototypeOf(LinearGauge)).call(this, LinearGauge.configure(options)));\n }\n\n /**\n * Checks and updates gauge options properly\n *\n * @param {*} options\n * @return {*}\n * @access protected\n */\n\n\n _createClass(LinearGauge, [{\n key: 'draw',\n\n\n /* istanbul ignore next */\n /**\n * Triggering linear gauge render on a canvas.\n *\n * @returns {LinearGauge}\n */\n value: function draw() {\n try {\n var canvas = this.canvas;\n var _ref2 = [-canvas.drawX, -canvas.drawY, canvas.drawWidth, canvas.drawHeight];\n var x = _ref2[0];\n var y = _ref2[1];\n var w = _ref2[2];\n var h = _ref2[3];\n\n var options = this.options;\n\n if (!canvas.elementClone.initialized) {\n var context = canvas.contextClone;\n\n // clear the cache\n context.clearRect(x, y, w, h);\n context.save();\n\n this.emit('beforePlate');\n this.drawBox = drawLinearPlate(context, options, x, y, w, h);\n\n this.emit('beforeBar');\n drawLinearBar.apply(undefined, [context, options].concat(_toConsumableArray(this.drawBox)));\n\n canvas.context.barDimensions = context.barDimensions;\n\n this.emit('beforeHighlights');\n drawLinearBarHighlights(context, options);\n this.emit('beforeMinorTicks');\n drawLinearMinorTicks(context, options);\n this.emit('beforeMajorTicks');\n drawLinearMajorTicks(context, options);\n this.emit('beforeNumbers');\n drawLinearMajorTicksNumbers(context, options);\n this.emit('beforeTitle');\n drawLinearTitle(context, options);\n this.emit('beforeUnits');\n drawLinearUnits(context, options);\n\n canvas.elementClone.initialized = true;\n }\n\n this.canvas.commit();\n\n // clear the canvas\n canvas.context.clearRect(x, y, w, h);\n canvas.context.save();\n\n canvas.context.drawImage(canvas.elementClone, x, y, w, h);\n canvas.context.save();\n\n this.emit('beforeProgressBar');\n drawLinearBarProgress.apply(undefined, [canvas.context, options].concat(_toConsumableArray(this.drawBox)));\n this.emit('beforeNeedle');\n drawLinearBarNeedle(canvas.context, options);\n this.emit('beforeValueBox');\n drawLinearValueBox.apply(undefined, [canvas.context, options, options.animatedValue ? this.options.value : this.value].concat(_toConsumableArray(this.drawBox)));\n\n _get(LinearGauge.prototype.__proto__ || Object.getPrototypeOf(LinearGauge.prototype), 'draw', this).call(this);\n } catch (err) {\n drawings.verifyError(err);\n }\n\n return this;\n }\n }], [{\n key: 'configure',\n value: function configure(options) {\n /* istanbul ignore else */\n if (options.barStrokeWidth >= options.barWidth) {\n //noinspection JSUnresolvedFunction\n options.barStrokeWidth = round(options.barWidth / 2);\n }\n\n //noinspection JSUndefinedPropertyAssignment\n options.hasLeft = hasTicksBar('right', options);\n //noinspection JSUndefinedPropertyAssignment\n options.hasRight = hasTicksBar('left', options);\n\n if (options.value > options.maxValue) {\n options.value = options.maxValue;\n }\n\n if (options.value < options.minValue) {\n options.value = options.minValue;\n }\n\n return BaseGauge.configure(options);\n }\n }]);\n\n return LinearGauge;\n}(BaseGauge);\n\n/**\n * @ignore\n * @typedef {object} ns\n */\n/* istanbul ignore if */\n\n\nif (typeof ns !== 'undefined') {\n ns['LinearGauge'] = LinearGauge;\n}\n\nBaseGauge.initialize('LinearGauge', defaultLinearGaugeOptions);;typeof module !== \"undefined\" && Object.assign(ns, {Collection: Collection,GenericOptions: GenericOptions,Animation: Animation,BaseGauge: BaseGauge,drawings: drawings,SmartCanvas: SmartCanvas,vendorize: vendorize});}(typeof module !== \"undefined\" ? module.exports : window));"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index c9779bb6..8ffc8130 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -11,6 +11,8 @@ const buffer = require('vinyl-buffer'); const rename = require('gulp-rename'); const sourcemaps = require('gulp-sourcemaps'); const uglify = require('gulp-uglify'); +const minify = require('gulp-uglify/minifier'); +const uglify6 = require('uglify-js-harmony'); const rimraf = require('rimraf'); const esdoc = require('gulp-esdoc'); const eslint = require('gulp-eslint'); @@ -40,10 +42,11 @@ const plato = require('gulp-plato'); let types = ['all', 'radial', 'linear']; -function es6concat(type = 'all') { +function es6concat(type = 'all', clean = false) { let bundle = [ 'lib/polyfill.js', 'lib/vendorize.js', + 'lib/EventEmitter.js', 'lib/Animation.js', 'lib/DomObserver.js', 'lib/SmartCanvas.js', @@ -53,6 +56,8 @@ function es6concat(type = 'all') { 'lib/drawings.js' ]; + if (clean) bundle.shift(); + switch (type.toLowerCase()) { case 'radial': case 'radial-gauge': @@ -76,8 +81,24 @@ function es6concat(type = 'all') { .pipe(replace(/%VERSION%/g, version)); } +function wrap(stream) { + return stream.pipe(replace(/^/, license() + '(function(ns) {')) + .pipe(replace(/$/, + ';typeof module !== "undefined" && Object.assign(ns, {' + + 'Collection: Collection,' + + 'GenericOptions: GenericOptions,' + + 'Animation: Animation,' + + 'BaseGauge: BaseGauge,' + + 'drawings: drawings,' + + 'SmartCanvas: SmartCanvas,' + + 'vendorize: vendorize' + + '});' + + '}(typeof module !== "undefined" ? ' + + 'module.exports : window));')); +} + function es5transpile(type = 'all', withSourceMaps = true, resolve = () => {}) { - let stream = es6concat(type) + let stream = wrap(es6concat(type) .pipe(rename('gauge.es5.js')) .pipe(babel({ presets: ['es2015'], @@ -88,20 +109,7 @@ function es5transpile(type = 'all', withSourceMaps = true, resolve = () => {}) { this.emit('end'); resolve(); }) - .pipe(rename('gauge.min.js')) - .pipe(replace(/^/, license() + '(function(ns) {')) - .pipe(replace(/$/, - ';typeof module !== "undefined" && Object.assign(ns, {' + - 'Collection: Collection,' + - 'GenericOptions: GenericOptions,' + - 'Animation: Animation,' + - 'BaseGauge: BaseGauge,' + - 'drawings: drawings,' + - 'SmartCanvas: SmartCanvas,' + - 'vendorize: vendorize' + - '});' + - '}(typeof module !== "undefined" ? ' + - 'module.exports : window));')); + .pipe(rename('gauge.min.js'))); if (withSourceMaps) { stream = stream.pipe(sourcemaps.init({ loadMaps: true })); @@ -167,6 +175,7 @@ gulp.task('help', () => usage(gulp, { emptyLineBetweenTasks: false })); * Builds production packages * * @task {build:prod} + * @order {5} */ gulp.task('build:prod', done => { rimraf('dist', () => { @@ -282,9 +291,13 @@ gulp.task('build:prod', done => { * * @task {build:es6} * @arg {type} build type: 'radial' - Gauge object only, 'linear' - LinearGauge object only, 'all' - everything (default) + * @order {4} */ gulp.task('build:es6', done => { - es6concat(yargs.argv.type || 'all') + es6concat(yargs.argv.type || 'all', true) + // .pipe(minify({ + // preserveComments: (node, comment) => comment.line === 1 + // }, uglify6)) .pipe(gulp.dest('.')) .on('end', () => done()); }); @@ -294,6 +307,7 @@ gulp.task('build:es6', done => { * * @task {build:es5} * @arg {type} build type: 'radial' - Gauge object only, 'linear' - LinearGauge object only, 'all' - everything (default) + * @order {3} */ gulp.task('build:es5', ['clean'], done => { es5transpile(yargs.argv.type || 'all') @@ -320,6 +334,7 @@ gulp.task('build:es5', ['clean'], done => { * Clean-ups files from previous build. * * @task {clean} + * @order {1} */ gulp.task('clean', done => { rimraf('gauge.js', () => @@ -332,6 +347,7 @@ gulp.task('clean', done => { * Cleans docs directory * * @task {clean:docs} + * @order {6} */ gulp.task('clean:docs', done => { rimraf('docs', done); @@ -342,6 +358,7 @@ gulp.task('clean:docs', done => { * from a source code. * * @task {doc} + * @order {7} */ gulp.task('doc', ['clean:docs'], done => { gulp.src('./lib') @@ -394,6 +411,7 @@ gulp.task('doc', ['clean:docs'], done => { * @task {build} * @arg {target} compile target, could be 'es5' (default) or 'es6' * @arg {type} build type: 'radial' - Gauge object only, 'linear' - LinearGauge object only, 'all' - everything (default) + * @order {2} */ gulp.task('build', () => { //noinspection JSUnresolvedVariable @@ -439,7 +457,8 @@ gulp.task('lint', () => { '!**.min.js', '!coverage/**', '!complexity/**', - '!dist/**' + '!dist/**', + '!test/cjs/**' ]) .pipe(eslint()) .pipe(eslint.format()) diff --git a/lib/Animation.js b/lib/Animation.js index 06e629d5..8b60558b 100644 --- a/lib/Animation.js +++ b/lib/Animation.js @@ -254,8 +254,8 @@ export default class Animation { */ animate(draw, end) { //noinspection JSUnresolvedVariable - const start = ns.performance && ns.performance.now ? - ns.performance.now() : + const start = window.performance && window.performance.now ? + window.performance.now() : (vendorize('animationStartTime') || Date.now()); draw = draw || this.draw; diff --git a/lib/BaseGauge.js b/lib/BaseGauge.js index 1fa1f1f6..20f9dc4d 100644 --- a/lib/BaseGauge.js +++ b/lib/BaseGauge.js @@ -27,6 +27,7 @@ const SmartCanvas = require('./SmartCanvas'); const Animation = require('./Animation'); const Collection = require('./Collection'); const DomObserver = require('./DomObserver'); +const EventEmitter = require('./EventEmitter'); const version = '%VERSION%'; @@ -63,7 +64,45 @@ gauges.version = version; * } * } */ -export default class BaseGauge { +export default class BaseGauge extends EventEmitter { + + /** + * Fired each time gauge is initialized on a page + * + * @event BaseGauge#init + */ + + /** + * Fired each time gauge scene is rendered + * + * @event BaseGauge#render + */ + + /** + * Fired each time gauge object is destroyed + * + * @event BaseGauge#destroy + */ + + /** + * Fired each time before animation is started on the gauge + * + * @event BaseGauge#animationStart + */ + + /** + * Fired each time animation scene is complete + * + * @event BaseGauge#animate + * @type {number} percent + * @type {number} value + */ + + /** + * Fired each time animation is complete on the gauge + * + * @event BaseGauge#animationEnd + */ /** * @constructor @@ -71,6 +110,8 @@ export default class BaseGauge { * @param {GenericOptions} options */ constructor(options) { + super(); + let className = this.constructor.name; if (className === 'BaseGauge') { @@ -92,7 +133,7 @@ export default class BaseGauge { * * @type {BaseGauge} type */ - this.type = ns[className]; + this.type = ns[className] || BaseGauge; /** * True if gauge has been drawn for the first time, false otherwise. @@ -168,31 +209,37 @@ export default class BaseGauge { * @param {number} value */ set value(value) { - value = parseFloat(value); - - if (isNaN(value) || !isFinite(value)) { - value = this.options.minValue; - } + value = BaseGauge.ensureValue(value, this.options.minValue); let fromValue = this.options.value; - if (value === this.options.value) return; + if (value === fromValue) return; if (this.options.animation) { /** * @type {number} * @access private */ - this._value = value; + if (this._value === undefined) { + this._value = value; + } + + this.emit('animationStart'); this.animation.animate(percent => { this.options.value = fromValue + (value - fromValue) * percent; this.draw(); + + this.emit('animate', percent, this.options.value); }, () => { - this.options.value = value; - delete this._value; + if (this._value !== undefined) { + this.options.value = this._value; + delete this._value; + } + this.draw(); + this.emit('animationEnd'); }); } @@ -212,6 +259,17 @@ export default class BaseGauge { this.options.value : this._value; } + /** + * Updates gauge options + * + * @param {*} options + * @return {BaseGauge} + * @access protected + */ + static configure(options) { + return options; + } + /** * Updates gauge configuration options at runtime and redraws the gauge * @@ -219,7 +277,7 @@ export default class BaseGauge { * @returns {BaseGauge} */ update(options) { - Object.assign(this.options, options || {}); + Object.assign(this.options, this.type.configure(options || {})); this.canvas.width = this.options.width; this.canvas.height = this.options.height; @@ -249,6 +307,8 @@ export default class BaseGauge { this.animation.destroy(); this.animation = null; + + this.emit('destroy'); } /** @@ -270,7 +330,12 @@ export default class BaseGauge { if (this.options.animateOnInit && !this.initialized) { this.value = this._value; this.initialized = true; + this.emit('init'); } + + this.emit('render'); + + return this; } /** @@ -280,7 +345,56 @@ export default class BaseGauge { * @param {GenericOptions} options */ static initialize(type, options) { - new DomObserver(options, 'canvas', type); + return new DomObserver(options, 'canvas', type); + } + + /** + * Initializes gauge from a given HTML element + * (given element should be valid HTML canvas gauge definition) + * + * @param {HTMLElement} element + */ + static fromElement(element) { + let type = DomObserver.toCamelCase(element.getAttribute('data-type')); + let attributes = element.attributes; + let i = 0; + let s = attributes.length; + let options = {}; + + if (!type) { + return ; + } + + if (!/Gauge$/.test(type)) { + type += 'Gauge'; + } + + for (; i < s; i++) { + options[ + DomObserver.toCamelCase( + attributes[i].name.replace(/^data-/, ''), + false) + ] = DomObserver.parse(attributes[i].value); + } + + new DomObserver(options, element.tagName, type).process(element); + } + + /** + * Ensures value is proper number + * + * @param {*} value + * @param {number} min + * @return {number} + */ + static ensureValue(value, min = 0) { + value = parseFloat(value); + + if (isNaN(value) || !isFinite(value)) { + value = parseFloat(min) || 0; + } + + return value; } } @@ -292,7 +406,7 @@ export default class BaseGauge { /* istanbul ignore if */ if (typeof ns !== 'undefined') { ns['BaseGauge'] = BaseGauge; - (ns.document || ns)['gauges'] = gauges; + ns['gauges'] = (window.document || {})['gauges'] = gauges; } module.exports = BaseGauge; diff --git a/lib/DomObserver.js b/lib/DomObserver.js index ef935d0f..fff8ab2a 100644 --- a/lib/DomObserver.js +++ b/lib/DomObserver.js @@ -106,10 +106,12 @@ export default class DomObserver { * * @type {boolean} */ - this.isObservable = !!ns.MutationObserver; + this.isObservable = !!window.MutationObserver; /* istanbul ignore next: this should be tested with end-to-end tests */ - DomObserver.domReady(this.traverse.bind(this)); + if (!window.GAUGES_NO_AUTO_INIT) { + DomObserver.domReady(this.traverse.bind(this)); + } } /** @@ -141,7 +143,7 @@ export default class DomObserver { } if (this.isObservable && !this.mutationsObserved) { - new ns.MutationObserver(this.observe.bind(this)) + new MutationObserver(this.observe.bind(this)) .observe(document.body, { childList: true, subtree: true, @@ -255,7 +257,7 @@ export default class DomObserver { if (!this.isObservable) return instance; - instance.observer = new ns.MutationObserver(records => { + instance.observer = new MutationObserver(records => { records.forEach(record => { if (record.type === 'attributes') { let attr = record.attributeName.toLowerCase(); @@ -309,6 +311,32 @@ export default class DomObserver { return str; } + /** + * Transforms dashed string to CamelCase representation + * + * @param {string} dashed + * @param {boolean} [capitalized] + * @return {string} + */ + static toCamelCase(dashed, capitalized = true) { + let arr = dashed.split(/-/); + let i = 0; + let s = arr.length; + let str = ''; + + for (; i < s; i++) { + if (!(i || capitalized)) { + str += arr[i].toLowerCase(); + } + + else { + str += arr[i][0].toUpperCase() + arr[i].substr(1).toLowerCase(); + } + } + + return str; + } + /** * Transforms camel case property name to dash separated attribute name * @@ -327,15 +355,16 @@ export default class DomObserver { * @param {Function} handler */ static domReady(handler) { - if (/comp|inter|loaded/.test((ns.document || {}).readyState + '')) + if (/comp|inter|loaded/.test((window.document || {}).readyState + '')) return handler(); - if (ns.addEventListener) - ns.addEventListener('DOMContentLoaded', handler, false); + if (window.addEventListener) + window.addEventListener('DOMContentLoaded', handler, false); - else if (ns.attachEvent) - ns.attachEvent('onload', handler); + else if (window.attachEvent) + window.attachEvent('onload', handler); } + } module.exports = DomObserver; diff --git a/lib/EventEmitter.js b/lib/EventEmitter.js new file mode 100644 index 00000000..6e238f47 --- /dev/null +++ b/lib/EventEmitter.js @@ -0,0 +1,145 @@ +/*! + * The MIT License (MIT) + * + * Copyright (c) 2016 Mykhailo Stadnyk + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Class EventEmitter - base event manager + */ +export default class EventEmitter { + /** + * @constructor + */ + constructor() { + this._events = {}; + + this.addListener = this.on; + this.removeListener = this.off; + } + + /** + * Returns all event listeners + * + * @return {object} + */ + get listeners() { + return this._events; + } + + /** + * Emits given event bypassing to each registered handler given args + * + * @param {string} event + * @param {...*} args + */ + emit(event, ...args) { + if (this._events[event]) { + let i = 0; + let s = this._events[event].length; + + for (; i < s; i++) { + this._events[event][i] && + this._events[event][i].apply(this, args); + } + } + } + + /** + * Registers given handler for given event to be called only once when + * event is emitted + * + * @param {string} event + * @param {...function} handlers + */ + once(event, ...handlers) { + let i = 0; + let s = handlers.length; + let self = this; + + for (; i < s; i++) { + let handler = handlers[i]; + let wrapper = function() { + self.off(event, wrapper); + handler.apply(self, arguments); + }; + + handlers[i] = wrapper; + } + + this.on.apply(this, [event].concat(handlers)); + } + + /** + * Registers given handlers for a given events to be called each time event + * is emitted + * + * @param {string} event + * @param {...function} handlers + */ + on(event, ...handlers) { + if (!this._events[event]) { + this._events[event] = []; + } + + let i = 0; + let s = handlers.length; + + for (; i < s; i++) { + this._events[event].push(handlers[i]); + } + } + + /** + * Un-registers previously registered event handlers + * + * @param {string} event + * @param {...function} handlers + */ + off(event, ...handlers) { + if (!this._events[event]) { + return ; + } + + let i = 0; + let s = handlers.length; + + for (; i < s; i++) { + let handler = handlers[i]; + let index; + + while (~(index = this._events[event].indexOf(handler))) { + this._events[event].splice(index, 1); + } + } + } + + /** + * Removes all listeners for a given event + * + * @param {string} event + */ + removeAllListeners(event) { + delete this._events[event]; + } +} + +module.exports = EventEmitter; diff --git a/lib/GenericOptions.js b/lib/GenericOptions.js index 93f6c63f..1fb3681a 100644 --- a/lib/GenericOptions.js +++ b/lib/GenericOptions.js @@ -40,7 +40,7 @@ /** * Shared generic gauges options * - * @type {{renderTo: RenderTarget, width: number, height: number, minValue: number, maxValue: number, value: number, units: string|boolean, majorTicks: number[]|string[], minorTicks: number, strokeTicks: boolean, animatedValue: boolean, animateOnInit: boolean, title: string|boolean, borders: boolean, valueInt: number, valueDec: number, majorTicksInt: number, majorTicksDec: number, animation: boolean, animationDuration: number, animationRule: string|AnimationRule, colorPlate: string, colorPlateEnd: string, colorMajorTicks: string, colorMinorTicks: string, colorTitle: string, colorUnits: string, colorNumbers: string, colorNeedle: string, colorNeedleEnd: string, colorValueText: string, colorValueTextShadow: string, colorBorderShadow: string, colorBorderOuter: string, colorBorderOuterEnd: string, colorBorderMiddle: string, colorBorderMiddleEnd: string, colorBorderInner: string, colorBorderInnerEnd: string, colorValueBoxRect: string, colorValueBoxRectEnd: string, colorValueBoxBackground: string, colorValueBoxShadow: string, colorNeedleShadowUp: string, colorNeedleShadowDown: string, needle: boolean, needleShadow: boolean, needleType: string, needleStart: number, needleEnd: number, needleWidth: number, borderOuterWidth: number, borderMiddleWidth: number, borderInnerWidth: number, borderShadowWidth: number, valueBox: boolean, valueBoxWidth: number, valueBoxStroke: number, valueText: string, valueTextShadow: boolean, valueBoxBorderRadius: number, highlights: Highlight[], highlightsWidth: number, fontNumbers: string, fontTitle: string, fontUnits: string, fontValue: string, fontTitleSize: number, fontValueSize: number, fontUnitsSize: number, fontNumbersSize: number, fontNumbersStyle: string, fontTitleStyle: string, fontUnitsStyle: string, fontValueStyle: string, fontNumbersWeight: string, fontTitleWeight: string, fontUnitsWeight: string, fontValueWeight: string}} GenericOptions + * @type {{renderTo: RenderTarget, width: number, height: number, minValue: number, maxValue: number, value: number, units: string|boolean, majorTicks: number[]|string[], minorTicks: number, strokeTicks: boolean, animatedValue: boolean, animateOnInit: boolean, title: string|boolean, borders: boolean, valueInt: number, valueDec: number, majorTicksInt: number, majorTicksDec: number, animation: boolean, animationDuration: number, animationRule: string|AnimationRule, colorPlate: string, colorPlateEnd: string, colorMajorTicks: string, colorMinorTicks: string, colorTitle: string, colorUnits: string, colorNumbers: string, colorNeedle: string, colorNeedleEnd: string, colorValueText: string, colorValueTextShadow: string, colorBorderShadow: string, colorBorderOuter: string, colorBorderOuterEnd: string, colorBorderMiddle: string, colorBorderMiddleEnd: string, colorBorderInner: string, colorBorderInnerEnd: string, colorValueBoxRect: string, colorValueBoxRectEnd: string, colorValueBoxBackground: string, colorValueBoxShadow: string, colorNeedleShadowUp: string, colorNeedleShadowDown: string, needle: boolean, needleShadow: boolean, needleType: string, needleStart: number, needleEnd: number, needleWidth: number, borderOuterWidth: number, borderMiddleWidth: number, borderInnerWidth: number, borderShadowWidth: number, valueBox: boolean, valueBoxWidth: number, valueBoxStroke: number, valueText: string, valueTextShadow: boolean, valueBoxBorderRadius: number, highlights: Highlight[], highlightsWidth: number, fontNumbers: string, fontTitle: string, fontUnits: string, fontValue: string, fontTitleSize: number, fontValueSize: number, fontUnitsSize: number, fontNumbersSize: number, fontNumbersStyle: string, fontTitleStyle: string, fontUnitsStyle: string, fontValueStyle: string, fontNumbersWeight: string, fontTitleWeight: string, fontUnitsWeight: string, fontValueWeight: string, barWidth: number, barStrokeWidth: number, barProgress: boolean, colorBar: string, colorBarStroke: string, colorBarProgress: string, colorBarShadow: string, barShadow: number}} GenericOptions */ const GenericOptions = { // basic options @@ -95,6 +95,10 @@ const GenericOptions = { colorValueBoxShadow: 'rgba(0,0,0,1)', colorNeedleShadowUp: 'rgba(2,255,255,0.2)', colorNeedleShadowDown: 'rgba(188,143,143,0.45)', + colorBarStroke: '#222', + colorBar: '#ccc', + colorBarProgress: '#888', + colorBarShadow: '#000', fontNumbers: 'Arial', fontTitle: 'Arial', @@ -104,7 +108,7 @@ const GenericOptions = { fontNumbersSize: 20, fontTitleSize: 24, fontUnitsSize: 22, - fontValueSize: 40, + fontValueSize: 26, fontNumbersStyle: 'normal', fontTitleStyle: 'normal', @@ -143,7 +147,13 @@ const GenericOptions = { { from: 20, to: 60, color: '#eee' }, { from: 60, to: 80, color: '#ccc' }, { from: 80, to: 100, color: '#999' }], - highlightsWidth: 15 + highlightsWidth: 15, + + // progress bar + barWidth: 20, // percents + barStrokeWidth: 0, // pixels + barProgress: true, + barShadow: 0 }; export default GenericOptions; diff --git a/lib/LinearGauge.js b/lib/LinearGauge.js index b71be07c..59531051 100644 --- a/lib/LinearGauge.js +++ b/lib/LinearGauge.js @@ -31,7 +31,7 @@ const SmartCanvas = require('./SmartCanvas'); /** * Linear gauge configuration options * - * @typedef {GenericOptions|{borderRadius: number, barBeginCircle: number, barWidth: number, barStrokeWidth: number, barProgress: boolean, colorBar: string, colorBarEnd: string, colorBarStroke: string, colorBarProgress: string, colorBarProgressEnd: string, tickSide: string, needleSide: string, numberSide: string, ticksWidth: number, ticksWidthMinor: number, ticksPadding: number, barLength: number}} LinearGaugeOptions + * @typedef {GenericOptions|{borderRadius: number, barBeginCircle: number, tickSide: string, needleSide: string, numberSide: string, ticksWidth: number, ticksWidthMinor: number, ticksPadding: number, barLength: number, colorBarEnd: string, colorBarProgressEnd: string}} LinearGaugeOptions */ /** @@ -47,14 +47,7 @@ let defaultLinearGaugeOptions = Object.assign({}, GenericOptions, { // bar barBeginCircle: 30, // percents - barWidth: 20, // percents - barStrokeWidth: 0, // pixels - barProgress: true, - - colorBarStroke: '#222', - colorBar: '#ccc', colorBarEnd: '', - colorBarProgress: '#888', colorBarProgressEnd: '', needleWidth: 6, @@ -250,7 +243,7 @@ function barDimensions(context, options, x, y, w, h) { //noinspection JSUnresolvedFunction titleMargin = round(length * 0.075); //noinspection JSUnresolvedFunction - valueMargin = round(length * 0.075); + valueMargin = round(length * 0.11); if (hasTitle) { length -= titleMargin; @@ -374,7 +367,7 @@ function drawLinearBarShape(context, options, type, x, y, w, h) { if (type === 'progress') { barLength = context.barDimensions.barOffset + (barLength - context.barDimensions.barOffset) * - (options.value - options.minValue) / + (drawings.normalizedValue(options).normal - options.minValue) / (options.maxValue - options.minValue); } @@ -535,7 +528,7 @@ function drawLinearBarHighlights(context, options) { for (; i < s; i++) { let entry = options.highlights[i]; //noinspection JSUnresolvedFunction - let eStart = ticksLength * abs(entry.from) / interval; + let eStart = ticksLength * abs(options.minValue - entry.from) / interval; //noinspection JSUnresolvedFunction let eW = ticksLength * abs((entry.to - entry.from) / interval); @@ -887,7 +880,7 @@ function drawLinearBarNeedle(context, options) { let hasLeft = options.needleSide !== 'right'; let hasRight = options.needleSide !== 'left'; let position = ticksLength * - (options.value - options.minValue) / + (drawings.normalizedValue(options).indented - options.minValue) / (options.maxValue - options.minValue); let tickWidth = (options.ticksWidth / 100 + ticksPadding) * width; let baseLength = (barWidth / 2 + tickWidth); @@ -1064,9 +1057,12 @@ function drawLinearValueBox(context, options, value, x, y, w, h) { // currently value box is available only for vertical linear gauge, // as far as by design it is hard to find a proper place for // horizontal ones + let boxWidth = (parseFloat(options.fontValueSize) || 0) * w / 200; + let dy = (0.11 * h - boxWidth) / 2; + context.barDimensions.isVertical && drawings.drawValueBox(context, options, value, x + w / 2, - y + h - (40 * (w / 300)), w); + y + h - boxWidth - dy, w); } /** @@ -1074,13 +1070,89 @@ function drawLinearValueBox(context, options, value, x, y, w, h) { */ export default class LinearGauge extends BaseGauge { + /** + * Fired each time before gauge plate is drawn + * + * @event LinearGauge#beforePlate + */ + + /** + * Fired each time before gauge highlight areas are drawn + * + * @event LinearGauge#beforeHighlights + */ + + /** + * Fired each time before gauge minor ticks are drawn + * + * @event LinearGauge#beforeMinorTicks + */ + + /** + * Fired each time before gauge major ticks are drawn + * + * @event LinearGauge#beforeMajorTicks + */ + + /** + * Fired each time before gauge tick numbers are drawn + * + * @event LinearGauge#beforeNumbers + */ + + /** + * Fired each time before gauge title is drawn + * + * @event LinearGauge#beforeTitle + */ + + /** + * Fired each time before gauge units text is drawn + * + * @event LinearGauge#beforeUnits + */ + + /** + * Fired each time before gauge bar area is drawn + * + * @event LinearGauge#beforeBar + */ + + /** + * Fired each time before gauge progress bar is drawn + * + * @event LinearGauge#beforeProgressBar + */ + + /** + * Fired each time before gauge value box is drawn + * + * @event LinearGauge#beforeValueBox + */ + + /** + * Fired each time before gauge needle is drawn + * + * @event LinearGauge#beforeNeedle + */ + /** * @constructor * @param {LinearGaugeOptions} options */ constructor(options) { options = Object.assign({}, defaultLinearGaugeOptions, options || {}); + super(LinearGauge.configure(options)); + } + /** + * Checks and updates gauge options properly + * + * @param {*} options + * @return {*} + * @access protected + */ + static configure(options) { /* istanbul ignore else */ if (options.barStrokeWidth >= options.barWidth) { //noinspection JSUnresolvedFunction @@ -1092,7 +1164,15 @@ export default class LinearGauge extends BaseGauge { //noinspection JSUndefinedPropertyAssignment options.hasRight = hasTicksBar('left', options); - super(options); + if (options.value > options.maxValue) { + options.value = options.maxValue; + } + + if (options.value < options.minValue) { + options.value = options.minValue; + } + + return BaseGauge.configure(options); } /* istanbul ignore next */ @@ -1119,17 +1199,25 @@ export default class LinearGauge extends BaseGauge { context.clearRect(x, y, w, h); context.save(); + this.emit('beforePlate'); this.drawBox = drawLinearPlate(context, options, x, y, w, h); + this.emit('beforeBar'); drawLinearBar(context, options, ...this.drawBox); canvas.context.barDimensions = context.barDimensions; + this.emit('beforeHighlights'); drawLinearBarHighlights(context, options); + this.emit('beforeMinorTicks'); drawLinearMinorTicks(context, options); + this.emit('beforeMajorTicks'); drawLinearMajorTicks(context, options); + this.emit('beforeNumbers'); drawLinearMajorTicksNumbers(context, options); + this.emit('beforeTitle'); drawLinearTitle(context, options); + this.emit('beforeUnits'); drawLinearUnits(context, options); canvas.elementClone.initialized = true; @@ -1144,8 +1232,11 @@ export default class LinearGauge extends BaseGauge { canvas.context.drawImage(canvas.elementClone, x, y, w, h); canvas.context.save(); + this.emit('beforeProgressBar'); drawLinearBarProgress(canvas.context, options, ...this.drawBox); + this.emit('beforeNeedle'); drawLinearBarNeedle(canvas.context, options); + this.emit('beforeValueBox'); drawLinearValueBox(canvas.context, options, options.animatedValue ? this.options.value : this.value, ...this.drawBox); diff --git a/lib/RadialGauge.js b/lib/RadialGauge.js index daabb30d..257a07f1 100644 --- a/lib/RadialGauge.js +++ b/lib/RadialGauge.js @@ -34,7 +34,7 @@ const HPI = PI / 2; /** * Gauge configuration options * - * @typedef {GenericOptions|{ticksAngle: number, startAngle: number, colorNeedleCircleOuter: string, colorNeedleCircleOuterEnd: string, colorNeedleCircleInner: string, colorNeedleCircleInnerEnd: string, needleCircleSize: number, needleCircleInner: boolean, needleCircleOuter: boolean, animationTarget: string}} RadialGaugeOptions + * @typedef {GenericOptions|{ticksAngle: number, startAngle: number, colorNeedleCircleOuter: string, colorNeedleCircleOuterEnd: string, colorNeedleCircleInner: string, colorNeedleCircleInnerEnd: string, needleCircleSize: number, needleCircleInner: boolean, needleCircleOuter: boolean, animationTarget: string, useMinPath: boolean}} RadialGaugeOptions */ /** @@ -60,7 +60,10 @@ const defaultRadialGaugeOptions = Object.assign({}, GenericOptions, { needleCircleOuter: true, // custom animations - animationTarget: 'needle' // 'needle' or 'plate' + animationTarget: 'needle', // 'needle' or 'plate' + useMinPath: false, + + barWidth: 0 }); /* istanbul ignore next: private, not testable */ @@ -266,7 +269,13 @@ function drawRadialMinorTicks(context, options) { * @return {number} */ function radialTicksRadius(context, options) { - return maxRadialRadius(context, options) - context.max * 0.05; + let unit = context.max / 100; + + return maxRadialRadius(context, options) - 5 * unit - + (options.barWidth ? + ((parseFloat(options.barStrokeWidth) || 0) * 2 + + ((parseFloat(options.barWidth) || 0) + 5) * unit) : + 0); } /* istanbul ignore next: private, not testable */ @@ -343,7 +352,7 @@ function closeStrokedPath(context) { * @param {RadialGaugeOptions} options */ function drawRadialNumbers(context, options) { - let radius = maxRadialRadius(context, options) - context.max * 0.35; + let radius = radialTicksRadius(context, options) - context.max * 0.25; let points = {}; let i = 0; let s = options.majorTicks.length; @@ -430,7 +439,8 @@ function drawRadialUnits(context, options) { function drawRadialNeedle(context, options) { if (!options.needle) return; - let value = options.value; + let value = options.ticksAngle < 360 ? + drawings.normalizedValue(options).indented : options.value; let max = maxRadialRadius(context, options); //noinspection JSUnresolvedFunction let r1 = abs(max / 100 * options.needleCircleSize); @@ -453,8 +463,9 @@ function drawRadialNeedle(context, options) { drawings.drawNeedleShadow(context, options); context.rotate(drawings.radians(isFixed ? options.startAngle : - (options.startAngle + (value - options.minValue) / - (options.maxValue - options.minValue) * options.ticksAngle))); + (options.startAngle + (value - + options.minValue) / (options.maxValue - options.minValue) * + options.ticksAngle))); context.fillStyle = drawings.linearGradient( context, @@ -542,6 +553,106 @@ function drawRadialValueBox(context, options, value) { context.max - context.max * 0.33, context.max); } +/* istanbul ignore next: private, not testable */ +/** + * Draws gauge progress bar + * + * @param {Canvas2DContext} context + * @param {RadialGaugeOptions} options + */ +function drawRadialProgressBar(context, options) { + let unit = context.max / 100; + let rMax = maxRadialRadius(context, options) - 5 * unit; + let sw = (parseFloat(options.barStrokeWidth) || 0); + let w = (parseFloat(options.barWidth) || 0) * unit; + let rMin = rMax - sw * 2 - w; + let half = (rMax- rMin) / 2; + let r = rMin + half; + let delta = sw / r; + let sa = options.startAngle; + let ea = options.startAngle + options.ticksAngle; + + context.save(); + context.rotate(HPI); + + if (sw) { + // draw stroke + context.beginPath(); + context.arc(0, 0, r, drawings.radians(sa) - delta, + drawings.radians(ea) + delta, false); + context.strokeStyle = options.colorBarStroke; + context.lineWidth = half * 2; + context.stroke(); + context.closePath(); + } + + if (w) { + // draw bar + context.beginPath(); + context.arc(0, 0, r, drawings.radians(sa), drawings.radians(ea), false); + context.strokeStyle = options.colorBar; + context.lineWidth = w; + context.stroke(); + context.closePath(); + + if (options.barShadow) { + // draw shadow + context.beginPath(); + context.arc(0, 0, rMax, drawings.radians(sa), drawings.radians(ea), + false); + context.clip(); + + context.beginPath(); + context.strokeStyle = options.colorBar; + context.lineWidth = 1; + context.shadowBlur = options.barShadow; + context.shadowColor = options.colorBarShadow; + context.shadowOffsetX = 0; + context.shadowOffsetY = 0; + context.arc(0, 0, rMax, + drawings.radians(options.startAngle), + drawings.radians(options.startAngle + options.ticksAngle), + false); + context.stroke(); + context.closePath(); + + context.restore(); + context.rotate(HPI); + } + + // draw bar progress + if (options.barProgress) { + context.beginPath(); + context.arc(0, 0, r, + drawings.radians(sa), + drawings.radians(sa + + (drawings.normalizedValue(options).normal - + options.minValue) / (options.maxValue - options.minValue) * + options.ticksAngle), + false); + context.strokeStyle = options.colorBarProgress; + context.lineWidth = w; + context.stroke(); + context.closePath(); + } + } + + context.restore(); +} + +/** + * Find and return gauge value to display + * + * @param {RadialGauge} gauge + */ +function displayValue(gauge) { + if (gauge.options.animatedValue) { + return gauge.options.value; + } + + return gauge.value; +} + /** * Minimalistic HTML5 Canvas Gauge * @example @@ -586,12 +697,84 @@ function drawRadialValueBox(context, options, value) { */ export default class RadialGauge extends BaseGauge { + /** + * Fired each time before gauge plate is drawn + * + * @event RadialGauge#beforePlate + */ + + /** + * Fired each time before gauge highlight areas are drawn + * + * @event RadialGauge#beforeHighlights + */ + + /** + * Fired each time before gauge minor ticks are drawn + * + * @event RadialGauge#beforeMinorTicks + */ + + /** + * Fired each time before gauge major ticks are drawn + * + * @event RadialGauge#beforeMajorTicks + */ + + /** + * Fired each time before gauge tick numbers are drawn + * + * @event RadialGauge#beforeNumbers + */ + + /** + * Fired each time before gauge title is drawn + * + * @event RadialGauge#beforeTitle + */ + + /** + * Fired each time before gauge units text is drawn + * + * @event RadialGauge#beforeUnits + */ + + /** + * Fired each time before gauge progress bar is drawn + * + * @event RadialGauge#beforeProgressBar + */ + + /** + * Fired each time before gauge value box is drawn + * + * @event RadialGauge#beforeValueBox + */ + + /** + * Fired each time before gauge needle is drawn + * + * @event RadialGauge#beforeNeedle + */ + /** * @constructor * @param {RadialGaugeOptions} options */ constructor(options) { options = Object.assign({}, defaultRadialGaugeOptions, options || {}); + super(RadialGauge.configure(options)); + } + + /** + * Checks and updates gauge options properly + * + * @param {*} options + * @return {*} + * @access protected + */ + static configure(options) { + if (options.barWidth > 50) options.barWidth = 50; /* istanbul ignore if */ if (isNaN(options.startAngle)) options.startAngle = 45; @@ -608,10 +791,38 @@ export default class RadialGauge extends BaseGauge { /* istanbul ignore if */ if (options.startAngle > 360) options.startAngle = 360; - super(options); + return options; + } + + /** + * Sets the value for radial gauge + * + * @param {number} value + */ + set value(value) { + value = BaseGauge.ensureValue(value, this.options.minValue); + + if (this.options.animation && + this.options.ticksAngle === 360 && + this.options.useMinPath + ) { + this._value = value; + value = this.options.value + + ((((value - this.options.value) % 360) + 540) % 360) - 180; + } + + super.value = value; + } + + /** + * Returns current gauge value + * + * @return {number} + */ + get value() { + return super.value; } - /* */ /** * Triggering gauge render on a canvas. * @@ -636,12 +847,19 @@ export default class RadialGauge extends BaseGauge { context.clearRect(x, y, w, h); context.save(); + this.emit('beforePlate'); drawRadialPlate(context, options); + this.emit('beforeHighlights'); drawRadialHighlights(context, options); + this.emit('beforeMinorTicks'); drawRadialMinorTicks(context, options); + this.emit('beforeMajorTicks'); drawRadialMajorTicks(context, options); + this.emit('beforeNumbers'); drawRadialNumbers(context, options); + this.emit('beforeTitle'); drawRadialTitle(context, options); + this.emit('beforeUnits'); drawRadialUnits(context, options); canvas.elementClone.initialized = true; @@ -656,29 +874,40 @@ export default class RadialGauge extends BaseGauge { canvas.context.drawImage(canvas.elementClone, x, y, w, h); canvas.context.save(); - drawRadialValueBox(canvas.context, options, - options.animatedValue ? this.options.value : this.value); + this.emit('beforeProgressBar'); + drawRadialProgressBar(canvas.context, options); + this.emit('beforeValueBox'); + drawRadialValueBox(canvas.context, options, displayValue(this)); + this.emit('beforeNeedle'); drawRadialNeedle(canvas.context, options); } else { - let plateValueAngle = -drawings.radians(( - (options.value - options.minValue) / - (options.maxValue - options.minValue) * options.ticksAngle)); + let plateValueAngle = -drawings.radians( + (options.value - options.minValue) / + (options.maxValue - options.minValue) * + options.ticksAngle); // clear the canvas canvas.context.clearRect(x, y, w, h); canvas.context.save(); + this.emit('beforePlate'); drawRadialPlate(canvas.context, options); canvas.context.rotate(plateValueAngle); // animated + this.emit('beforeHighlights'); drawRadialHighlights(canvas.context, options); + this.emit('beforeMinorTicks'); drawRadialMinorTicks(canvas.context, options); + this.emit('beforeMajorTicks'); drawRadialMajorTicks(canvas.context, options); + this.emit('beforeNumbers'); drawRadialNumbers(canvas.context, options); + this.emit('beforeProgressBar'); + drawRadialProgressBar(canvas.context, options); // non-animated canvas.context.rotate(-plateValueAngle); @@ -691,8 +920,11 @@ export default class RadialGauge extends BaseGauge { context.clearRect(x, y, w, h); context.save(); + this.emit('beforeTitle'); drawRadialTitle(context, options); + this.emit('beforeUnits'); drawRadialUnits(context, options); + this.emit('beforeNeedle'); drawRadialNeedle(context, options); canvas.elementClone.initialized = true; @@ -702,8 +934,8 @@ export default class RadialGauge extends BaseGauge { } // value box animations - drawRadialValueBox(canvas.context, options, options.animatedValue ? - this.options.value : this.value); + this.emit('beforeValueBox'); + drawRadialValueBox(canvas.context, options, displayValue(this)); super.draw(); } diff --git a/lib/SmartCanvas.js b/lib/SmartCanvas.js index 46773e90..e9bb569c 100644 --- a/lib/SmartCanvas.js +++ b/lib/SmartCanvas.js @@ -224,7 +224,7 @@ export default class SmartCanvas { static get pixelRatio() { /* istanbul ignore next */ //noinspection JSUnresolvedVariable - return ns.devicePixelRatio || 1; + return window.devicePixelRatio || 1; } /** @@ -244,9 +244,9 @@ SmartCanvas.collection = []; /* istanbul ignore next: very browser-specific testing required to cover */ //noinspection JSUnresolvedVariable -if (ns.matchMedia) { +if (window.matchMedia) { //noinspection JSUnresolvedFunction - ns.matchMedia('screen and (min-resolution: 2dppx)') + window.matchMedia('screen and (min-resolution: 2dppx)') .addListener(SmartCanvas.redraw); } diff --git a/lib/drawings.js b/lib/drawings.js index e47dd059..5ddba11c 100644 --- a/lib/drawings.js +++ b/lib/drawings.js @@ -297,6 +297,40 @@ export function font(options, target, baseSize) { options['font' + target]; } +/* istanbul ignore next: private, not testable */ +/** + * Resets some context settings + * + * @param {Canvas2DContext} context + */ +function reset(context) { + context.shadowOffsetX = null; + context.shadowOffsetY = null; + context.shadowBlur = null; + context.shadowColor = ''; + context.strokeStyle = null; + context.lineWidth = 0; + context.save(); +} + +/* istanbul ignore next: private, not testable */ +/** + * Declares to drow value text shadow if configured + * + * @param context + * @param options + * @param offset + * @param blur + */ +function drawValueTextShadow(context, options, offset, blur) { + if (options.valueTextShadow) { + context.shadowOffsetX = offset; + context.shadowOffsetY = offset; + context.shadowBlur = blur; + context.shadowColor = options.colorValueTextShadow; + } +} + /* istanbul ignore next: private, not testable */ /** * Draws value box at given position @@ -311,54 +345,57 @@ export function font(options, target, baseSize) { export function drawValueBox(context, options, value, x, y, max) { if (!options.valueBox) return; - let text = options.valueText || padValue(value, options); + reset(context); - context.shadowOffsetX = null; - context.shadowOffsetY = null; - context.shadowBlur = null; - context.shadowColor = ''; - context.strokeStyle = null; - context.lineWidth = 0; - context.save(); + let text = options.valueText || padValue(value, options); + let tunit = max / 200; + let runit = max / 100; + let offset = 0.4 * runit; + let blur = 1.2 * runit; - context.font = font(options, 'Value', max / 200); - context.save(); - context.beginPath(); + context.font = font(options, 'Value', tunit); + drawValueTextShadow(context, options, offset, blur); - let th = 0.12 * max; - let bs = parseFloat(options.valueBoxStroke) || 0; - let bmax = max * 2 - bs * 2; let tw = context.measureText(options.valueText ? text : ('-' + padValue(0, options))).width; - let bw = tw + 0.05 * max; - let bh = th + 0.07 * max; - let br = max * options.valueBoxBorderRadius / 100; + + reset(context); + + let th = parseFloat(options.fontValueSize) * tunit + offset + blur; + let sw = runit * parseFloat(options.valueBoxStroke); + let bmax = max * 2 - sw * 2; + + let bw = tw + 10 * runit; + let bh = 1.1 * th + offset + blur; + let br = runit * options.valueBoxBorderRadius; let obw = (parseFloat(options.valueBoxWidth) || 0) / 100 * bmax; (obw > bw) && (bw = obw); (bw > bmax) && (bw = bmax); let bx = x - bw / 2; - let by = y - th - 0.04 * max; + let by = y - bh / 2; + let gy = y - 5.75 * runit; + + context.beginPath(); if (br) roundRect(context, bx, by, bw, bh, br); else context.rect(bx, by, bw, bh); - let gy = y - 0.12 * max - 0.025 * max + (0.12 * max + 0.045 * max) / 2; - - if (options.valueBoxStroke) { - let grd = context.createRadialGradient(x, gy, max / 10, x, gy, max / 5); + if (sw) { + let grd = context.createRadialGradient( + x, gy, runit * 10, x, gy, runit * 20); grd.addColorStop(0, options.colorValueBoxRect); grd.addColorStop(1, options.colorValueBoxRectEnd); context.strokeStyle = grd; - context.lineWidth = max * options.valueBoxStroke / 100; + context.lineWidth = sw; context.stroke(); } if (options.colorValueBoxShadow) { - context.shadowBlur = 0.012 * max; + context.shadowBlur = 1.2 * runit; context.shadowColor = options.colorValueBoxShadow; } @@ -370,19 +407,34 @@ export function drawValueBox(context, options, value, x, y, max) { context.closePath(); context.restore(); - if (options.valueTextShadow) { - context.shadowOffsetX = 0.004 * max; - context.shadowOffsetY = 0.004 * max; - context.shadowBlur = 0.012 * max; - context.shadowColor = options.colorValueTextShadow; - } + drawValueTextShadow(context, options, offset, blur); context.fillStyle = options.colorValueText; context.textAlign = 'center'; - context.fillText(text, bx + bw / 2, y); + context.textBaseline = 'alphabetic'; + context.fillText(text, bx + bw / 2, y + bh / 2 - th / 3); context.restore(); } +/* istanbul ignore next: private, not testable */ +/** + * Returns normalized value + * + * @param {GenericOptions} options + * @return {{normal: number, indented: number}} + */ +export function normalizedValue(options) { + let value = options.value; + let min = options.minValue; + let max = options.maxValue; + let dt = (max - min) * 0.01; + + return { + normal: value < min ? min : value > max ? max : value, + indented: value < min ? min - dt : value > max ? max + dt : value + }; +} + const drawings = { roundRect: roundRect, padValue: padValue, @@ -395,7 +447,8 @@ const drawings = { verifyError: verifyError, prepareTicks: prepareTicks, drawShadow: drawShadow, - font: font + font: font, + normalizedValue: normalizedValue }; export default drawings; diff --git a/lib/polyfill.js b/lib/polyfill.js index 71bcb50d..8c18aa0d 100644 --- a/lib/polyfill.js +++ b/lib/polyfill.js @@ -117,3 +117,10 @@ if (!Array.prototype.fill) { return O; }; } + +/** + * mocking window + */ +if (typeof window === 'undefined') { + window = typeof global === 'undefined' ? {} : global; +} diff --git a/package.json b/package.json index 9f75a266..d7af5981 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "canvas-gauges", - "version": "2.0.9", - "description": "Minimalistic HTML5 Canvas Gauges", + "version": "2.1.0", + "description": "Minimalist HTML5 Canvas Gauges", "main": "gauge.min.js", "directories": { "example": "examples" @@ -117,11 +117,13 @@ "selenium-standalone": "^5.5.0", "semver": "^5.3.0", "sinon": "^1.17.5", + "uglify-js-harmony": "^2.6.2", "utils-merge": "^1.0.0", "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^1.1.0", "watchify": "^3.7.0", "webdriverio": "^4.2.7", + "webpack": "^1.13.2", "yargs": "^5.0.0" } } diff --git a/test-coverage.svg b/test-coverage.svg index 451c8111..92a2f066 100644 --- a/test-coverage.svg +++ b/test-coverage.svg @@ -1 +1 @@ -coveragecoverage89.34%89.34% \ No newline at end of file +coveragecoverage84.89%84.89% \ No newline at end of file diff --git a/test/cjs/index.html b/test/cjs/index.html new file mode 100644 index 00000000..07c1fab8 --- /dev/null +++ b/test/cjs/index.html @@ -0,0 +1,51 @@ + + + + + + Gauge Test + + + + + + + + + + + + + + diff --git a/test/cjs/index.js b/test/cjs/index.js new file mode 100644 index 00000000..62fcde20 --- /dev/null +++ b/test/cjs/index.js @@ -0,0 +1,2 @@ +var gauges = require('../../gauge.min'); +console.log(gauges); diff --git a/test/cjs/webpack.config.js b/test/cjs/webpack.config.js new file mode 100644 index 00000000..6fc9127b --- /dev/null +++ b/test/cjs/webpack.config.js @@ -0,0 +1,7 @@ +module.exports = { + entry: './test/cjs/index.js', + output: { + path: './test/cjs', + filename: 'bundle.js' + } +}; diff --git a/test/spec/BaseGauge.js b/test/spec/BaseGauge.spec.js similarity index 100% rename from test/spec/BaseGauge.js rename to test/spec/BaseGauge.spec.js diff --git a/test/spec/DomObserver.spec.js b/test/spec/DomObserver.spec.js index c3b8a13a..7818321b 100644 --- a/test/spec/DomObserver.spec.js +++ b/test/spec/DomObserver.spec.js @@ -79,6 +79,15 @@ describe('DomObserver', () => { }); }); + describe('toCamelCase()', () => { + it('should transform dashed string to CamelCase representation', () => { + let dashed = 'on-two-three'; + + expect(DomObserver.toCamelCase('one-two-three')) + .to.equal('OneTwoThree'); + }); + }); + describe('process()', () => { it('should properly process given node and create associated type ' + 'instance', () => diff --git a/test/spec/EventEmitter.spec.js b/test/spec/EventEmitter.spec.js new file mode 100644 index 00000000..9253b3e3 --- /dev/null +++ b/test/spec/EventEmitter.spec.js @@ -0,0 +1,120 @@ +const sinon = require('sinon'); +const expect = require('chai').expect; +const EventEmitter = require('../../lib/EventEmitter'); + +describe('EventEmitter', () => { + it('should be a class', () => { + expect(EventEmitter).is.a('function'); + expect(() => new EventEmitter()).to.not.throw(Error); + }); + + describe('constructor()', () => { + it('should define required class properties', () => { + let emitter = new EventEmitter(); + + expect(emitter._events).to.be.defined; + expect(emitter.addListener).to.be.defined; + expect(emitter.removeListener).to.be.defined; + }); + }); + + describe('emit()', () => { + let emitter; + + before(() => { + emitter = new EventEmitter(); + }); + + it('should not throw', () => { + expect(() => emitter.emit()).to.not.throw(Error); + }); + + it('should emit properly', () => { + let one = sinon.spy(); + let two = sinon.spy(); + + emitter._events.test = [one, two]; + + emitter.emit('test', 1, 2, 3); + expect(one.calledWith(1, 2, 3)).to.be.true; + expect(two.calledWith(1, 2, 3)).to.be.true; + }); + }); + + describe('on()', () => { + let emitter; + + before(() => { + emitter = new EventEmitter(); + }); + + it('should register event handlers properly', () => { + let one = sinon.spy(); + let two = sinon.spy(); + + emitter.on('test', one, two); + + emitter.emit('test', 1, 2, 3); + expect(one.calledWith(1, 2, 3)).to.be.true; + expect(two.calledWith(1, 2, 3)).to.be.true; + }); + }); + + describe('off()', () => { + let emitter; + + before(() => { + emitter = new EventEmitter(); + }); + + it('should un-register event handlers properly', () => { + let one = sinon.spy(); + let two = sinon.spy(); + + emitter.on('test', one, two); + emitter.off('test', one, two); + + emitter.emit('test'); + expect(one.called).to.be.false; + expect(two.called).to.be.false; + }); + }); + + describe('once()', () => { + let emitter; + + before(() => { + emitter = new EventEmitter(); + }); + + it('should register event handlers properly', () => { + let one = sinon.spy(); + let two = sinon.spy(); + + emitter.once('test', one, two); + + emitter.emit('test'); + emitter.emit('test'); + expect(one.calledOnce).to.be.true; + expect(two.calledOnce).to.be.true; + }); + }); + + describe('removeAllListeners()', () => { + let emitter; + + before(() => { + emitter = new EventEmitter(); + }); + + it('should register event handlers properly', () => { + let one = sinon.spy(); + let two = sinon.spy(); + + emitter.on('test', one, two); + + emitter.removeAllListeners('test'); + expect(emitter.listeners.test).to.be.undefined; + }); + }); +});