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

+1 -1
View File
@@ -67,7 +67,7 @@ module Maptool
"geometry" => { "type" => "MultiLineString", "coordinates" => [coordinates] },
"properties" => { "kind" => "track", "name" => nil, "activity_type" => result.activity_type }
.merge(TrackStats.compute(coordinates, times: result.records.map { |r| r[:time] }))
.merge("profile" => TrackStats.build_profile(coordinates, extras: extras)),
.merge("profile" => TrackStats.build_profile(coordinates, times: result.records.map { |r| r[:time] }, extras: extras)),
}
end
private_class_method :track_feature
+1 -1
View File
@@ -72,7 +72,7 @@ module Maptool
"geometry" => { "type" => "MultiLineString", "coordinates" => lines },
"properties" => { "kind" => "track", "name" => child_text(trk, "name"), "activity_type" => child_text(trk, "type") }
.merge(TrackStats.compute(all_points, times: times))
.merge("profile" => TrackStats.build_profile(all_points, extras: extras)),
.merge("profile" => TrackStats.build_profile(all_points, times: times, extras: extras)),
}
end
private_class_method :track_feature
+8 -3
View File
@@ -30,10 +30,13 @@ module Maptool
# One entry per coordinate, for the profile chart: cumulative distance
# (computed the same way for every format, rather than trusting a
# device's own odometer field — keeps a GPX and a FIT file directly
# comparable), elevation, and whatever per-point extras (speed/cadence/
# heart rate) the caller has, nil where a format/file doesn't carry it.
# comparable), elapsed time since the first known timestamp, elevation,
# and whatever per-point extras (speed/cadence/heart rate) the caller
# has — nil wherever a format/file doesn't carry it.
# `extras`: array of hashes parallel to `coordinates`, or shorter/empty.
def self.build_profile(coordinates, extras: [])
# `times`: array of Time (or nil) parallel to `coordinates`, or [].
def self.build_profile(coordinates, times: [], extras: [])
start_time = times.compact.first
distance = 0.0
previous = nil
@@ -41,9 +44,11 @@ module Maptool
distance += haversine(previous[1], previous[0], lat, lon) if previous
previous = [lon, lat]
extra = extras[i] || {}
point_time = times[i]
{
"distance_meters" => distance.round(1),
"elapsed_secs" => point_time && start_time ? (point_time - start_time).to_i : nil,
"elevation_meters" => ele,
"speed_mps" => extra[:speed_mps],
"cadence_rpm" => extra[:cadence_rpm],