diff --git a/server/templates/history.html b/server/templates/history.html
index 3cd917c..df81e9d 100644
--- a/server/templates/history.html
+++ b/server/templates/history.html
@@ -71,8 +71,11 @@
-
+
diff --git a/static/js/history.js b/static/js/history.js
index 431a47a..ac88296 100644
--- a/static/js/history.js
+++ b/static/js/history.js
@@ -35,7 +35,8 @@
// ── Core state ──────────────────────────────────────────────────────
let st = {
- route: null, marker: null, points: [], timer: null, ctrl: null, activeRow: null
+ route: null, marker: null, points: [], timer: null, ctrl: null, activeRow: null,
+ maxIndex: null
};
let _cache = {};
let _geoTimer = null, _geoCtrl = null, _lastKey = null;
@@ -59,7 +60,9 @@
stopTm();
if (st.route) { map.removeLayer(st.route); st.route = null; }
if (st.marker) { map.removeLayer(st.marker); st.marker = null; }
- st.points = []; _cache = {}; _lastKey = null;
+ st.points = []; _cache = {}; _lastKey = null; st.maxIndex = null;
+ var maxTick = document.getElementById("trip-max-tick");
+ if (maxTick) maxTick.hidden = true;
if (_geoCtrl) { _geoCtrl.abort(); _geoCtrl = null; }
clearTimeout(_geoTimer);
timeline.hidden = true; summary.textContent = "Select a trip";
@@ -149,6 +152,27 @@
showPt(0);
}
+ // ── Max-speed marker helpers ────────────────────────────────────────
+ function jumpToMax() {
+ if (st.maxIndex == null) return;
+ stopTm();
+ showPt(st.maxIndex);
+ }
+ function placeMaxTick() {
+ var tick = document.getElementById("trip-max-tick");
+ var scrubber = document.getElementById("trip-scrubber");
+ if (!tick || !scrubber) return;
+ if (st.maxIndex == null || !st.points || st.points.length < 2) {
+ tick.hidden = true;
+ return;
+ }
+ var ratio = st.maxIndex / (st.points.length - 1);
+ var thumb = 16; // approximate range thumb width
+ var usable = Math.max(1, scrubber.clientWidth - thumb);
+ tick.style.left = (thumb / 2 + ratio * usable) + "px";
+ tick.hidden = false;
+ }
+
// ── Trip loader ─────────────────────────────────────────────────────
var _deb;
function loadTrip(id) {
@@ -172,10 +196,14 @@
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;
+ // Pin the fastest point on the route, remembering its index so
+ // clicking the marker scrubs the timeline to that point.
+ var maxPt = null; st.maxIndex = null;
for (var i = 0; i < d.points.length; i++) {
- if (!maxPt || d.points[i].speed > maxPt.speed) maxPt = d.points[i];
+ if (!maxPt || d.points[i].speed > maxPt.speed) {
+ maxPt = d.points[i];
+ st.maxIndex = i;
+ }
}
if (maxPt && maxPt.speed > 0) {
L.circleMarker([maxPt.latitude, maxPt.longitude], {
@@ -188,6 +216,7 @@
.bindTooltip("Max speed: " + fS(maxPt.speed), {
permanent: true, direction: "top", offset: [0, -8],
})
+ .on("click", jumpToMax)
.addTo(st.route);
}
st.route.addTo(map);
@@ -202,12 +231,16 @@
};
summary.textContent = fK(d.trip.distance_km) + " \u00b7 " + fD(d.trip.duration_seconds) + " \u00b7 avg " + fS(d.trip.average_speed_kmh) + " \u00b7 max " + fS(d.trip.max_speed_kmh) + " \u00b7 " + d.points.length + " pts";
initTL(d.points);
+ placeMaxTick();
} catch (e) { if (e.name !== "AbortError") showErr(e.message); }
finally { if (!sig.aborted) setLoading(false); }
}
// ── Scrubber & play ─────────────────────────────────────────────────
scrubber.addEventListener("input", function () { stopTm(); showPt(Number(scrubber.value)); });
+ var maxTick = document.getElementById("trip-max-tick");
+ if (maxTick) maxTick.addEventListener("click", jumpToMax);
+ window.addEventListener("resize", placeMaxTick);
playButton.addEventListener("click", function () {
if (st.timer) { stopTm(); return; }
if (Number(scrubber.value) >= st.points.length - 1) showPt(0);
diff --git a/static/yaris.css b/static/yaris.css
index 161573d..45df919 100644
--- a/static/yaris.css
+++ b/static/yaris.css
@@ -334,6 +334,21 @@ body {
padding-bottom: .375rem;
}
+/* Max-speed tick overlaid on the trip replay scrubber. */
+.trip-max-tick {
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ background: #f6c23e;
+ border: 2px solid #fff;
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, .15);
+ cursor: pointer;
+ z-index: 2;
+}
+
/* ── Dashcam / video ─────────────────────────────────────────────────────── */
/* Desktop: truncate long filenames */
diff --git a/templates/history.html b/templates/history.html
index 6be8a82..416a6a0 100644
--- a/templates/history.html
+++ b/templates/history.html
@@ -68,8 +68,11 @@
-
+