{/* The basemap is a vector style by default and a raster template when the
user brought their own, so the two are drawn by different things. The
satellite toggle is always raster.
key remounts the raster layer on switch, else attribution/maxZoom stick
at mount-time values. */}
{isSatellite ? (
) : basemap.kind === 'vector' ? (
) : (
)}
0 ? dayPlaces : places} routeCoords={dayPlaces.length > 0 ? routeCoords : []} fitKey={fitKey} paddingOpts={paddingOpts} framedOnMount={initialView.framed} focusPoints={focusPoints} fitPadding={fitPadding} />
{markers}
{/* Apple-Maps style: darker-blue casing under a bright-blue core, rounded.
The casing carries the click when the route can be reshaped: it is the wider of
the two, so it is the one a pointer actually lands on. */}
{route && route.length > 0 && route.flatMap((seg, i) => seg.length > 1 ? [
{
// Stops the map's own click, which would otherwise open the add-place menu
// underneath the new via.
e.originalEvent.stopPropagation()
onRouteClick(e.latlng.lat, e.latlng.lng)
},
} : undefined}
/>,
,
] : [])}
{/* The last bit to a place the road does not reach.
Dashed and thin, over the route rather than under it, because it is the one
piece of the line that is not driving: the router snapped the stop to the
nearest road and the drive really ends there. Same blue as the route, so it
reads as the end of that route and not as a second one. */}
{(accessLines ?? []).map((spur, i) => (
))}
{/* The offered ways of driving one leg, over the route they replace. Clicking one
takes it, which is the same choice the bar above the map offers. */}
{/* Every option in blue over a white casing, after Apple Maps: they are all real
roads, so the difference is emphasis, not category. Grey was the first attempt
and it disappeared on Positron, which is almost entirely greys. */}
{(alternativeRoutes ?? []).flatMap((alt: AlternativeOverlay) => {
const active = activeAlternative === alt.index
return [
,
{ e.originalEvent.stopPropagation(); onChooseAlternative(alt.index) },
mouseover: () => onHighlightAlternative?.(alt.index),
mouseout: () => onHighlightAlternative?.(null),
} : undefined}
/>,
// The drive time on the road itself, the way Apple labels them.
onChooseAlternative(alt.index),
mouseover: () => onHighlightAlternative?.(alt.index),
mouseout: () => onHighlightAlternative?.(null),
} : undefined}
/>,
]
})}
{/* The handles that shape the drive. After the route so they sit on top of it. */}
{roadtripVias ? (
) : null}
{/* GPX imported route geometries */}
{gpxPolylines}
{hazards?.length > 0 && }
{/* The route as it was actually recorded (#2279). Drawn in the casing
pane's sibling order so it sits under the planned route rather than
over it — the plan is what the user is editing. */}
{poiMarkers}
{/* Charging stops / rest areas a plugin route places on the drawn day route.
Host-vetted data (server-normalized), rendered as plain tone dots. */}
{(routeVias as RouteVia[]).filter(v => !v.nightPause || mapZoom >= NIGHT_PAUSE_MIN_ZOOM).map((v, i) => (
handleMarkerHover({ name: v.label, routeVia: v }, e.originalEvent.clientX, e.originalEvent.clientY),
mousemove: e => handleMarkerHover({ name: v.label, routeVia: v }, e.originalEvent.clientX, e.originalEvent.clientY),
mouseout: handleMarkerHoverOut,
} : undefined}
>
{(!v.hoverCard || isTouchDevice) && (v.label || v.dwellSeconds != null) && (
{v.label}
{v.label && v.dwellSeconds != null ? ' · ' : ''}
{v.dwellSeconds != null ? formatViaDwell(v.dwellSeconds) : ''}
)}
))}
{isMobile &&
}
{/* 20px off the sidebar, not 12: the pill is round and frosted, so at the
smaller gap its shadow ran into the sidebar edge and the two read as one
surface. */}
{/* Bottom left, whatever else is on screen. Opening a place used to send it to the
top of the map, which read as the control moving house rather than as room being
made: the inspector is a centred card at most 800 wide, so the corner it would
have been clearing is one the card never reaches. */}
{TooltipOverlay && hoveredPlace.routeVia?.nightPause && (