Task group 2 (part a) of elevation-profile-hardening — wire the group-1
primitives into the headline stat and the chart.
- computeElevation (parse.ts): despike each segment's elevation sequence,
then take filteredTotals; gain/loss are now noise-filtered (no more
20–50% inflation from per-point jitter), the profile is built from the
despiked data, and additive gainRaw/lossRaw expose the unfiltered sums.
- elevationSeries: despike per segment (no cross-trkseg interpolation)
before downsampling, so the chart and the headline totals derive from
the same cleaned data.
- types.ts: GpxData.elevation gains gainRaw/lossRaw (additive).
Well-formed monotonic climbs are unchanged (steps exceed the 5 m
threshold → filtered == raw); a shared noisy-track test proves jitter is
filtered and a 300 m single-point spike is interpolated out of both the
totals and the chart.
Verified: gpx 111/111; full pnpm typecheck 13/13, lint 13/13, test 11/11
(journal + planner compile with the additive fields).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements the journal-elevation-profile change (specs/journal-elevation-profile):
- gpx: `elevationSeries(tracks)` → { d, e, lat, lng }[] with cumulative distance,
downsampled (keeps first/last), empty when <2 points carry elevation.
- ElevationProfile: read-only SVG area chart (vertical gradient fill), highest/
lowest summary + a hover readout. Reports hovered index (onActive) and clicked
index (onSeek); draws a marker at the active index. Renders nothing for an
empty series.
- RouteMapThumbnail: ActiveMarker (CircleMarker at the chart's active point),
HoverTracker (route hover → nearest sample → onHoverIndex), Recenter (panTo on
chart click). Props forwarded through ClientMap.
- Wired into the activity + route detail pages via a shared activeIndex/centerOn
state; loaders expose the series (activity reuses the moving-time parse).
- i18n journal.elevation.{highest,lowest} in en + de.
Ascent/descent stay in the stat row (#532); the chart summary shows highest/
lowest to avoid duplication.
Tests: elevationSeries unit; ElevationProfile component (jsdom); e2e creates an
activity from an elevation GPX and asserts the chart renders. typecheck + lint +
unit (gpx 67, journal 315) green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>