Add force curve component
Add a component that shows the force curve of the last drive in a chart.
This commit is contained in:
parent
bd97723f8b
commit
6aa5c696c6
|
|
@ -0,0 +1,105 @@
|
||||||
|
'use strict'
|
||||||
|
/*
|
||||||
|
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
|
||||||
|
|
||||||
|
Component that renders a metric of the dashboard
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AppElement, html, css } from './AppElement.js'
|
||||||
|
import { customElement, property } from 'lit/decorators.js'
|
||||||
|
import Chart from 'chart.js/auto'
|
||||||
|
|
||||||
|
@customElement('dashboard-force-curve')
|
||||||
|
export class DashboardForceCurve extends AppElement {
|
||||||
|
static styles = css`
|
||||||
|
canvas {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
@property({ type: Object })
|
||||||
|
value = []
|
||||||
|
|
||||||
|
chart
|
||||||
|
|
||||||
|
firstUpdated () {
|
||||||
|
const ctx = this.renderRoot.querySelector('#chart').getContext('2d')
|
||||||
|
this.chart = new Chart(
|
||||||
|
ctx,
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
fill: true,
|
||||||
|
data: this.value?.map((data, index) => ({ y: data, x: index })),
|
||||||
|
pointRadius: 1,
|
||||||
|
borderColor: 'rgb(255,255,255)',
|
||||||
|
backgroundColor: 'rgb(220,220,220)'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Force Curve',
|
||||||
|
color: 'rgb(255,255,255)',
|
||||||
|
font: {
|
||||||
|
size: 32
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
boxWidth: 0,
|
||||||
|
font: {
|
||||||
|
size: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
type: 'linear',
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
ticks: {
|
||||||
|
color: 'rgb(255,255,255)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animations: {
|
||||||
|
tension: {
|
||||||
|
duration: 200,
|
||||||
|
easing: 'easeInQuad'
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
duration: 200,
|
||||||
|
easing: 'easeInQuad'
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
duration: 200,
|
||||||
|
easing: 'easeInQuad'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (this.chart?.data) {
|
||||||
|
this.chart.data.datasets[0].data = this.value?.map((data, index) => ({ y: data, x: index }))
|
||||||
|
this.forceCurve = this.value
|
||||||
|
this.chart.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<canvas id="chart"></canvas>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
import { AppElement, html, css } from './AppElement.js'
|
import { AppElement, html, css } from './AppElement.js'
|
||||||
import { APP_STATE } from '../store/appState.js'
|
import { APP_STATE } from '../store/appState.js'
|
||||||
import { customElement, property } from 'lit/decorators.js'
|
import { customElement, property } from 'lit/decorators.js'
|
||||||
|
import './DashboardForceCurve.js'
|
||||||
import './DashboardMetric.js'
|
import './DashboardMetric.js'
|
||||||
import './DashboardActions.js'
|
import './DashboardActions.js'
|
||||||
import './BatteryIcon.js'
|
import './BatteryIcon.js'
|
||||||
|
|
@ -32,7 +33,7 @@ export class PerformanceDashboard extends AppElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dashboard-metric, dashboard-actions {
|
dashboard-metric, dashboard-actions,dashboard-force-curve {
|
||||||
background: var(--theme-widget-color);
|
background: var(--theme-widget-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -69,6 +70,7 @@ export class PerformanceDashboard extends AppElement {
|
||||||
}
|
}
|
||||||
</dashboard-metric>`
|
</dashboard-metric>`
|
||||||
: html`<dashboard-metric .icon=${icon_paddle} unit="total" .value=${metrics?.totalNumberOfStrokes?.value}></dashboard-metric>`}
|
: html`<dashboard-metric .icon=${icon_paddle} unit="total" .value=${metrics?.totalNumberOfStrokes?.value}></dashboard-metric>`}
|
||||||
|
<dashboard-force-curve .value=${this.appState?.metrics?.driveHandleForceCurve} style="grid-column: span 2"></dashboard-force-curve>
|
||||||
<dashboard-metric .icon=${icon_fire} unit="kcal" .value=${metrics?.totalCalories?.value}></dashboard-metric>
|
<dashboard-metric .icon=${icon_fire} unit="kcal" .value=${metrics?.totalCalories?.value}></dashboard-metric>
|
||||||
<dashboard-metric .icon=${icon_clock} .value=${metrics?.totalMovingTimeFormatted?.value}></dashboard-metric>
|
<dashboard-metric .icon=${icon_clock} .value=${metrics?.totalMovingTimeFormatted?.value}></dashboard-metric>
|
||||||
<dashboard-actions .appState=${this.appState}></dashboard-actions>
|
<dashboard-actions .appState=${this.appState}></dashboard-actions>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import NoSleep from 'nosleep.js'
|
||||||
import { filterObjectByKeys } from './helper.js'
|
import { filterObjectByKeys } from './helper.js'
|
||||||
|
|
||||||
const rowingMetricsFields = ['totalNumberOfStrokes', 'totalLinearDistanceFormatted', 'totalCalories', 'cyclePower', 'heartrate',
|
const rowingMetricsFields = ['totalNumberOfStrokes', 'totalLinearDistanceFormatted', 'totalCalories', 'cyclePower', 'heartrate',
|
||||||
'heartrateBatteryLevel', 'cyclePaceFormatted', 'cycleStrokeRate', 'totalMovingTimeFormatted']
|
'heartrateBatteryLevel', 'cyclePaceFormatted', 'cycleStrokeRate', 'totalMovingTimeFormatted', 'driveHandleForceCurve']
|
||||||
|
|
||||||
export function createApp (app) {
|
export function createApp (app) {
|
||||||
const urlParameters = new URLSearchParams(window.location.search)
|
const urlParameters = new URLSearchParams(window.location.search)
|
||||||
|
|
@ -79,11 +79,11 @@ export function createApp (app) {
|
||||||
// if we are in reset state only update heart rate and peripheral mode
|
// if we are in reset state only update heart rate and peripheral mode
|
||||||
if (data.totalNumberOfStrokes < 1) {
|
if (data.totalNumberOfStrokes < 1) {
|
||||||
if (data.totalLinearDistanceFormatted > 0) {
|
if (data.totalLinearDistanceFormatted > 0) {
|
||||||
activeFields = ['totalLinearDistanceFormatted', 'heartrate', 'heartrateBatteryLevel']
|
activeFields = ['totalLinearDistanceFormatted', 'heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve']
|
||||||
} else if (data.totalMovingTimeFormatted !== '00:00') {
|
} else if (data.totalMovingTimeFormatted !== '00:00') {
|
||||||
activeFields = ['totalMovingTimeFormatted', 'heartrate', 'heartrateBatteryLevel']
|
activeFields = ['totalMovingTimeFormatted', 'heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve']
|
||||||
} else {
|
} else {
|
||||||
activeFields = ['heartrate', 'heartrateBatteryLevel']
|
activeFields = ['heartrate', 'heartrateBatteryLevel', 'driveHandleForceCurve']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@
|
||||||
"pigpio": "3.3.1",
|
"pigpio": "3.3.1",
|
||||||
"serve-static": "1.14.2",
|
"serve-static": "1.14.2",
|
||||||
"ws": "8.5.0",
|
"ws": "8.5.0",
|
||||||
"xml2js": "0.4.23"
|
"xml2js": "0.4.23",
|
||||||
|
"chart.js": "^4.2.1"
|
||||||
},
|
},
|
||||||
"//fix1Comment": "version 0.5.3-8 currently does not work with bleno",
|
"//fix1Comment": "version 0.5.3-8 currently does not work with bleno",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue