Fix marker z-ordering: waypoints and highlight above POIs and route

Extract all Leaflet zIndexOffset values into z-index.ts constants:
  POI markers (-1000) < cursors (-1000) < ghost waypoint (-100)
  < waypoint markers (1000) < highlight dot (2000)

Replaced CircleMarker highlight with a Marker+DivIcon so it
participates in z-index ordering above waypoint markers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-04-11 01:46:55 +02:00
parent f310e0f66f
commit 337df6b527
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
4 changed files with 29 additions and 8 deletions

View file

@ -1,5 +1,5 @@
import { useEffect, useState, useCallback, useRef } from "react";
import { MapContainer, TileLayer, LayersControl, Marker, CircleMarker, useMapEvents, useMap } from "react-leaflet";
import { MapContainer, TileLayer, LayersControl, Marker, useMapEvents, useMap } from "react-leaflet";
import L from "leaflet";
import * as Y from "yjs";
import { useTranslation } from "react-i18next";
@ -10,6 +10,7 @@ import { parseGpxAsync, extractWaypoints } from "@trails-cool/gpx";
import { isOvernight } from "~/lib/overnight";
import { setOvernight } from "~/lib/overnight";
import { usePois } from "~/lib/use-pois";
import { Z_CURSOR, Z_WAYPOINT, Z_HIGHLIGHT } from "~/lib/z-index";
import { NoGoAreaLayer } from "./NoGoAreaLayer";
import { ColoredRoute, findSegmentForPoint, type ColorMode } from "./ColoredRoute";
import { RouteInteraction } from "./RouteInteraction";
@ -175,7 +176,7 @@ function CursorTracker({ awareness }: { awareness: YjsState["awareness"] }) {
<Marker
key={clientId}
position={[cursor.lat, cursor.lng]}
zIndexOffset={-1000}
zIndexOffset={Z_CURSOR}
icon={L.divIcon({
className: "",
html: `<div style="position:relative;z-index:400;pointer-events:none">
@ -519,6 +520,7 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted
key={i}
position={[wp.lat, wp.lon]}
draggable
zIndexOffset={Z_WAYPOINT}
icon={waypointIcon(i, wp.overnight, highlightedWaypoint === i)}
eventHandlers={{
mouseover: () => {
@ -585,10 +587,15 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted
)}
{highlightPosition && (
<CircleMarker
center={highlightPosition}
radius={6}
pathOptions={{ color: "#ef4444", fillColor: "#ef4444", fillOpacity: 1, weight: 2 }}
<Marker
position={highlightPosition}
zIndexOffset={Z_HIGHLIGHT}
interactive={false}
icon={L.divIcon({
className: "",
html: '<div style="width:12px;height:12px;border-radius:50%;background:#ef4444;border:2px solid white;box-shadow:0 1px 3px rgba(0,0,0,0.3);transform:translate(-6px,-6px)"></div>',
iconSize: [0, 0],
})}
/>
)}
</MapContainer>

View file

@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { useMap } from "react-leaflet";
import { poiCategories } from "~/lib/poi-categories";
import type { PoiState } from "~/lib/use-pois";
import { Z_POI_MARKER } from "~/lib/z-index";
interface PoiPanelProps {
poiState: PoiState;
@ -111,7 +112,7 @@ export function PoiMarkers({ poiState }: PoiPanelProps) {
">${cat.icon}</div>`,
iconSize: [0, 0],
}),
zIndexOffset: -1000,
zIndexOffset: Z_POI_MARKER,
});
const popupLines = [`<strong>${poi.name ?? cat.icon + " " + poi.category}</strong>`];

View file

@ -1,6 +1,7 @@
import { useEffect, useRef, useCallback } from "react";
import { useMap } from "react-leaflet";
import L from "leaflet";
import { Z_GHOST_WAYPOINT } from "~/lib/z-index";
interface RouteInteractionProps {
coordinates: [number, number, number][]; // [lon, lat, ele]
@ -89,7 +90,7 @@ export function RouteInteraction({
icon: ghostIcon,
draggable: true,
interactive: true,
zIndexOffset: -100,
zIndexOffset: Z_GHOST_WAYPOINT,
});
markerRef.current = marker;

View file

@ -0,0 +1,12 @@
/**
* Leaflet marker z-index offsets for consistent layering.
* Higher values render on top of lower values.
*
* Rendering order (bottom to top):
* POI markers cursor markers ghost waypoint waypoint markers highlight dot
*/
export const Z_POI_MARKER = -1000;
export const Z_CURSOR = -1000;
export const Z_GHOST_WAYPOINT = -100;
export const Z_WAYPOINT = 1000;
export const Z_HIGHLIGHT = 2000;