From ca9cbd3540e00915e7f3f254ef20dc6c935314a5 Mon Sep 17 00:00:00 2001 From: fililip <31371657+fililip@users.noreply.github.com> Date: Thu, 24 Jul 2025 22:32:58 +0200 Subject: [PATCH] web/client: various improvements to the client app --- web/client/public/favicon.ico | Bin 0 -> 42454 bytes web/client/public/index.css | 27 ++++++++- web/client/public/index.html | 29 ++++++--- web/client/public/index.js | 109 ++++++++++++++++++++++++++-------- 4 files changed, 127 insertions(+), 38 deletions(-) create mode 100644 web/client/public/favicon.ico diff --git a/web/client/public/favicon.ico b/web/client/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c853db73c7ec414e78ed8f7f95bd5176c64aa158 GIT binary patch literal 42454 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

ZELcmxTVwj3 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 aF#kW6>(&Q%3p#NC0000 - xd2 + Cosmo PK rocket status preview +

-
-
-
-
- -
-
- + +
+
+
+
+ +
+
+ +
+
+ +
diff --git a/web/client/public/index.js b/web/client/public/index.js index 9929c9e..e1bb9c8 100644 --- a/web/client/public/index.js +++ b/web/client/public/index.js @@ -26,21 +26,55 @@ export const db = getDatabase(app); const dbRef = ref(db); -const entryLimit = 80; +Chart.defaults.font.family = "Geist Mono"; + +const entryLimit = 160; +const flyToCurrentPositionOnUpdate = false; let tempChart = null; let pressureChart = null; let altitudeChart = null; +let statusText = document.querySelector("#status"); +let latitudeText = document.querySelector("#latitude"); +let longitudeText = document.querySelector("#longitude"); +let timeText = document.querySelector("#time"); + let data = {}; let lastN = 0; const polylineData = []; let polyline; +function isPresent(value) { + return value !== null && value !== undefined; +} + function cloneObject(object) { return JSON.parse(JSON.stringify(object)); } +const RocketStatus = { + Dev: 0, + Idle: 1, + PreLaunch: 2, + Climbing: 3, + Apogee: 4, + DescentPrimary: 5, + Recovery: 6, + Error: 99, +}; + +const rocketStatusToText = { + [RocketStatus.Dev]: "dev", + [RocketStatus.Idle]: "idle/testing", + [RocketStatus.PreLaunch]: "pre-launch", + [RocketStatus.Climbing]: "climbing", + [RocketStatus.Apogee]: "at apogee", + [RocketStatus.DescentPrimary]: "descending", + [RocketStatus.Recovery]: "landed", + [RocketStatus.Error]: "error", +}; + const defaultData = { bmp: { altitude: 0, @@ -88,9 +122,9 @@ const defaultData = { status: 0, }; -function pushToArrayAndTrim(array, data) { +function pushToArrayAndTrim(array, data, limit = entryLimit) { array.push(data); - if (array.length > entryLimit) { + if (array.length > limit) { array.splice(0, 1); } } @@ -112,6 +146,22 @@ function backfillComponent(incomingData, component, key) { } } +function pushChartData(chart, data, time, limit = entryLimit) { + pushToArrayAndTrim( + chart.data.labels, + formatDate(time.hours, time.minutes, time.seconds), + limit, + ); + chart.data.datasets.forEach((dataset) => { + pushToArrayAndTrim(dataset.data, data, limit); + }); + chart.update("none"); +} + +function formatDate(hours = 0, minutes = 0, seconds = 0) { + return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; +} + function setData(incomingData) { try { data = incomingData; @@ -147,27 +197,17 @@ function setData(incomingData) { pushChartData(altitudeChart, data.bmp.altitude, time); pushPolylineData(data.gps.latitude, data.gps.longitude); + + statusText.innerText = `Status: ${rocketStatusToText[data.status]}`; + latitudeText.innerText = `Latitude: ${data.gps.latitude}`; + longitudeText.innerText = `Longitude: ${data.gps.longitude}`; + timeText.innerText = `Time: ${formatDate(time.hours, time.minutes, time.seconds)}`; } catch (err) { data = cloneObject(defaultData); console.log("error", err); } } -function pushChartData(chart, data, time) { - pushToArrayAndTrim( - chart.data.labels, - formatDate(time.hours, time.minutes, time.seconds), - ); - chart.data.datasets.forEach((dataset) => { - pushToArrayAndTrim(dataset.data, data); - }); - chart.update(); -} - -function formatDate(hours = 0, minutes = 0, seconds = 0) { - return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; -} - function initChart(handle, name, color) { const ctx = document.querySelector(`#${handle}-chart`); return new Chart(ctx, { @@ -190,6 +230,12 @@ function initChart(handle, name, color) { }); } +window.addEventListener("resize", () => { + tempChart.resize(); + pressureChart.resize(); + altitudeChart.resize(); +}); + function initCharts() { tempChart = initChart("temp", "Temperature", { r: 79, g: 192, b: 192 }); pressureChart = initChart("pressure", "Pressure", { r: 192, g: 79, b: 192 }); @@ -237,7 +283,7 @@ async function init() { { const historicalSnapshots = await retrieveHistoricalSnapshots(loraRef); - const skipCount = 4; // snapshots are apparently taken 4 times a second + const skipCount = Math.floor(historicalSnapshots.length / entryLimit); for (let i = 0; i < historicalSnapshots.length; i += skipCount) { const snapshot = historicalSnapshots[i]; setData(snapshot); @@ -249,18 +295,29 @@ async function init() { marker.setLatLng(newLoc); } + function updateApp(data) { + setData(data); + if (flyToCurrentPositionOnUpdate) { + map.flyTo([data.gps.latitude, data.gps.longitude], 14); + } + setMarkerLocation(data.gps.latitude, data.gps.longitude); + } + onValue(loraRef, (snapshot) => { const latestData = Object.values(snapshot.val())[0]; const snapshots = Object.values(latestData); - const data = snapshots[snapshots.length - 1]; - if (data.n) { - if (data.n == lastN) { + const latestDataEntry = snapshots[snapshots.length - 1]; + if (latestDataEntry.n) { + if (latestDataEntry.n == lastN) { return; } - setData(data); - map.flyTo([data.gps.latitude, data.gps.longitude], 14); - setMarkerLocation(data.gps.latitude, data.gps.longitude); - lastN = data.n; + if ( + isPresent(latestDataEntry.gps.longitude) && + isPresent(latestDataEntry.gps.latitude) + ) { + updateApp(latestDataEntry); + } + lastN = latestDataEntry.n; } }); }