// profile.js — elevation profile chart model (pure): samples {d_km, z_m, water} → SVG path data + scales const PAD = { l: 40, r: 6, t: 8, b: 18 }; export function profileModel(samples, w, h) { const L = samples.at(-1).d_km || 1; const zs = samples.map(s => s.z_m); const lo = Math.min(0, ...zs); const hi = Math.max(lo + 100, 0, ...zs); const X = d => PAD.l + (d / L) * (w - PAD.l - PAD.r); const Y = z => PAD.t + (1 - (z - lo) / (hi - lo)) * (h - PAD.t - PAD.b); const line = samples.map((s, i) => `${i ? 'L' : 'M'}${X(s.d_km).toFixed(1)},${Y(s.z_m).toFixed(1)}`).join(''); const area = `${line}L${X(L).toFixed(1)},${Y(lo).toFixed(1)}L${X(0).toFixed(1)},${Y(lo).toFixed(1)}Z`; const half = L / Math.max(1, samples.length - 1) / 2; const water = []; let start = null; samples.forEach((s, i) => { if (s.water && start === null) start = i; const last = i === samples.length - 1; if (start !== null && (!s.water || last)) { const end = s.water ? i : i - 1; water.push([X(Math.max(0, samples[start].d_km - half)), X(Math.min(L, samples[end].d_km + half))]); start = null; } }); const xAt = px => ((px - PAD.l) / (w - PAD.l - PAD.r)) * L; return { line, area, water, seaY: Y(0), lo, hi, L, X, Y, xAt }; } export function sampleAt(samples, d) { let a = 0, b = samples.length - 1; while (b - a > 1) { const m = (a + b) >> 1; if (samples[m].d_km <= d) a = m; else b = m; } return Math.abs(samples[a].d_km - d) <= Math.abs(samples[b].d_km - d) ? a : b; }