Monitoring system for electric vehicles (log various sensors, such as consumed power, solar production, speed, slope, apparent wind, etc.)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

102 lines
2.5 KiB

import m from 'mithril';
import { NumericValue } from 'components/widgets/numeric-value';
import { Pipe } from 'utilities/pipe';
require('./gauge.css');
export class Gauge extends NumericValue {
protected bars: SVGGeometryElement[] = [];
private displayedValue = 0.0;
private targetValue = 0.0;
private valueChangeRate = 0.0;
private litBars = 0;
private animating = false;
private shuttingDown = false;
private lastGaugeUpdate = 0.0;
private lastAnimationTick = 0.0;
constructor(vnode: any) {
super(vnode);
}
onbeforeremove(vnode: m.Vnode<{}, {}>) {
this.shuttingDown = true;
super.onbeforeremove(vnode);
}
protected graphicalRepresentation(vnode: m.Vnode<{}, {}>): m.Children {
return <svg></svg>;
}
protected onValueChange(value: number) {
let now = Date.now() / 1000.0;
let ratio = value / (this.maxValue || 1.0);
let numBars = this.bars.length;
let threshold = 0.33 / numBars;
if(ratio > this.targetValue + threshold || ratio < this.targetValue - threshold) {
let animationTime = this.lastGaugeUpdate == 0.0 ? 0.0001 : Math.max(0.0001, Math.min(0.75, now - this.lastGaugeUpdate));
this.valueChangeRate = (ratio - this.displayedValue) / animationTime;
this.targetValue = ratio;
this.enableAnimation();
}
this.lastGaugeUpdate = now;
}
private enableAnimation() {
if(this.animating) return;
this.animating = true;
this.lastAnimationTick = Date.now() / 1000.0 - 0.016;
requestAnimationFrame(() => this.animate());
}
private animate() {
if(this.shuttingDown) return;
if(this.valueChangeRate == 0.0) {
this.animating = false;
return;
}
requestAnimationFrame(() => this.animate());
let now = Date.now() / 1000.0;
if(now > this.lastAnimationTick + 0.75) {
this.displayedValue = this.targetValue;
this.valueChangeRate = 0.0;
}
else {
let dt = now - this.lastAnimationTick;
if(dt < 0.04) return; // limit framerate to save battery
this.displayedValue += this.valueChangeRate * dt;
if((this.displayedValue > this.targetValue) == (this.valueChangeRate > 0.0)) {
this.displayedValue = this.targetValue;
this.valueChangeRate = 0.0;
}
}
this.lastAnimationTick = now;
let numBars = this.bars.length;
let litBars = Math.round(this.displayedValue * numBars);
if(litBars == this.litBars)
return;
this.litBars = litBars;
for(let barIdx = 0; barIdx < numBars; ++barIdx) {
let bar = this.bars[barIdx];
let isLit = barIdx < litBars;
if(bar.classList.contains('lit') != isLit)
bar.classList.toggle('lit', isLit);
}
}
}