Add a Distance/Time toggle to the profile chart's x-axis
CI / check (push) Successful in 42s
CI / deploy (push) Successful in 16s

TrackStats.build_profile now also computes elapsed_secs per point
(relative to the first known timestamp), alongside the existing
cumulative distance. Point x-positions stay distance-based either
way — only the shared axis strip's 5 tick labels (and the tooltip)
switch between the two, so toggling is a cheap re-render rather than
rebuilding the charts. The toggle only appears when a track actually
has elapsed-time data to switch to.
This commit is contained in:
randy committed 2026-09-07 13:54:49 +02:00
1 parent 4f7fe3c2a4
commit a0476f1204
7 files changed
+138 -14

No files matched your search

+19 -8
View File
@@ -265,14 +265,16 @@ when present. `Maptool::TrackStats.build_profile` (called from both
`Gpx`/`Fit`, alongside `.compute` above) produces this: one entry per
point with cumulative distance (computed the same way for every
format, not trusted from a device's own odometer field, so a GPX and a
FIT track are directly comparable), elevation, and whatever
speed/cadence/heart-rate extras that point's format/file carried —
`nil` fields simply don't render their chart. For FIT, those extras
are the `record` message's own `heart_rate`/`cadence`/`speed` fields
(3/4/6); for GPX, a device-specific `<extensions>` block under each
`<trkpt>` — usually Garmin's `TrackPointExtension`, matched by local
element name only (`hr`/`cad`/`speed`) so it doesn't care which XML
namespace prefix a given file happens to declare.
FIT track are directly comparable), elapsed time since the first known
timestamp, elevation, and whatever speed/cadence/heart-rate extras
that point's format/file carried — `nil` fields simply don't render
their chart (or, for `elapsed_secs`, don't offer the axis toggle
below). For FIT, those extras are the `record` message's own
`heart_rate`/`cadence`/`speed` fields (3/4/6); for GPX, a
device-specific `<extensions>` block under each `<trkpt>` — usually
Garmin's `TrackPointExtension`, matched by local element name only
(`hr`/`cad`/`speed`) so it doesn't care which XML namespace prefix a
given file happens to declare.
+
Each chart is its own single-series `<svg>` (elevation/speed/cadence/
heart rate are on wildly different scales, so this is small multiples
@@ -288,6 +290,15 @@ three things at once: a synchronized crosshair line in every chart, a
single tooltip listing every active series' value at that point, and a
MapLibre `Marker` moved to that point's `lon`/`lat` on the map — so
hovering the chart shows where on the track that moment actually was.
Each chart's own min/max are shown as plain HTML overlays in its
top-left/bottom-left corners (not SVG `<text>` — the viewBox's
non-uniform scaling would stretch it). Below the stack, a single
shared x-axis strip (again HTML, same reason) shows 5 evenly-spaced
ticks along the shared distance scale; a Distance/Time toggle above it
(only shown when the track has any elapsed-time data at all) switches
what those 5 ticks are labeled with — the underlying point positions
stay distance-based either way, only the tick text changes, so
toggling is a cheap re-render of just that strip.
== Live GNSS position