fix(phase26): geocode pre-caching (BUG-09) + gate trips on OBD presence (BUG-10)

This commit is contained in:
Mathieu Moran
2026-08-11 02:38:00 -04:00
parent a709517973
commit 7e913558f6
4 changed files with 107 additions and 3 deletions
+52 -3
View File
@@ -33,17 +33,65 @@
let _geoTimer = null;
let _lastGeoKey = null;
let _geoCache = {}; // key → label, pre-populated on trip load
function _geoKey(lat, lon) {
return `${lat.toFixed(3)},${lon.toFixed(3)}`;
}
function preloadGeocodes(points) {
// Collect unique rounded coordinates and batch-fetch all labels upfront.
_geoCache = {};
const seen = new Set();
const queue = [];
for (const p of points) {
const key = _geoKey(p.latitude, p.longitude);
if (seen.has(key)) continue;
seen.add(key);
queue.push({ key, lat: p.latitude, lon: p.longitude });
}
// Fetch in parallel with a small concurrency cap
const CONCURRENCY = 4;
let idx = 0;
function next() {
if (idx >= queue.length) return;
const item = queue[idx++];
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 4000);
return fetch(`/api/geocode?lat=${item.lat}&lon=${item.lon}`, { signal: ctrl.signal })
.then(r => { clearTimeout(t); return r.ok ? r.json() : null; })
.then(data => {
_geoCache[item.key] = (data && data.label) || null;
})
.catch(() => { clearTimeout(t); _geoCache[item.key] = null; })
.finally(() => next());
}
// Start initial batch
for (let i = 0; i < CONCURRENCY && i < queue.length; i++) next();
}
function geocodePoint(lat, lon) {
const key = `${lat.toFixed(3)},${lon.toFixed(3)}`;
const key = _geoKey(lat, lon);
if (key === _lastGeoKey) return;
_lastGeoKey = key;
const fallback = `${lat.toFixed(5)}, ${lon.toFixed(5)}`;
// Use cache if available
if (_geoCache.hasOwnProperty(key)) {
replayLocation.textContent = _geoCache[key] || fallback;
return;
}
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 6000);
const t = setTimeout(() => ctrl.abort(), 4000);
fetch(`/api/geocode?lat=${lat}&lon=${lon}`, { signal: ctrl.signal })
.then(r => { clearTimeout(t); return r.ok ? r.json() : null; })
.then(data => { replayLocation.textContent = (data && data.label) ? data.label : fallback; })
.then(data => {
const label = (data && data.label) || fallback;
_geoCache[key] = (data && data.label) || null;
replayLocation.textContent = label;
})
.catch(() => { clearTimeout(t); replayLocation.textContent = fallback; });
}
@@ -177,6 +225,7 @@
+ `avg ${formatSpeed(result.trip.average_speed_kmh)} · `
+ `max ${formatSpeed(result.trip.max_speed_kmh)} · `
+ `${result.points.length} route points`;
preloadGeocodes(result.points);
initializeTimeline(result.points);
}