fix(phase26): debounce trip clicks, guard against stale renders
This commit is contained in:
+20
-24
@@ -28,6 +28,7 @@
|
||||
let replayPoints = [];
|
||||
let replayTimer = null;
|
||||
let replayController = null;
|
||||
let _replayDebounce = null;
|
||||
const recenterBtn = document.getElementById("btn-recenter-history");
|
||||
const replayLocation = document.getElementById("trip-replay-location");
|
||||
|
||||
@@ -193,21 +194,15 @@
|
||||
replayController.abort();
|
||||
}
|
||||
replayController = new AbortController();
|
||||
const response = await fetch(
|
||||
`/api/trip/${tripId}`,
|
||||
{ signal: replayController.signal }
|
||||
);
|
||||
const signal = replayController.signal;
|
||||
try {
|
||||
const response = await fetch(`/api/trip/${tripId}`, { signal });
|
||||
const result = await response.json();
|
||||
if (!response.ok) {
|
||||
throw new Error(result.error || "Could not load trip route.");
|
||||
}
|
||||
if (!response.ok) throw new Error(result.error || "Could not load trip route.");
|
||||
if (signal.aborted) return;
|
||||
|
||||
if (routeLayer) {
|
||||
routeLayer.remove();
|
||||
}
|
||||
const coordinates = result.points.map(function (point) {
|
||||
return [point.latitude, point.longitude];
|
||||
});
|
||||
if (routeLayer) routeLayer.remove();
|
||||
const coordinates = result.points.map(p => [p.latitude, p.longitude]);
|
||||
routeLayer = L.featureGroup();
|
||||
L.polyline(coordinates, { color: "#4e73df", weight: 5 }).addTo(routeLayer);
|
||||
if (coordinates.length) {
|
||||
@@ -215,11 +210,13 @@
|
||||
L.marker(coordinates[coordinates.length - 1]).bindPopup("Trip end").addTo(routeLayer);
|
||||
}
|
||||
routeLayer.addTo(map);
|
||||
if (signal.aborted) { routeLayer.remove(); return; }
|
||||
if (coordinates.length > 1) {
|
||||
map.fitBounds(routeLayer.getBounds(), { padding: [24, 24] });
|
||||
} else if (coordinates.length === 1) {
|
||||
map.setView(coordinates[0], 15);
|
||||
}
|
||||
if (signal.aborted) { routeLayer.remove(); return; }
|
||||
recenterBtn.hidden = false;
|
||||
recenterBtn.onclick = function () {
|
||||
if (coordinates.length > 1) {
|
||||
@@ -233,8 +230,12 @@
|
||||
+ `avg ${formatSpeed(result.trip.average_speed_kmh)} · `
|
||||
+ `max ${formatSpeed(result.trip.max_speed_kmh)} · `
|
||||
+ `${result.points.length} route points`;
|
||||
if (signal.aborted) { routeLayer.remove(); return; }
|
||||
preloadGeocodes(result.points);
|
||||
initializeTimeline(result.points);
|
||||
} catch (e) {
|
||||
if (e.name !== "AbortError") showError(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
const tripList = document.getElementById("trip-list");
|
||||
@@ -351,18 +352,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Replay button click (desktop) or row click (mobile)
|
||||
const button = event.target.closest("[data-trip-id]");
|
||||
const row = event.target.closest("tr[data-trip-id]");
|
||||
// Replay button click (desktop) or row click (mobile) — debounced
|
||||
const tripId = button ? button.dataset.tripId : (row ? row.dataset.tripId : null);
|
||||
if (!tripId) {
|
||||
return;
|
||||
}
|
||||
replayTrip(tripId).catch(function (replayError) {
|
||||
if (replayError.name !== "AbortError") {
|
||||
showError(replayError.message);
|
||||
}
|
||||
});
|
||||
if (!tripId) return;
|
||||
clearTimeout(_replayDebounce);
|
||||
_replayDebounce = setTimeout(() => {
|
||||
replayTrip(tripId);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
scrubber.addEventListener("input", function () {
|
||||
|
||||
Reference in New Issue
Block a user