Give each map leg its own colour
Legs cycle through the shared 8-hue palette by index: polylines (air stays dashed), km-label accents, and the Legs-list number badges all match, so multiple car routes are distinguishable. Badges use dark text after a contrast check ruled out white on these hues.
This commit is contained in:
@@ -283,7 +283,7 @@ textarea.input { resize: vertical; }
|
||||
|
||||
.map-pin-wrap { background: none; border: none; }
|
||||
.map-pin { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; color: #fff; font-weight: 700; font-size: 0.8rem; box-shadow: 0 2px 6px rgba(0,0,0,0.35); border: 2px solid #fff; }
|
||||
.km-label { background: rgba(37, 99, 235, 0.92); color: #fff; font-size: 0.7rem; font-weight: 700; padding: 0.1rem 0.4rem; border-radius: 999px; white-space: nowrap; box-shadow: 0 1px 3px rgba(0,0,0,0.3); }
|
||||
.km-label { background: rgba(37, 99, 235, 0.92); color: #fff; font-size: 0.7rem; font-weight: 700; padding: 0.1rem 0.4rem 0.1rem 0.55rem; border-radius: 999px; white-space: nowrap; box-shadow: 0 1px 3px rgba(0,0,0,0.3); border-left: 4px solid var(--leg-accent, transparent); }
|
||||
.map-popup strong { font-size: 0.95rem; }
|
||||
.map-popup-sub { color: #64748b; font-size: 0.8rem; margin-top: 0.15rem; }
|
||||
.map-popup-loc { font-size: 0.82rem; margin-top: 0.15rem; }
|
||||
|
||||
+28
-13
@@ -4,6 +4,14 @@
|
||||
import { el } from '../dom.js';
|
||||
import { typeInfo, entryIcon } from '../format.js';
|
||||
import { api } from '../api.js';
|
||||
import { STAY_PALETTE } from './stayBands.js';
|
||||
|
||||
// Each route leg gets its own colour from the same palette used for stay
|
||||
// bands/area dots, so several ground legs (e.g. multiple car routes) read
|
||||
// apart instead of blending into one generic "ground" colour.
|
||||
function legColor(i) {
|
||||
return STAY_PALETTE[((i % STAY_PALETTE.length) + STAY_PALETTE.length) % STAY_PALETTE.length];
|
||||
}
|
||||
|
||||
export function renderMap(tctx) {
|
||||
const route = tctx.route || { stops: [], legs: [], totalKm: 0 };
|
||||
@@ -91,20 +99,22 @@ function initMap(mapDiv, stops, legs, kmEls) {
|
||||
.bindPopup(popupHtml(stop, info, entryIcon(stop)));
|
||||
});
|
||||
|
||||
// One polyline per measured leg, styled by mode (air = dashed blue, ground =
|
||||
// solid teal), each with a km label at its midpoint (straight great-circle
|
||||
// line to start — the map is never empty while road geometry loads).
|
||||
const legLayers = legs.map(({ leg, a, b }) => {
|
||||
// One polyline per measured leg, each in its own colour from the shared
|
||||
// palette (air legs keep the dashed pattern), each with a km label at its
|
||||
// midpoint (straight great-circle line to start — the map is never empty
|
||||
// while road geometry loads).
|
||||
const legLayers = legs.map(({ leg, a, b }, i) => {
|
||||
const air = leg.mode === 'air';
|
||||
const color = legColor(i);
|
||||
const line = L.polyline([[a.lat, a.lng], [b.lat, b.lng]], {
|
||||
color: air ? '#2563eb' : '#0f766e',
|
||||
color,
|
||||
weight: 3,
|
||||
opacity: 0.75,
|
||||
dashArray: air ? '6 6' : null,
|
||||
}).addTo(map);
|
||||
const mid = [(a.lat + b.lat) / 2, (a.lng + b.lng) / 2];
|
||||
const label = L.marker(mid, { icon: kmLabel(L, leg.km), interactive: false }).addTo(map);
|
||||
return { leg, a, b, line, label };
|
||||
const label = L.marker(mid, { icon: kmLabel(L, leg.km, false, color), interactive: false }).addTo(map);
|
||||
return { leg, a, b, line, label, color };
|
||||
});
|
||||
|
||||
if (points.length === 1) {
|
||||
@@ -122,17 +132,18 @@ function initMap(mapDiv, stops, legs, kmEls) {
|
||||
// already drawn, so a slow/failed fetch just leaves those in place — no
|
||||
// error UI. Each leg fetches (and fails) independently.
|
||||
function fetchRoadGeometry(L, map, mapDiv, legLayers, kmEls) {
|
||||
legLayers.forEach(({ leg, a, b, line, label }, i) => {
|
||||
legLayers.forEach(({ leg, a, b, line, label, color }, i) => {
|
||||
if (leg.mode !== 'ground') return;
|
||||
api.directions({ lat: a.lat, lng: a.lng }, { lat: b.lat, lng: b.lng })
|
||||
.then((res) => {
|
||||
// The trip view may have been re-rendered (refreshTrip) while this
|
||||
// was in flight — the old map/section is detached from the DOM and
|
||||
// its layers must not be touched.
|
||||
// its layers must not be touched. Only latlngs/label are swapped —
|
||||
// the polyline keeps its per-leg colour/style from creation.
|
||||
if (!mapDiv.isConnected || !map.hasLayer(line) || !map.hasLayer(label)) return;
|
||||
line.setLatLngs(res.geometry);
|
||||
label.setLatLng(pathMidpoint(res.geometry) || label.getLatLng());
|
||||
label.setIcon(kmLabel(L, res.km, true));
|
||||
label.setIcon(kmLabel(L, res.km, true, color));
|
||||
const kmEl = kmEls[i];
|
||||
if (kmEl) kmEl.textContent = `${fmtKm(res.km)} km · road`;
|
||||
})
|
||||
@@ -166,10 +177,11 @@ function numberedIcon(L, n, color) {
|
||||
});
|
||||
}
|
||||
|
||||
function kmLabel(L, km, road) {
|
||||
function kmLabel(L, km, road, color) {
|
||||
const accent = color ? ` style="--leg-accent:${color}"` : '';
|
||||
return L.divIcon({
|
||||
className: 'km-label-wrap',
|
||||
html: `<span class="km-label">${fmtKm(km)} km${road ? ' · road' : ''}</span>`,
|
||||
html: `<span class="km-label"${accent}>${fmtKm(km)} km${road ? ' · road' : ''}</span>`,
|
||||
iconSize: [0, 0],
|
||||
});
|
||||
}
|
||||
@@ -217,7 +229,10 @@ function legList(legs) {
|
||||
el(
|
||||
'div',
|
||||
{ class: 'leg-row' },
|
||||
el('span', { class: 'leg-index' }, String(i + 1)),
|
||||
// Dark text, not white: the palette's mid-tone hues (amber, lime, …)
|
||||
// don't clear AA contrast with white at full strength — the same
|
||||
// reason stay bands use dark text on these colours (see stayBands.js).
|
||||
el('span', { class: 'leg-index', style: { background: legColor(i), color: '#334155' } }, String(i + 1)),
|
||||
el('span', { class: 'leg-mode', title: air ? 'Flight' : 'Ground' }, air ? '✈️' : '🚗'),
|
||||
el('span', { class: 'leg-path' }, stopLabel(a), ' → ', stopLabel(b)),
|
||||
kmEl,
|
||||
|
||||
Reference in New Issue
Block a user