diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-16 14:23:32 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-16 14:23:32 +0200 |
| commit | 53ab332e6d2afe9818914e0026310e4cadcc4202 (patch) | |
| tree | 198d708fa05d4247bdcc0cf2900fdf551d61b7d6 /web/static/ride-detail.js | |
| parent | 2d18d177f48285eb123e7da8680fc00e7a6fe19c (diff) | |
refactor(web): migrate browser code to TypeScript
Diffstat (limited to 'web/static/ride-detail.js')
| -rw-r--r-- | web/static/ride-detail.js | 142 |
1 files changed, 0 insertions, 142 deletions
diff --git a/web/static/ride-detail.js b/web/static/ride-detail.js deleted file mode 100644 index 67c87ae..0000000 --- a/web/static/ride-detail.js +++ /dev/null @@ -1,142 +0,0 @@ -import { OfficialClimbProfileController } from "./official-climb-profile.js"; -import { RideBoundaryController } from "./ride-detail-boundaries.js"; -import { RideProfileCanvas } from "./ride-detail-canvas.js"; -import { RideDetailMap } from "./ride-detail-map.js"; -import { formatDistance, formatElevation } from "./ride-detail-logic.js"; - -export const mountRideDetail = () => { - const mapElement = document.getElementById("ride-map"); - const routeElement = /** @type {HTMLScriptElement | null} */ (document.getElementById("ride-route")); - const profileElement = /** @type {HTMLScriptElement | null} */ (document.getElementById("ride-profile")); - const canvas = /** @type {HTMLCanvasElement | null} */ (document.getElementById("ride-profile-chart")); - /** @type {HTMLElement | null} */ - const hoverOutput = document.getElementById("ride-profile-hover"); - if (!mapElement || !routeElement || !profileElement || !canvas || !hoverOutput) return; - const leaflet = window.L; - if (!leaflet) return; - - const colorProbe = document.createElement("span"); - colorProbe.hidden = true; - document.body.append(colorProbe); - const resolveColor = (name) => { - colorProbe.style.color = `var(${name})`; - return getComputedStyle(colorProbe).color; - }; - const colors = { - accent: resolveColor("--color-accent"), - forest: resolveColor("--color-forest"), - subtle: resolveColor("--color-subtle"), - plotSurface: resolveColor("--color-plot-surface"), - plotSurfaceOverlay: resolveColor("--color-plot-surface-overlay"), - grid: resolveColor("--color-plot-grid"), - accentFill: resolveColor("--color-accent-fill"), - climbLabel: resolveColor("--color-climb-label"), - crossing: resolveColor("--color-crossing"), - crossingLabel: resolveColor("--color-crossing-label"), - hoverLine: resolveColor("--color-hover-line"), - climbRoute: resolveColor("--color-climb-route"), - climbFocusFill: resolveColor("--color-climb-focus-fill"), - }; - colorProbe.remove(); - - const route = JSON.parse(routeElement.textContent); - const profile = JSON.parse(profileElement.textContent); - const points = profile.points || []; - if (points.length === 0) return; - - const climbItems = [...document.querySelectorAll("[data-climb-item]")].map((item) => /** @type {HTMLElement} */ (item)); - const climbItemIndices = climbItems.map((item) => Number.parseInt(item.dataset.climbIndex, 10)); - /** @type {HTMLButtonElement | null} */ - const previousClimbButton = document.querySelector("[data-climb-previous]"); - /** @type {HTMLButtonElement | null} */ - const nextClimbButton = document.querySelector("[data-climb-next]"); - /** @type {HTMLElement | null} */ - const climbPosition = document.querySelector("[data-climb-position]"); - const climbBounds = (profile.climbs || []).map((climb) => ({ startIndex: climb.startIndex, endIndex: climb.endIndex })); - const state = { - focusedClimbItemIndex: 0, - focusedClimbIndex: climbItemIndices[0] ?? 0, - }; - - const mapController = new RideDetailMap({ - leaflet, - element: mapElement, - route, - points, - climbs: climbBounds, - colors, - }); - const officialProfileController = new OfficialClimbProfileController(points); - let boundaryController; - const profileCanvas = new RideProfileCanvas({ - canvas, - points, - profile, - colors, - getClimbBounds: () => climbBounds, - canSelectPoint: (source) => boundaryController?.isSelecting(source) ?? false, - onPointSelected: (index) => boundaryController?.choosePoint(index), - onPointHover: (index) => { - if (index < 0) { - mapController.clearPoint(); - hoverOutput.textContent = "Hover or focus the profile to inspect elevation."; - return; - } - const point = points[index]; - mapController.showPoint(index); - hoverOutput.textContent = `${formatDistance(point.distanceKm)} ยท ${formatElevation(point.elevationM)}`; - }, - }); - - const updateClimbLayer = (index) => { - mapController.updateClimbLayer(index, climbBounds[index], index === state.focusedClimbIndex); - }; - boundaryController = new RideBoundaryController({ - forms: [...document.querySelectorAll("[data-official-climb-form]")].map((form) => /** @type {HTMLFormElement} */ (form)), - points, - climbBounds, - onBoundaryChanged: (index) => { - updateClimbLayer(index); - profileCanvas.redraw(); - }, - onPointSelected: (index) => profileCanvas.showPoint(index), - setMessage: (message) => { - hoverOutput.textContent = message; - }, - }); - - mapController.onClick((event) => { - if (!boundaryController.isSelecting("map")) return; - boundaryController.choosePoint(mapController.nearestPointIndex(event.latlng.lat, event.latlng.lng)); - }); - - const updateClimbFocus = (index, zoom) => { - if (climbItems.length === 0) return; - state.focusedClimbItemIndex = Math.max(0, Math.min(climbItems.length - 1, index)); - state.focusedClimbIndex = climbItemIndices[state.focusedClimbItemIndex]; - for (let itemIndex = 0; itemIndex < climbItems.length; itemIndex++) { - const active = itemIndex === state.focusedClimbItemIndex; - climbItems[itemIndex].hidden = !active; - climbItems[itemIndex].setAttribute("aria-hidden", String(!active)); - climbItems[itemIndex].classList.toggle("focused", active); - updateClimbLayer(climbItemIndices[itemIndex]); - } - if (climbPosition) climbPosition.textContent = `Climb ${state.focusedClimbItemIndex + 1} of ${climbItems.length}`; - if (previousClimbButton) previousClimbButton.disabled = state.focusedClimbItemIndex === 0; - if (nextClimbButton) nextClimbButton.disabled = state.focusedClimbItemIndex === climbItems.length - 1; - boundaryController.clearSelection(); - profileCanvas.setFocusedClimbIndex(state.focusedClimbIndex); - if (zoom) mapController.zoomToClimb(climbBounds[state.focusedClimbIndex]); - }; - - if (previousClimbButton) previousClimbButton.addEventListener("click", () => updateClimbFocus(state.focusedClimbItemIndex - 1, true)); - if (nextClimbButton) nextClimbButton.addEventListener("click", () => updateClimbFocus(state.focusedClimbItemIndex + 1, true)); - window.addEventListener("resize", () => { - profileCanvas.redraw(); - officialProfileController.redrawOpen(); - }); - if (climbItems.length > 0) updateClimbFocus(0, false); - else profileCanvas.redraw(); -}; - -mountRideDetail(); |