More configuration

This commit is contained in:
Jan Zípek 2022-08-14 12:46:15 +02:00
parent 94d2549fca
commit 6e867a0fae
Signed by: kamen
GPG Key ID: A17882625B33AC31
1 changed files with 121 additions and 45 deletions

View File

@ -20,7 +20,7 @@ function load() {
fetch("/api/sensors") fetch("/api/sensors")
.then((r) => r.json()) .then((r) => r.json())
.then((sensors) => { .then((sensors) => {
$sensorsContainer.innerHTML = '' $sensorsContainer.innerHTML = "";
sensorComponents = sensors.map((sensor) => createSensor(sensor)); sensorComponents = sensors.map((sensor) => createSensor(sensor));
sensorComponents.forEach((component) => sensorComponents.forEach((component) =>
@ -74,10 +74,28 @@ function renderConfig({ sensor, onSave, shown }) {
<label>Name</label> <label>Name</label>
<input name="name" value="${config.name}" /> <input name="name" value="${config.name}" />
</div> </div>
<div class="input">
<label>Type</label>
<select name="graphType" value="${config.graphType || 'line'}">
<option value="line">Line</option>
<option value="points">Points</option>
<option value="lineAndPoints">Line + Points</option>
<option value="bar">Bar</option>
</select>
</div>
<div class="input"> <div class="input">
<label>Unit</label> <label>Unit</label>
<input name="unit" value="${config.unit}" /> <input name="unit" value="${config.unit}" />
</div> </div>
<div class="input">
<label>Min value</label>
<input name="min" value="${config.min}" />
</div>
<div class="input">
<label>Max value</label>
<input name="max" value="${config.max}" />
</div>
<div class="actions"> <div class="actions">
<button onclick=${hideConfig} type="button">Cancel</button> <button onclick=${hideConfig} type="button">Cancel</button>
@ -91,27 +109,58 @@ function renderConfig({ sensor, onSave, shown }) {
); );
} }
const CURRENT_FILTERS = { const CURRENT_FILTERS = loadFilters();
interval: "week",
refresh: "1s",
customFrom: new Date().toISOString(),
customTo: new Date().toISOString(),
};
function refreshAll() { function loadFilters() {
sensorComponents.forEach(c => c.refreshValues()) const params = new URLSearchParams(location.search.replace(/^\?/, ""));
return {
interval: params.get("interval") || "week",
refresh: "1s",
customFrom: params.get("from") || new Date().toISOString(),
customTo: params.get("to") || new Date().toISOString(),
};
} }
let isCustomSelected = false function saveFilters() {
let lastIntervalSelected = 'week' const values = {
interval: CURRENT_FILTERS.interval,
};
if (CURRENT_FILTERS.interval === "custom") {
values.from = CURRENT_FILTERS.customFrom.toISOString();
values.to = CURRENT_FILTERS.customTo.toISOString();
}
const url = new URL(location.href);
const params = new URLSearchParams(values);
url.search = params.toString();
history.replaceState(null, null, url.toString());
}
function refreshAll() {
sensorComponents.forEach((c) => c.refreshValues());
}
let lastIntervalSelected = CURRENT_FILTERS.interval;
function splitDateTime(v) { function splitDateTime(v) {
const d = new Date(v) const d = new Date(v);
const date = d.getFullYear() + '-' + (d.getMonth() + 1).toString().padStart(2, '0') + '-' + d.getDate().toString().padStart(2, '0') const date =
const time = d.getHours().toString().padStart(2, '0') + ':' + d.getMinutes().toString().padStart(2, '0') d.getFullYear() +
"-" +
(d.getMonth() + 1).toString().padStart(2, "0") +
"-" +
d.getDate().toString().padStart(2, "0");
const time =
d.getHours().toString().padStart(2, "0") +
":" +
d.getMinutes().toString().padStart(2, "0");
return [date, time] return [date, time];
} }
function renderFilters() { function renderFilters() {
@ -128,23 +177,26 @@ function renderFilters() {
CURRENT_FILTERS.customFrom = from.toISOString(); CURRENT_FILTERS.customFrom = from.toISOString();
CURRENT_FILTERS.customTo = to.toISOString(); CURRENT_FILTERS.customTo = to.toISOString();
} else { } else {
CURRENT_FILTERS.customFrom = new Date(`${data.fromDate} ${data.fromTime}`) CURRENT_FILTERS.customFrom = new Date(
CURRENT_FILTERS.customTo = new Date(`${data.toDate} ${data.toTime}`) `${data.fromDate} ${data.fromTime}`
);
CURRENT_FILTERS.customTo = new Date(`${data.toDate} ${data.toTime}`);
} }
refreshAll() refreshAll();
renderFilters() renderFilters();
saveFilters();
}; };
const handleIntervalChange = (e) => { const handleIntervalChange = (e) => {
lastIntervalSelected = e.target.value lastIntervalSelected = e.target.value;
renderFilters() renderFilters();
} };
const customFrom = splitDateTime(CURRENT_FILTERS.customFrom) const customFrom = splitDateTime(CURRENT_FILTERS.customFrom);
const customTo = splitDateTime(CURRENT_FILTERS.customTo) const customTo = splitDateTime(CURRENT_FILTERS.customTo);
const isCustomSelected = lastIntervalSelected === 'custom' const isCustomSelected = lastIntervalSelected === "custom";
render( render(
$filters, $filters,
@ -153,7 +205,11 @@ function renderFilters() {
<form class="horizontal" onsubmit=${handleApply}> <form class="horizontal" onsubmit=${handleApply}>
<div class="input"> <div class="input">
<label>Interval</label> <label>Interval</label>
<select name="interval" value="${lastIntervalSelected}" onchange=${handleIntervalChange}> <select
name="interval"
value="${lastIntervalSelected}"
onchange=${handleIntervalChange}
>
<option value="hour">Hour</option> <option value="hour">Hour</option>
<option value="day">Day</option> <option value="day">Day</option>
<option value="week">Week</option> <option value="week">Week</option>
@ -162,22 +218,32 @@ function renderFilters() {
</select> </select>
</div> </div>
${isCustomSelected ? html` ${isCustomSelected
<div class="input date-time"> ? html`
<label>From</label> <div class="input date-time">
<div> <label>From</label>
<input type="date" value="${customFrom[0]}" name="fromDate" /> <div>
<input type="time" value="${customFrom[1]}" name="fromTime" /> <input
</div> type="date"
</div> value="${customFrom[0]}"
<div class="input date-time"> name="fromDate"
<label>To</label> />
<div> <input
<input type="date" value="${customTo[0]}" name="toDate" /> type="time"
<input type="time" value="${customTo[1]}" name="toTime" /> value="${customFrom[1]}"
</div> name="fromTime"
</div> />
` : undefined} </div>
</div>
<div class="input date-time">
<label>To</label>
<div>
<input type="date" value="${customTo[0]}" name="toDate" />
<input type="time" value="${customTo[1]}" name="toTime" />
</div>
</div>
`
: undefined}
<button>Apply</button> <button>Apply</button>
</form> </form>
@ -246,20 +312,30 @@ function createSensor(sensor) {
const renderBody = (range, values) => { const renderBody = (range, values) => {
const { from, to } = range; const { from, to } = range;
const minValue = parseFloat(sensor.config.min);
const maxValue = parseFloat(sensor.config.max);
const customRange = !isNaN(minValue) && !isNaN(maxValue);
Plotly.newPlot( Plotly.newPlot(
body, body,
[ [
{ {
type: "lines", ...(sensor.config.graphType === 'line' && { type: 'scatter', mode: 'lines' }),
...(sensor.config.graphType === 'points' && { type: 'scatter', mode: 'markers' }),
...(sensor.config.graphType === 'lineAndPoints' && { type: 'scatter', mode: 'lines+markers' }),
...(sensor.config.graphType === 'bar' && { type: 'bar' }),
x: values.map((v) => new Date(v.timestamp * 1000)), x: values.map((v) => new Date(v.timestamp * 1000)),
y: values.map((v) => v.value), y: values.map((v) => v.value),
}, },
], ],
{ {
xaxis: { range: [from, to], type: "date" }, xaxis: { range: [from, to], type: "date" },
yaxis: {
...(customRange && { range: [minValue, maxValue] }),
...(sensor.config.unit && { ticksuffix: ` ${sensor.config.unit}` }),
},
margin: { margin: {
l: 50, l: 70,
r: 20, r: 20,
b: 60, b: 60,
t: 20, t: 20,
@ -302,7 +378,7 @@ function createSensor(sensor) {
return { return {
container, container,
refreshValues refreshValues,
}; };
} }