UNPKG

nonlinear-canvas-gauges

Version:

Modification of canvas-gauges. Rendering nonlinear scale.

1,075 lines (940 loc) 31.1 kB
/*! * The MIT License (MIT) * * Copyright (c) 2016 Mykhailo Stadnyk <mikhus@gmail.com> * * 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. */ require("./polyfill"); const GenericOptions = require("./GenericOptions"); const BaseGauge = require("./BaseGauge"); const SmartCanvas = require("./SmartCanvas"); const drawings = require("./drawings"); const PI = Math.PI; const HPI = PI / 2; /** * Gauge configuration options * * @typedef {GenericOptions|{exactTicks: boolean, ticksAngle: number, startAngle: number, colorNeedleCircleOuter: string, colorNeedleCircleOuterEnd: string, colorNeedleCircleInner: string, colorNeedleCircleInnerEnd: string, needleCircleSize: number, needleCircleInner: boolean, needleCircleOuter: boolean, animationTarget: string, useMinPath: boolean}} RadialGaugeOptions */ /** * Default gauge configuration options * * @access private * @type {RadialGaugeOptions} */ const defaultRadialGaugeOptions = Object.assign({}, GenericOptions, { // basic options ticksAngle: 270, startAngle: 100, // colors colorNeedleCircleOuter: "#f0f0f0", colorNeedleCircleOuterEnd: "#ccc", colorNeedleCircleInner: "#e8e8e8", colorNeedleCircleInnerEnd: "#f5f5f5", // needle needleCircleSize: 10, needleCircleInner: true, needleCircleOuter: true, needleStart: 20, // custom animations animationTarget: "needle", // 'needle' or 'plate' useMinPath: false, barWidth: 0 }); /* istanbul ignore next: private, not testable */ /** * Draws gradient-filled circle on a canvas * * @access private * @param {number} radius * @param {number} width * @param {Canvas2DContext} context * @param {string} start gradient start color * @param {string} end gradient end color */ function drawRadialBorder(radius, width, context, start, end) { context.beginPath(); //noinspection JSUnresolvedFunction context.arc(0, 0, abs(radius), 0, PI * 2, true); context.lineWidth = width; context.strokeStyle = end ? drawings.linearGradient(context, start, end, radius) : start; context.stroke(); context.closePath(); } /* istanbul ignore next: private, not testable */ /** * Returns max radius without borders for the gauge * * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options * @return {number} */ function maxRadialRadius(context, options) { let pxRatio = SmartCanvas.pixelRatio; if (!context.maxRadius) { context.maxRadius = context.max - options.borderShadowWidth - options.borderOuterWidth * pxRatio - options.borderMiddleWidth * pxRatio - options.borderInnerWidth * pxRatio + (options.borderOuterWidth ? 0.5 : 0) + (options.borderMiddleWidth ? 0.5 : 0) + (options.borderInnerWidth ? 0.5 : 0); } return context.maxRadius; } /* istanbul ignore next: private, not testable */ /** * Draws gauge plate on the canvas * * @access private * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialPlate(context, options) { let pxRatio = SmartCanvas.pixelRatio; let d0 = options.borderShadowWidth * pxRatio; let r0 = context.max - d0 - (options.borderOuterWidth * pxRatio) / 2; let r1 = r0 - (options.borderOuterWidth * pxRatio) / 2 - (options.borderMiddleWidth * pxRatio) / 2 + 0.5; let r2 = r1 - (options.borderMiddleWidth * pxRatio) / 2 - (options.borderInnerWidth * pxRatio) / 2 + 0.5; let r3 = maxRadialRadius(context, options); let grad; let shadowDrawn = false; context.save(); if (options.borderOuterWidth) { shadowDrawn = drawings.drawShadow(context, options, shadowDrawn); drawRadialBorder( r0, options.borderOuterWidth * pxRatio, context, options.colorBorderOuter, options.colorBorderOuterEnd ); } if (options.borderMiddleWidth) { shadowDrawn = drawings.drawShadow(context, options, shadowDrawn); drawRadialBorder( r1, options.borderMiddleWidth * pxRatio, context, options.colorBorderMiddle, options.colorBorderMiddleEnd ); } if (options.borderInnerWidth) { shadowDrawn = drawings.drawShadow(context, options, shadowDrawn); drawRadialBorder( r2, options.borderInnerWidth * pxRatio, context, options.colorBorderInner, options.colorBorderInnerEnd ); } drawings.drawShadow(context, options, shadowDrawn); context.beginPath(); //noinspection JSUnresolvedFunction context.arc(0, 0, abs(r3), 0, PI * 2, true); if (options.colorPlateEnd) { grad = context.createRadialGradient(0, 0, r3 / 2, 0, 0, r3); grad.addColorStop(0, options.colorPlate); grad.addColorStop(1, options.colorPlateEnd); } else { grad = options.colorPlate; } context.fillStyle = grad; context.fill(); context.closePath(); context.restore(); } /* istanbul ignore next: private, not testable */ /** * Draws gauge highlight areas on a canvas * * @access private * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialHighlights(context, options) { let hlWidth = (context.max * (parseFloat(options.highlightsWidth) || 0)) / 100; if (!hlWidth) return; //noinspection JSUnresolvedFunction let r = abs(radialTicksRadius(context, options) - hlWidth / 2); let i = 0, s = options.highlights.length; let vd = (options.maxValue - options.minValue) / options.ticksAngle; context.save(); for (; i < s; i++) { let hlt = options.highlights[i]; context.beginPath(); context.rotate(HPI); context.arc( 0, 0, r, drawings.radians( options.startAngle + (hlt.from - options.minValue) / vd ), drawings.radians( options.startAngle + (hlt.to - options.minValue) / vd ), false ); context.strokeStyle = hlt.color; context.lineWidth = hlWidth; context.stroke(); context.closePath(); context.restore(); context.save(); } } /* istanbul ignore next: private, not testable */ /** * Draws minor ticks bar on a canvas * * @access private * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialMinorTicks(context, options) { let radius = radialTicksRadius(context, options); let s, range, angle; let i = 0; let delta = 0; let minTicks = Math.abs(options.minorTicks) || 0; let ratio = options.ticksAngle / (options.maxValue - options.minValue); context.lineWidth = SmartCanvas.pixelRatio; context.strokeStyle = options.colorMinorTicks || options.colorStrokeTicks; context.save(); if (options.exactTicks) { range = options.maxValue - options.minValue; s = minTicks ? range / minTicks : 0; delta = (BaseGauge.mod(options.majorTicks[0], minTicks) || 0) * ratio; } else { s = minTicks * (options.majorTicks.length - 1); } for (; i < s; ++i) { angle = options.startAngle + delta + i * (options.ticksAngle / s); if (angle <= options.ticksAngle + options.startAngle) { context.rotate(drawings.radians(angle)); context.beginPath(); context.moveTo(0, radius); context.lineTo(0, radius - context.max * 0.075); closeStrokedPath(context); } } } /* istanbul ignore next: private, not testable */ /** * Returns ticks radius * * @access private * @param context * @param options * @return {number} */ function radialTicksRadius(context, options) { 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 */ /** * Draws gauge major ticks bar on a canvas * * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialMajorTicks(context, options) { drawings.prepareTicks(options); //noinspection JSUnresolvedFunction let r = abs(radialTicksRadius(context, options)); let i, colors; let s = options.majorTicks.length; let pixelRatio = SmartCanvas.pixelRatio; context.lineWidth = 2 * pixelRatio; context.save(); colors = options.colorMajorTicks instanceof Array ? options.colorMajorTicks : new Array(s).fill( options.colorStrokeTicks || options.colorMajorTicks ); i = 0; for (; i < s; ++i) { context.strokeStyle = colors[i]; context.rotate( drawings.radians( radialNextAngle( options, options.exactTicks ? options.majorTicks[i] : i, s ) ) ); context.beginPath(); context.moveTo(0, r); context.lineTo(0, r - context.max * 0.15); closeStrokedPath(context); } if (options.strokeTicks) { context.strokeStyle = options.colorStrokeTicks || colors[0]; context.rotate(HPI); context.beginPath(); context.arc( 0, 0, r, drawings.radians(options.startAngle), drawings.radians(options.startAngle + options.ticksAngle), false ); closeStrokedPath(context); } } /* istanbul ignore next: private, not testable */ function radialNextAngle(options, i, s) { if (options.exactTicks) { let ratio = options.ticksAngle / (options.maxValue - options.minValue); return options.startAngle + ratio * (i - options.minValue); } return options.startAngle + i * (options.ticksAngle / (s - 1)); } /* istanbul ignore next: private, not testable */ /** * Strokes, closes path and restores previous context state * * @param {Canvas2DContext} context */ function closeStrokedPath(context) { context.stroke(); context.restore(); context.closePath(); context.save(); } /* istanbul ignore next: private, not testable */ /** * Draws gauge bar numbers * * @access private * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialNumbers(context, options) { let radius = radialTicksRadius(context, options) - context.max * 0.15; let points = {}; let i = 0; let s = options.majorTicks.length; let isAnimated = options.animationTarget !== "needle"; let colors = options.colorNumbers instanceof Array ? options.colorNumbers : new Array(s).fill(options.colorNumbers); let plateValueAngle = isAnimated ? (-(options.value - options.minValue) / (options.maxValue - options.minValue)) * options.ticksAngle : 0; if (isAnimated) { context.save(); context.rotate(-drawings.radians(plateValueAngle)); } context.font = drawings.font(options, "Numbers", context.max / 200); context.lineWidth = 0; context.textAlign = "center"; context.textBaseline = "middle"; for (; i < s; ++i) { let angle = plateValueAngle + radialNextAngle( options, options.exactTicks ? options.majorTicks[i] : i, s ); let textWidth = context.measureText(options.majorTicks[i]).width; let textHeight = options.fontNumbersSize; let textRadius = Math.sqrt(textWidth * textWidth + textHeight * textHeight) / 2; let point = drawings.radialPoint( radius - textRadius - (options.numbersMargin / 100) * context.max, drawings.radians(angle) ); if (angle === 360) angle = 0; if (points[angle]) { continue; //already drawn at this place, skipping } points[angle] = true; context.fillStyle = colors[i]; context.fillText(options.majorTicks[i], point.x, point.y); } isAnimated && context.restore(); } /* istanbul ignore next: private, not testable */ /** * Draws gauge title * * @access private * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialTitle(context, options) { if (!options.title) return; context.save(); context.font = drawings.font(options, "Title", context.max / 200); context.fillStyle = options.colorTitle; context.textAlign = "center"; context.fillText(options.title, 0, -context.max / 4.25, context.max * 0.8); context.restore(); } /* istanbul ignore next: private, not testable */ /** * Draws units name on the gauge * * @access private * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialUnits(context, options) { if (!options.units) return; context.save(); context.font = drawings.font(options, "Units", context.max / 200); context.fillStyle = options.colorUnits; context.textAlign = "center"; context.fillText(options.units, 0, context.max / 3.25, context.max * 0.8); context.restore(); } /* istanbul ignore next: private, not testable */ /** * Draws gauge needle * * @access private * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options */ function drawRadialNeedle(context, options) { if (!options.needle) return; 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); //noinspection JSUnresolvedFunction let r2 = abs((max / 100) * options.needleCircleSize * 0.75); //noinspection JSUnresolvedFunction let rIn = abs((max / 100) * options.needleEnd); //noinspection JSUnresolvedFunction let rStart = abs( options.needleStart ? (max / 100) * options.needleStart : 0 ); //noinspection JSUnresolvedFunction let pad1 = (max / 100) * options.needleWidth; let pad2 = ((max / 100) * options.needleWidth) / 2; let pixelRatio = SmartCanvas.pixelRatio; let isFixed = options.animationTarget !== "needle"; context.save(); drawings.drawNeedleShadow(context, options); context.rotate( drawings.radians( isFixed ? options.startAngle : options.startAngle + ((value - options.minValue) / (options.maxValue - options.minValue)) * options.ticksAngle ) ); context.fillStyle = drawings.linearGradient( context, options.colorNeedle, options.colorNeedleEnd, rIn - rStart ); if (options.needleType === "arrow") { context.beginPath(); context.moveTo(-pad2, -rStart); context.lineTo(-pad1, 0); context.lineTo(-1 * pixelRatio, rIn); context.lineTo(pixelRatio, rIn); context.lineTo(pad1, 0); context.lineTo(pad2, -rStart); context.closePath(); context.fill(); context.beginPath(); context.lineTo(-0.5 * pixelRatio, rIn); context.lineTo(-1 * pixelRatio, rIn); context.lineTo(-pad1, 0); context.lineTo(-pad2, -rStart); context.lineTo((pad2 / 2) * pixelRatio - 2 * pixelRatio, -rStart); context.closePath(); context.fillStyle = options.colorNeedleShadowUp; context.fill(); } else { // simple line needle context.beginPath(); context.moveTo(-pad2, rIn); context.lineTo(-pad2, rStart); context.lineTo(pad2, rStart); context.lineTo(pad2, rIn); context.closePath(); context.fill(); } if (options.needleCircleSize) { context.restore(); drawings.drawNeedleShadow(context, options); if (options.needleCircleOuter) { context.beginPath(); context.arc(0, 0, r1, 0, PI * 2, true); context.fillStyle = drawings.linearGradient( context, options.colorNeedleCircleOuter, options.colorNeedleCircleOuterEnd, r1 ); context.fill(); context.closePath(); } if (options.needleCircleInner) { context.beginPath(); context.arc(0, 0, r2, 0, PI * 2, true); context.fillStyle = drawings.linearGradient( context, options.colorNeedleCircleInner, options.colorNeedleCircleInnerEnd, r2 ); context.fill(); context.closePath(); } context.restore(); } } /* istanbul ignore next: private, not testable */ /** * Draws gauge value box * * @param {Canvas2DContext} context * @param {RadialGaugeOptions} options * @param {number} value */ function drawRadialValueBox(context, options, value) { drawings.drawValueBox( context, options, value, 0, 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 * var gauge = new RadialGauge({ * renderTo: 'gauge-id', // identifier of HTML canvas element or element itself * width: 400, * height: 400, * units: 'Km/h', * title: false, * value: 0, * minValue: 0, * maxValue: 220, * majorTicks: [ * '0','20','40','60','80','100','120','140','160','180','200','220' * ], * minorTicks: 2, * strokeTicks: false, * highlights: [ * { from: 0, to: 50, color: 'rgba(0,255,0,.15)' }, * { from: 50, to: 100, color: 'rgba(255,255,0,.15)' }, * { from: 100, to: 150, color: 'rgba(255,30,0,.25)' }, * { from: 150, to: 200, color: 'rgba(255,0,225,.25)' }, * { from: 200, to: 220, color: 'rgba(0,0,255,.25)' } * ], * colorPlate: '#222', * colorMajorTicks: '#f5f5f5', * colorMinorTicks: '#ddd', * colorTitle: '#fff', * colorUnits: '#ccc', * colorNumbers: '#eee', * colorNeedleStart: 'rgba(240, 128, 128, 1)', * colorNeedleEnd: 'rgba(255, 160, 122, .9)', * valueBox: true, * animationRule: 'bounce' * }); * // draw initially * gauge.draw(); * // animate * setInterval(() => { * gauge.value = Math.random() * -220 + 220; * }, 1000); */ 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 = 100; /* istanbul ignore if */ if (isNaN(options.ticksAngle)) options.ticksAngle = 270; /* istanbul ignore if */ if (options.ticksAngle > 360) options.ticksAngle = 360; /* istanbul ignore if */ if (options.ticksAngle < 0) options.ticksAngle = 0; /* istanbul ignore if */ if (options.startAngle < 0) options.startAngle = 0; /* istanbul ignore if */ if (options.startAngle > 360) options.startAngle = 360; 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. * * @returns {RadialGauge} */ draw() { console.log("RadialGauge.draw"); try { let canvas = this.canvas; let [x, y, w, h] = [ -canvas.drawX, -canvas.drawY, canvas.drawWidth, canvas.drawHeight ]; let options = this.options; if (options.animationTarget === "needle") { if (!canvas.elementClone.initialized) { let context = canvas.contextClone; // clear the cache 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; } this.canvas.commit(); // clear the canvas canvas.context.clearRect(x, y, w, h); canvas.context.save(); canvas.context.drawImage(canvas.elementClone, x, y, w, h); canvas.context.save(); 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 ); // 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); canvas.context.save(); if (!canvas.elementClone.initialized) { let context = canvas.contextClone; // clear the cache 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; } canvas.context.drawImage(canvas.elementClone, x, y, w, h); } // value box animations this.emit("beforeValueBox"); drawRadialValueBox(canvas.context, options, displayValue(this)); super.draw(); } catch (err) { drawings.verifyError(err); } return this; } } /** * @ignore * @typedef {object} ns */ /* istanbul ignore if */ if (typeof ns !== "undefined") { ns["RadialGauge"] = RadialGauge; } BaseGauge.initialize("RadialGauge", defaultRadialGaugeOptions); module.exports = RadialGauge;