Add data plot to sauna route
Signed-off-by: Thomas Klaehn <thomas.klaehn@perinet.io>
This commit is contained in:
parent
59cb6d1380
commit
5822328d9d
914
webui/package-lock.json
generated
914
webui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,7 @@
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"hamburger-menu-svelte": "^2.2.0"
|
||||
"hamburger-menu-svelte": "^2.2.0",
|
||||
"uplot": "^1.6.30"
|
||||
}
|
||||
}
|
||||
|
113
webui/src/lib/Uplot.svelte
Normal file
113
webui/src/lib/Uplot.svelte
Normal file
@ -0,0 +1,113 @@
|
||||
<script lang="ts">
|
||||
import 'uplot/dist/uPlot.min.css';
|
||||
|
||||
export let data_label = ""; // data label in legend
|
||||
export let unit = ""; // unit in legend
|
||||
|
||||
export let last_for_seconds = 20; // Period of time [s] the data are shifted out on the left
|
||||
let plotContainer;
|
||||
let data = [];
|
||||
data[0] = [Date.now()];
|
||||
data[1] = [null];
|
||||
|
||||
const PRECISION = 1;
|
||||
|
||||
export async function create(legend_label, legend_unit, duration) {
|
||||
console.log(legend_label);
|
||||
console.log(legend_unit);
|
||||
console.log(duration);
|
||||
data_label = legend_label;
|
||||
unit = legend_unit;
|
||||
last_for_seconds = duration;
|
||||
const uplotModule = await import('uplot');
|
||||
const uPlot = uplotModule.default;
|
||||
redraw(uPlot);
|
||||
}
|
||||
|
||||
export async function add_data(new_data) {
|
||||
data[0].push(Date.now());
|
||||
data[1].push(new_data);
|
||||
}
|
||||
|
||||
function redraw(uPlot) {
|
||||
function getSize() {
|
||||
let max_height = window.innerHeight;
|
||||
let max_width = window.innerWidth;
|
||||
let current_posY = plotContainer.getBoundingClientRect().top;
|
||||
let height = Math.max(max_height - current_posY - 200, 250);
|
||||
let width = Math.max(max_width - (2 * 50), 600);
|
||||
return {
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
const opts = {
|
||||
...getSize(),
|
||||
ms: 1,
|
||||
cursor: {drag: {setScale: false}},
|
||||
points: {show: false},
|
||||
pxSnap: false,
|
||||
pxAlign: 0,
|
||||
series: [
|
||||
{
|
||||
label: "time"
|
||||
},
|
||||
{
|
||||
label: data_label,
|
||||
stroke: "red",
|
||||
paths: uPlot.paths.spline(),
|
||||
value: (u, v, sidx, didx) => {
|
||||
if (didx == null) {
|
||||
let d = u.data[sidx];
|
||||
v = d[d.length - 1];
|
||||
}
|
||||
let value = v;
|
||||
if ( value != null) {
|
||||
value = value.toFixed(PRECISION) + unit;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
pxAlign: 0,
|
||||
points: { show: false },
|
||||
}
|
||||
],
|
||||
axes: [{grid: { show: false}}, {grid: { show: false}}],
|
||||
// hooks are used here to filter out the time series from the legend
|
||||
hooks: {
|
||||
init: [
|
||||
u => {
|
||||
[...u.root.querySelectorAll('.u-legend .u-series')].forEach((el, i) => {
|
||||
if (u.series[i].label ==="time") {
|
||||
el.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
let uplot = new uPlot(opts, data, plotContainer);
|
||||
|
||||
function update() {
|
||||
const now = Date.now();
|
||||
const scale = { min: now - (last_for_seconds * 1000), max: now };
|
||||
|
||||
// shift out data earlier than chart origin
|
||||
let last = Date.now();
|
||||
let first = last - (last_for_seconds * 1000);
|
||||
while(data[0][0] < first) {
|
||||
for(let i = 0; i < data.length; i++) {
|
||||
data[i].shift();
|
||||
}
|
||||
}
|
||||
|
||||
uplot.setData(data, false);
|
||||
uplot.setScale('x', scale);
|
||||
uplot.setLegend({idx: data[0].length - 1}, false);
|
||||
requestAnimationFrame(update);
|
||||
}
|
||||
requestAnimationFrame(update);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={plotContainer}></div>
|
@ -1,5 +1,6 @@
|
||||
<script>
|
||||
import { onMount } from "../../../node_modules/svelte/internal";
|
||||
import Plot from "$lib/Uplot.svelte"
|
||||
import icon from "$lib/images/sauna.svg"
|
||||
|
||||
let backend_url = "https://home.blackfinn.de/api/sauna";
|
||||
@ -8,6 +9,7 @@
|
||||
let temperature_unit = "°C"
|
||||
let time = "00:00:00";
|
||||
let updated = false;
|
||||
let plot;
|
||||
|
||||
function get_temperature() {
|
||||
fetch(backend_url)
|
||||
@ -16,6 +18,9 @@
|
||||
temperature_unit = data.unit
|
||||
temperature_value = data.value
|
||||
time = data.time.slice(11, 19)
|
||||
if(plot) {
|
||||
plot.add_data(Math.floor(Math.random() * 30) - 15);
|
||||
}
|
||||
updated = JSON.parse(data.valid);
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
@ -28,6 +33,9 @@
|
||||
}, 1000)
|
||||
|
||||
onMount(async () => {
|
||||
if(plot) {
|
||||
plot.create("Temperature", "°C", 4 * 60 * 60 /* 4h */);
|
||||
}
|
||||
get_temperature();
|
||||
});
|
||||
</script>
|
||||
@ -45,5 +53,8 @@
|
||||
{#if updated}
|
||||
<div>{time} Uhr:</div>
|
||||
<h1>{temperature_value} {temperature_unit}</h1>
|
||||
<div><Plot/></div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<Plot bind:this={plot}/>
|
||||
|
Loading…
Reference in New Issue
Block a user