From 87d63e8f3242d533fbed62ad4e0ccaac518359b5 Mon Sep 17 00:00:00 2001 From: Mathieu Moran Date: Sat, 15 Aug 2026 17:54:49 -0400 Subject: [PATCH] feat: pin the fastest point on the trip replay map (FEAT-16) When a route loads, add an amber circle + permanent 'Max speed: X km/h' tooltip at the point with the highest speed. Shared history.js, so it applies to both the Pi and the server portal. --- FEATURES.md | 11 +++++++++++ static/js/history.js | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/FEATURES.md b/FEATURES.md index b26bf55..c85d14f 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -35,6 +35,7 @@ dedicated PLAN.md phase (or fold it into the relevant existing work) and mark it | FEAT-13 | `IDEA` | Flush uploaded tracking rows from local DB | unassigned | | FEAT-14 | `SHIPPED` | Second T3U to replace onboard wlan0 (dual AC radios) | Phase 29 | | FEAT-15 | `SHIPPED` | Clear DTC codes from the DTC page | Phase 29 | +| FEAT-16 | `SHIPPED` | Max-speed marker on trip replay map | Phase 29 | --- @@ -291,3 +292,13 @@ dedicated PLAN.md phase (or fold it into the relevant existing work) and mark it `POST /api/dtc/clear` in `app.py`, and the button + confirm/status JS in `templates/dtc.html`. +### FEAT-16 — Max-speed marker on trip replay map +- **Status**: `SHIPPED` 2026-08-15 +- **Area**: `static/js/history.js` +- **Phase**: Phase 29 +- **What**: when a trip's route loads, the replay map now pins the fastest point with an + amber circle + a permanent "Max speed: X km/h" tooltip. It uses the per-point speed (OBD + when available, otherwise the smoothed GPS-derived value), so it matches the trip summary's + `max_speed_kmh`. Works identically on the Pi and the server portal (shared `history.js`). + + diff --git a/static/js/history.js b/static/js/history.js index a3b27dd..431a47a 100644 --- a/static/js/history.js +++ b/static/js/history.js @@ -172,6 +172,24 @@ L.marker(coords[0]).bindPopup("Start").addTo(st.route); L.marker(coords[coords.length - 1]).bindPopup("End").addTo(st.route); } + // Pin the fastest point on the route. + var maxPt = null; + for (var i = 0; i < d.points.length; i++) { + if (!maxPt || d.points[i].speed > maxPt.speed) maxPt = d.points[i]; + } + if (maxPt && maxPt.speed > 0) { + L.circleMarker([maxPt.latitude, maxPt.longitude], { + radius: 6, + color: "#fff", + weight: 2, + fillColor: "#f6c23e", + fillOpacity: 1, + }) + .bindTooltip("Max speed: " + fS(maxPt.speed), { + permanent: true, direction: "top", offset: [0, -8], + }) + .addTo(st.route); + } st.route.addTo(map); if (sig.aborted) { cleanup(); return; } if (coords.length > 1) map.fitBounds(st.route.getBounds(), {padding: [24, 24], maxZoom: 15});