framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
315 lines (288 loc) • 9.49 kB
JavaScript
/* 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;