From 548808fd832c6dc6fa81935728fb9c963e21f8e7 Mon Sep 17 00:00:00 2001 From: Mathieu Moran Date: Mon, 10 Aug 2026 02:45:41 -0400 Subject: [PATCH] feat(history): show reverse-geocoded location during trip scrubbing - Location name (road + city) appears below time/speed in the timeline panel - Debounced 600ms so dragging the scrubber doesn't spam Nominatim - Deduped by ~3 decimal lat/lon so stationary replay doesn't re-fetch - Cleared when a new trip is loaded Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- static/js/history.js | 31 +++++++++++++++++++++++++++++++ templates/history.html | 1 + 2 files changed, 32 insertions(+) diff --git a/static/js/history.js b/static/js/history.js index 0810776..f2b3fcd 100644 --- a/static/js/history.js +++ b/static/js/history.js @@ -22,6 +22,34 @@ let replayTimer = null; let replayController = null; const recenterBtn = document.getElementById("btn-recenter-history"); + const replayLocation = document.getElementById("trip-replay-location"); + + let _geoTimer = null; + let _lastGeoKey = null; + + function geocodePoint(lat, lon) { + const key = `${lat.toFixed(3)},${lon.toFixed(3)}`; + if (key === _lastGeoKey) return; + _lastGeoKey = key; + fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lon}`, { + headers: { 'Accept-Language': 'en' } + }) + .then(r => r.ok ? r.json() : null) + .then(data => { + if (!data) return; + const a = data.address || {}; + const road = a.road || a.hamlet || a.village || a.suburb || ''; + const city = a.city || a.town || a.village || a.municipality || ''; + replayLocation.textContent = [road, city].filter(Boolean).join(', ') + || data.display_name?.split(',').slice(0, 2).join(',') || ''; + }) + .catch(() => {}); + } + + function scheduleGeocode(lat, lon) { + clearTimeout(_geoTimer); + _geoTimer = setTimeout(() => geocodePoint(lat, lon), 600); + } function formatDuration(seconds) { const hours = Math.floor(seconds / 3600); @@ -69,6 +97,7 @@ replayTime.textContent = formatDate(point.datetime); const source = point.speed_source === "obd" ? "OBD wheel" : "GPS"; replaySpeed.textContent = `${source} speed: ${formatSpeed(point.speed)}`; + scheduleGeocode(point.latitude, point.longitude); } function initializeTimeline(points) { @@ -77,6 +106,8 @@ scrubber.max = Math.max(0, points.length - 1); scrubber.value = 0; timeline.hidden = points.length === 0; + replayLocation.textContent = ''; + _lastGeoKey = null; if (vehicleMarker) { vehicleMarker.remove(); } diff --git a/templates/history.html b/templates/history.html index 41436cf..dd139fc 100644 --- a/templates/history.html +++ b/templates/history.html @@ -67,6 +67,7 @@ +