Color elevation chart by surface type when in surface mode

The chart was falling through to plain blue when surface mode was
selected. Now reads surface data from Yjs routeData and draws
segments colored by road surface type, matching the route colors
on the map.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-04-11 03:18:36 +02:00
parent 858c7e9118
commit 7bddc131cd
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9

View file

@ -2,7 +2,7 @@ import { useEffect, useState, useRef, useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { DayStage } from "@trails-cool/gpx"; import type { DayStage } from "@trails-cool/gpx";
import type { YjsState } from "~/lib/use-yjs"; import type { YjsState } from "~/lib/use-yjs";
import { elevationColor, type ColorMode } from "~/components/ColoredRoute"; import { elevationColor, SURFACE_COLORS, DEFAULT_SURFACE_COLOR, type ColorMode } from "~/components/ColoredRoute";
function gradeColor(grade: number): string { function gradeColor(grade: number): string {
const absGrade = Math.abs(grade); const absGrade = Math.abs(grade);
@ -74,6 +74,7 @@ export function ElevationChart({ yjs, onHover, days }: ElevationChartProps) {
const [points, setPoints] = useState<ElevationPoint[]>([]); const [points, setPoints] = useState<ElevationPoint[]>([]);
const [hoverIdx, setHoverIdx] = useState<number | null>(null); const [hoverIdx, setHoverIdx] = useState<number | null>(null);
const [colorMode, setColorMode] = useState<ColorMode>("plain"); const [colorMode, setColorMode] = useState<ColorMode>("plain");
const [surfaces, setSurfaces] = useState<string[]>([]);
const canvasRef = useRef<HTMLCanvasElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null);
const pointsRef = useRef<ElevationPoint[]>([]); const pointsRef = useRef<ElevationPoint[]>([]);
pointsRef.current = points; pointsRef.current = points;
@ -88,6 +89,12 @@ export function ElevationChart({ yjs, onHover, days }: ElevationChartProps) {
} }
const mode = yjs.routeData.get("colorMode") as ColorMode | undefined; const mode = yjs.routeData.get("colorMode") as ColorMode | undefined;
setColorMode(mode ?? "plain"); setColorMode(mode ?? "plain");
const surfacesJson = yjs.routeData.get("surfaces") as string | undefined;
if (surfacesJson) {
try { setSurfaces(JSON.parse(surfacesJson)); } catch { setSurfaces([]); }
} else {
setSurfaces([]);
}
}; };
yjs.routeData.observe(update); yjs.routeData.observe(update);
update(); update();
@ -172,6 +179,30 @@ export function ElevationChart({ yjs, onHover, days }: ElevationChartProps) {
ctx.fill(); ctx.fill();
// Line segment // Line segment
ctx.beginPath();
ctx.moveTo(toX(p0.distance), toY(p0.elevation));
ctx.lineTo(toX(p1.distance), toY(p1.elevation));
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.stroke();
}
} else if (colorMode === "surface" && surfaces.length >= points.length) {
// Surface-colored segments
for (let i = 0; i < points.length - 1; i++) {
const p0 = points[i]!;
const p1 = points[i + 1]!;
const surface = surfaces[i] ?? "unknown";
const color = SURFACE_COLORS[surface] ?? DEFAULT_SURFACE_COLOR;
ctx.beginPath();
ctx.moveTo(toX(p0.distance), PADDING.top + chartH);
ctx.lineTo(toX(p0.distance), toY(p0.elevation));
ctx.lineTo(toX(p1.distance), toY(p1.elevation));
ctx.lineTo(toX(p1.distance), PADDING.top + chartH);
ctx.closePath();
ctx.fillStyle = color + "40";
ctx.fill();
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(toX(p0.distance), toY(p0.elevation)); ctx.moveTo(toX(p0.distance), toY(p0.elevation));
ctx.lineTo(toX(p1.distance), toY(p1.elevation)); ctx.lineTo(toX(p1.distance), toY(p1.elevation));
@ -276,7 +307,7 @@ export function ElevationChart({ yjs, onHover, days }: ElevationChartProps) {
ctx.fillText(label, labelX, PADDING.top + 10); ctx.fillText(label, labelX, PADDING.top + 10);
} }
}, },
[points, colorMode, days, t], [points, colorMode, surfaces, days, t],
); );
useEffect(() => { useEffect(() => {