diff --git a/WebApp/src/components/widgets/chronometer.css b/WebApp/src/components/widgets/chronometer.css new file mode 100644 index 0000000..5046bc9 --- /dev/null +++ b/WebApp/src/components/widgets/chronometer.css @@ -0,0 +1,3 @@ +div.widget.chronometer span.integral-value { + font-size: 2.0rem; +} diff --git a/WebApp/src/components/widgets/chronometer.tsx b/WebApp/src/components/widgets/chronometer.tsx new file mode 100644 index 0000000..7e0e114 --- /dev/null +++ b/WebApp/src/components/widgets/chronometer.tsx @@ -0,0 +1,54 @@ +import { NumericValue } from 'components/widgets/numeric-value'; + +require('./chronometer.css'); + +export class Chronometer extends NumericValue { + private realTimeValue = 0; + private realTimeReference = 0; + + private animating = false; + private shuttingDown = false; + + protected mainClassName() { return 'numeric-value chronometer'; } + + protected onValueChange(value: number) { + let now = Date.now() / 1000; + + let realTimeValue = this.realTimeValue + (now - this.realTimeReference); + + if(Math.abs(value - realTimeValue) < 2.0) + return; + + this.realTimeValue = value; + this.realTimeReference = now; + realTimeValue = value; + this.startAnimation(); + } + + private startAnimation() { + if(this.animating) + return; + this.animating = true; + this.animate(); + } + + onbeforeremove(vnode: any) { + this.shuttingDown = true; + super.onbeforeremove(vnode); + } + + private animate() { + if(this.shuttingDown) return; + + let now = Date.now() / 1000; + let realTimeValue = this.realTimeValue + (now - this.realTimeReference); + + let hours = Math.floor(realTimeValue / 3600); + let minutes = Math.floor((realTimeValue - hours * 3600)/60); + let seconds = Math.floor(realTimeValue - hours * 3600 - minutes * 60); + + this.integralValueElement.innerText = (hours < 10 ? '0' : '') + hours + ':' + (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds; + + setTimeout(() => this.animate(), (Math.ceil(realTimeValue) + 0.05 - realTimeValue) * 1000); + } +} diff --git a/WebApp/src/components/widgets/gauge.tsx b/WebApp/src/components/widgets/gauge.tsx index ea2082f..579da05 100644 --- a/WebApp/src/components/widgets/gauge.tsx +++ b/WebApp/src/components/widgets/gauge.tsx @@ -36,6 +36,8 @@ export class Gauge extends NumericValue { protected onValueChange(value: number) { let now = Date.now() / 1000.0; + super.onValueChange(value); + let ratio = value / (this.maxValue || 1.0); let numBars = this.bars.length; let threshold = 0.33 / numBars; diff --git a/WebApp/src/components/widgets/numeric-value.css b/WebApp/src/components/widgets/numeric-value.css index 1bb0933..ddb1d33 100644 --- a/WebApp/src/components/widgets/numeric-value.css +++ b/WebApp/src/components/widgets/numeric-value.css @@ -1,5 +1,5 @@ div.widget span.integral-value { - font-size: 2.3rem; + font-size: 2.2rem; font-family: monospace; } diff --git a/WebApp/src/components/widgets/numeric-value.tsx b/WebApp/src/components/widgets/numeric-value.tsx index 0c81e24..b07dda8 100644 --- a/WebApp/src/components/widgets/numeric-value.tsx +++ b/WebApp/src/components/widgets/numeric-value.tsx @@ -13,8 +13,8 @@ export class NumericValue extends Widget { protected icon?: string; - private integralValueElement: HTMLElement; - private decimalValueElement: HTMLElement; + protected integralValueElement: HTMLElement; + protected decimalValueElement: HTMLElement; constructor(vnode: any) { super(vnode); @@ -27,7 +27,7 @@ export class NumericValue extends Widget { this.icon = vnode.attrs.icon || null; - this.value.onChange(() => this.onValueChange_()); + this.value.onChange(() => this.onValueChange(this.getClampedValue())); } view(vnode: m.Vnode<{}, {}>): m.Children { @@ -48,27 +48,25 @@ export class NumericValue extends Widget { return []; } - protected onValueChange(newValue: number) { - } - - private onValueChange_() { + private getClampedValue() { let value = this.value.get(); if(this.minValue !== null) value = Math.max(value, this.minValue); if(this.maxValue !== null) value = Math.min(value, this.maxValue); - - let valueStr = value.toFixed(this.decimals); + return value; + } + + protected onValueChange(newValue: number) { + let valueStr = newValue.toFixed(this.decimals); let parts = valueStr.split('.'); this.integralValueElement.innerText = parts[0]; this.decimalValueElement.innerText = this.decimals > 0 ? '.' + parts[1] : ''; - - this.onValueChange(value); } oncreate(vnode: any) { this.integralValueElement = vnode.dom.querySelector('span.integral-value'); this.decimalValueElement = vnode.dom.querySelector('span.decimal-value'); - this.onValueChange_(); + this.onValueChange(this.getClampedValue()); } } diff --git a/WebApp/src/pages/dashboard/dashboard-page.tsx b/WebApp/src/pages/dashboard/dashboard-page.tsx index b4dc56a..9e087d1 100644 --- a/WebApp/src/pages/dashboard/dashboard-page.tsx +++ b/WebApp/src/pages/dashboard/dashboard-page.tsx @@ -5,6 +5,7 @@ import { Pipe } from 'utilities/pipe'; import { Clock } from 'components/widgets/clock'; import { NumericValue } from 'components/widgets/numeric-value'; +import { Chronometer } from 'components/widgets/chronometer'; import { GaugeLinear } from 'components/widgets/gauge-linear'; import { GaugeCircular } from 'components/widgets/gauge-circular'; import { GaugeBattery } from 'components/widgets/gauge-battery'; @@ -28,6 +29,7 @@ export class DashboardPage extends Page { private battery = new Pipe(0.0); private speed = new Pipe(0.0); + private tripTotalTime = new Pipe(0.0); private tripDistance = new Pipe(0.0); private tripAverageSpeed = new Pipe(0.0); private tripEnergy = new Pipe(0.0); @@ -62,6 +64,7 @@ export class DashboardPage extends Page { this.speed.set(this.status.speed * 3.6); // convert m/s to km/h + this.tripTotalTime.set(this.status.tripTotalTime); this.tripDistance.set(this.status.tripDistance/1000); this.tripAverageSpeed.set(this.status.tripDistance/1000 / (Math.max(1.0, this.status.tripMovingTime)/3600)); this.tripEnergy.set(this.status.tripMotorEnergy); @@ -72,7 +75,7 @@ export class DashboardPage extends Page { this.altitude.set(this.status.altitude); if(this.autoRefresh) - setTimeout(() => { if(this.autoRefresh) this.refresh(); }, 150); + setTimeout(() => { if(this.autoRefresh) this.refresh(); }, 400); } view() { @@ -90,6 +93,7 @@ export class DashboardPage extends Page {
+