fix(phase26): geocode pre-caching (BUG-09) + gate trips on OBD presence (BUG-10)
This commit is contained in:
+52
-3
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user