Browse Source

added smooth animation when a gauge value changes

master
Youen Toupin 2 years ago
parent
commit
bd851a06f7
  1. 2
      WebApp/src/components/widgets/gauge-circular.tsx
  2. 2
      WebApp/src/components/widgets/gauge-linear.tsx
  3. 78
      WebApp/src/components/widgets/gauge.tsx
  4. 10
      WebApp/src/monitor-api.ts

2
WebApp/src/components/widgets/gauge-circular.tsx

@ -51,7 +51,7 @@ export class GaugeCircular extends Gauge {
bg.classList.add('gauge-bg');
svgElement.append(bg);
let barHeight = 12;
let barHeight = 10;
const barGap = barHeight * 0.2;
let numBars = Math.round(arcLength / (barHeight + barGap));

2
WebApp/src/components/widgets/gauge-linear.tsx

@ -33,7 +33,7 @@ export class GaugeLinear extends Gauge {
bg.classList.add('gauge-bg');
svgElement.append(bg);
let barHeight = 15;
let barHeight = 10;
const barGap = barHeight * 0.2;
let numBars = Math.round((h - paddingTop) / (barHeight + barGap));

78
WebApp/src/components/widgets/gauge.tsx

@ -14,6 +14,17 @@ export class Gauge extends Widget {
private integralValueElement: HTMLElement;
private decimalValueElement: HTMLElement;
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);
@ -25,6 +36,11 @@ export class Gauge extends Widget {
this.gaugeValue.onChange(() => this.updateGauge());
}
onbeforeremove(vnode: m.Vnode<{}, {}>) {
this.shuttingDown = true;
super.onbeforeremove(vnode);
}
view(vnode: m.Vnode<{}, {}>): m.Children {
return <div class="widget gauge" style={'flex: ' + this.widgetWidth}>
<p><span class="integral-value"></span><span class="decimal-value"></span><span class="unit">{this.unit}</span></p>
@ -34,6 +50,8 @@ export class Gauge extends Widget {
}
updateGauge() {
let now = Date.now() / 1000.0;
let value = Math.max(0.0, Math.min(this.gaugeMaxValue, this.gaugeValue.get()));
let integralValue = Math.floor(value);
@ -44,10 +62,66 @@ export class Gauge extends Widget {
let ratio = value / this.gaugeMaxValue;
let numBars = this.bars.length;
let litBars = Math.round(ratio * numBars);
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];
bar.classList.toggle('lit', barIdx < litBars);
let isLit = barIdx < litBars;
if(bar.classList.contains('lit') != isLit)
bar.classList.toggle('lit', isLit);
}
}

10
WebApp/src/monitor-api.ts

@ -37,14 +37,8 @@ export class MonitorApi {
let apiStatus: ApiStatus;
if(this.mockServer) {
//await new Promise(resolve => setTimeout(resolve, 200));
/*apiStatus = {
v: Math.random() * 6000 + 36000,
c: Math.random() * 30000,
s: Math.random() * 14000,
t: Math.random() * 400 - 100,
alt: Math.random() * 4500000 - 200000
};*/
await new Promise(resolve => setTimeout(resolve, 200));
let t = new Date().getTime() / 1000.0;
apiStatus = {
v: (Math.cos(t*0.4)+1.0)*0.5 * 6000 + 36000,

Loading…
Cancel
Save