summaryrefslogtreecommitdiff
path: root/web/frontend/ride-detail-map.ts
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-08-17 13:05:50 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-08-17 13:05:50 +0200
commitb626f15b6e40311143cdec91728046dc79e0d328 (patch)
tree9c7ff4f9a879785d5a63b3410e0aa02be1a5219d /web/frontend/ride-detail-map.ts
parent151853c458348a4afccd7677deba6366ee4181eb (diff)
feat(web): display nearby passes on ride maps
Diffstat (limited to 'web/frontend/ride-detail-map.ts')
-rw-r--r--web/frontend/ride-detail-map.ts18
1 files changed, 16 insertions, 2 deletions
diff --git a/web/frontend/ride-detail-map.ts b/web/frontend/ride-detail-map.ts
index dcc2b60..81367f3 100644
--- a/web/frontend/ride-detail-map.ts
+++ b/web/frontend/ride-detail-map.ts
@@ -1,5 +1,5 @@
import { clamp } from "./ride-detail-logic.js";
-import type { ClimbBounds, RideMapColors, RideProfilePoint, RideRoute } from "./types.js";
+import type { ClimbBounds, RideMapColors, RideMapPass, RideProfilePoint, RideRoute } from "./types.js";
import type { CircleMarker, LeafletMouseEvent, Map as LeafletMap, Polyline } from "leaflet";
type LeafletApi = typeof import("leaflet");
@@ -10,6 +10,7 @@ interface RideDetailMapOptions {
route: RideRoute;
points: RideProfilePoint[];
climbs: ClimbBounds[];
+ passes: RideMapPass[];
colors: RideMapColors;
}
@@ -21,7 +22,7 @@ export class RideDetailMap {
private readonly climbLayers: (Polyline | null)[];
private readonly routeCursor: CircleMarker;
- constructor({ leaflet, element, route, points, climbs, colors }: RideDetailMapOptions) {
+ constructor({ leaflet, element, route, points, climbs, passes, colors }: RideDetailMapOptions) {
this.leaflet = leaflet;
this.points = points;
this.colors = colors;
@@ -37,6 +38,19 @@ export class RideDetailMap {
})
.addTo(this.map);
const bounds = routeLayer.getBounds();
+ const passIcon = leaflet.divIcon({
+ className: "ride-map-pass-icon",
+ html: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 19 10.5 6l3.25 5.5L16 8l5 11H3Z" fill="currentColor"/></svg>',
+ iconSize: [28, 28],
+ iconAnchor: [14, 14],
+ });
+ for (const pass of passes) {
+ const marker = leaflet.marker([pass.latitude, pass.longitude], { icon: passIcon, alt: pass.name || "Mountain pass" }).addTo(this.map);
+ const tooltip = document.createElement("span");
+ tooltip.textContent = `${pass.name || "Mountain pass"} | ${Math.round(pass.elevationM)} m`;
+ marker.bindTooltip(tooltip);
+ bounds.extend(marker.getLatLng());
+ }
if (bounds.isValid()) this.map.fitBounds(bounds, { padding: [24, 24], maxZoom: 15 });
this.climbLayers = climbs.map((climb) => this.createClimbLayer(climb));
this.routeCursor = leaflet