UNPKG

framework7

Version:

Full featured mobile HTML framework for building iOS & Android apps

315 lines (288 loc) 9.49 kB
/* eslint no-nested-ternary: off */ import $ from 'dom7'; import Utils from '../../utils/utils'; import Framework7Class from '../../utils/class'; class Gauge extends Framework7Class { constructor(app, params = {}) { // Extends with open/close Modal methods; super(params, [app]); const gauge = this; const defaults = Utils.extend({}, app.params.gauge); // Extend defaults with modules params gauge.useModulesParams(defaults); gauge.params = Utils.extend(defaults, params); const { el } = gauge.params; if (!el) return gauge; const $el = $(el); if ($el.length === 0) return gauge; if ($el[0].f7Gauge) return $el[0].f7Gauge; Utils.extend(gauge, { app, $el, el: $el && $el[0], }); $el[0].f7Gauge = gauge; // Install Modules gauge.useModules(); gauge.init(); return gauge; } calcRadius() { const gauge = this; const { size, borderWidth } = gauge.params; return (size / 2) - (borderWidth / 2); } calcBorderLength() { const gauge = this; const radius = gauge.calcRadius(); return 2 * Math.PI * radius; } render() { const gauge = this; if (gauge.params.render) return gauge.params.render.call(gauge, gauge); const { type, value, size, bgColor, borderBgColor, borderColor, borderWidth, valueText, valueTextColor, valueFontSize, valueFontWeight, labelText, labelTextColor, labelFontSize, labelFontWeight, } = gauge.params; const semiCircle = type === 'semicircle'; const radius = gauge.calcRadius(); const length = gauge.calcBorderLength(); const progress = Math.max(Math.min(value, 1), 0); return ` <svg class="gauge-svg" width="${size}px" height="${semiCircle ? size / 2 : size}px" viewBox="0 0 ${size} ${semiCircle ? size / 2 : size}"> ${semiCircle ? ` <path class="gauge-back-semi" d="M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0" stroke="${borderBgColor}" stroke-width="${borderWidth}" fill="${bgColor || 'none'}" /> <path class="gauge-front-semi" d="M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0" stroke="${borderColor}" stroke-width="${borderWidth}" stroke-dasharray="${length / 2}" stroke-dashoffset="${(length / 2) * (1 + progress)}" fill="${borderBgColor ? 'none' : (bgColor || 'none')}" /> ` : ` ${borderBgColor ? ` <circle class="gauge-back-circle" stroke="${borderBgColor}" stroke-width="${borderWidth}" fill="${bgColor || 'none'}" cx="${size / 2}" cy="${size / 2}" r="${radius}" ></circle> ` : ''} <circle class="gauge-front-circle" transform="${`rotate(-90 ${size / 2} ${size / 2})`}" stroke="${borderColor}" stroke-width="${borderWidth}" stroke-dasharray="${length}" stroke-dashoffset="${length * (1 - progress)}" fill="${borderBgColor ? 'none' : bgColor || 'none'}" cx="${size / 2}" cy="${size / 2}" r="${radius}" ></circle> `} ${valueText ? ` <text class="gauge-value-text" x="50%" y="${semiCircle ? '100%' : '50%'}" font-weight="${valueFontWeight}" font-size="${valueFontSize}" fill="${valueTextColor}" dy="${semiCircle ? (labelText ? -labelFontSize - 15 : -5) : 0}" text-anchor="middle" dominant-baseline="${!semiCircle && 'middle'}" >${valueText}</text> ` : ''} ${labelText ? ` <text class="gauge-label-text" x="50%" y="${semiCircle ? '100%' : '50%'}" font-weight="${labelFontWeight}" font-size="${labelFontSize}" fill="${labelTextColor}" dy="${semiCircle ? -5 : (valueText ? ((valueFontSize / 2) + 10) : 0)}" text-anchor="middle" dominant-baseline="${!semiCircle && 'middle'}" >${labelText}</text> ` : ''} </svg> `.trim(); } update(newParams = {}) { const gauge = this; const { params, $gaugeSvgEl } = gauge; Object.keys(newParams).forEach((param) => { if (typeof newParams[param] !== 'undefined') { params[param] = newParams[param]; } }); if ($gaugeSvgEl.length === 0) return gauge; const { value, size, bgColor, borderBgColor, borderColor, borderWidth, valueText, valueTextColor, valueFontSize, valueFontWeight, labelText, labelTextColor, labelFontSize, labelFontWeight, } = params; const length = gauge.calcBorderLength(); const progress = Math.max(Math.min(value, 1), 0); const radius = gauge.calcRadius(); const semiCircle = params.type === 'semicircle'; const svgAttrs = { width: `${size}px`, height: `${semiCircle ? size / 2 : size}px`, viewBox: `0 0 ${size} ${semiCircle ? size / 2 : size}`, }; Object.keys(svgAttrs).forEach((attr) => { $gaugeSvgEl.attr(attr, svgAttrs[attr]); }); if (semiCircle) { const backAttrs = { d: `M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0`, stroke: borderBgColor, 'stroke-width': borderWidth, fill: bgColor || 'none', }; const frontAttrs = { d: `M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0`, stroke: borderColor, 'stroke-width': borderWidth, 'stroke-dasharray': length / 2, 'stroke-dashoffset': (length / 2) * (1 + progress), fill: borderBgColor ? 'none' : (bgColor || 'none'), }; Object.keys(backAttrs).forEach((attr) => { $gaugeSvgEl.find('.gauge-back-semi').attr(attr, backAttrs[attr]); }); Object.keys(frontAttrs).forEach((attr) => { $gaugeSvgEl.find('.gauge-front-semi').attr(attr, frontAttrs[attr]); }); } else { const backAttrs = { stroke: borderBgColor, 'stroke-width': borderWidth, fill: bgColor || 'none', cx: size / 2, cy: size / 2, r: radius, }; const frontAttrs = { transform: `rotate(-90 ${size / 2} ${size / 2})`, stroke: borderColor, 'stroke-width': borderWidth, 'stroke-dasharray': length, 'stroke-dashoffset': length * (1 - progress), fill: borderBgColor ? 'none' : bgColor || 'none', cx: size / 2, cy: size / 2, r: radius, }; Object.keys(backAttrs).forEach((attr) => { $gaugeSvgEl.find('.gauge-back-circle').attr(attr, backAttrs[attr]); }); Object.keys(frontAttrs).forEach((attr) => { $gaugeSvgEl.find('.gauge-front-circle').attr(attr, frontAttrs[attr]); }); } if (valueText) { if (!$gaugeSvgEl.find('.gauge-value-text').length) { $gaugeSvgEl.append('<text class="gauge-value-text"></text>'); } const textAttrs = { x: '50%', y: semiCircle ? '100%' : '50%', 'font-weight': valueFontWeight, 'font-size': valueFontSize, fill: valueTextColor, dy: semiCircle ? (labelText ? -labelFontSize - 15 : -5) : 0, 'text-anchor': 'middle', 'dominant-baseline': !semiCircle && 'middle', }; Object.keys(textAttrs).forEach((attr) => { $gaugeSvgEl.find('.gauge-value-text').attr(attr, textAttrs[attr]); }); $gaugeSvgEl.find('.gauge-value-text').text(valueText); } else { $gaugeSvgEl.find('.gauge-value-text').remove(); } if (labelText) { if (!$gaugeSvgEl.find('.gauge-label-text').length) { $gaugeSvgEl.append('<text class="gauge-label-text"></text>'); } const labelAttrs = { x: '50%', y: semiCircle ? '100%' : '50%', 'font-weight': labelFontWeight, 'font-size': labelFontSize, fill: labelTextColor, dy: semiCircle ? -5 : (valueText ? ((valueFontSize / 2) + 10) : 0), 'text-anchor': 'middle', 'dominant-baseline': !semiCircle && 'middle', }; Object.keys(labelAttrs).forEach((attr) => { $gaugeSvgEl.find('.gauge-label-text').attr(attr, labelAttrs[attr]); }); $gaugeSvgEl.find('.gauge-label-text').text(labelText); } else { $gaugeSvgEl.find('.gauge-label-text').remove(); } return gauge; } init() { const gauge = this; const $gaugeSvgEl = $(gauge.render()).eq(0); $gaugeSvgEl.f7Gauge = gauge; Utils.extend(gauge, { $gaugeSvgEl, gaugeSvgEl: $gaugeSvgEl && $gaugeSvgEl[0], }); gauge.$el.append($gaugeSvgEl); return gauge; } destroy() { const gauge = this; if (!gauge.$el || gauge.destroyed) return; gauge.$el.trigger('gauge:beforedestroy'); gauge.emit('local::beforeDestroy gaugeBeforeDestroy', gauge); gauge.$gaugeSvgEl.remove(); delete gauge.$el[0].f7Gauge; Utils.deleteProps(gauge); gauge.destroyed = true; } } export default Gauge;