Highlight map stops from result list

This commit is contained in:
Edward Betts 2026-08-15 12:35:09 +01:00
parent 7da704d837
commit aeb429768b
3 changed files with 37 additions and 0 deletions

View file

@ -13,6 +13,7 @@ let selectedStop = null;
let markers = L.featureGroup().addTo(map);
let searchMarker = null;
let selectedMarkerHalo = null;
let hoveredMarkerHalo = null;
let userMapInteractionPending = false;
let mapMoveTimer = null;
let mapRequestController = null;
@ -132,6 +133,7 @@ function restoreSearchFromUrl() {
markers.clearLayers();
if (searchMarker) { searchMarker.remove(); searchMarker = null; }
if (selectedMarkerHalo) { selectedMarkerHalo.remove(); selectedMarkerHalo = null; }
if (hoveredMarkerHalo) { hoveredMarkerHalo.remove(); hoveredMarkerHalo = null; }
selectedStop = null;
show('results-panel', false);
show('stop-detail', false);
@ -249,6 +251,7 @@ function renderStops(data, fitMap = true, sortOrigin = null, preserveSelection =
}
if (fitMap) show('map-status', false);
markers.clearLayers();
if (hoveredMarkerHalo) { hoveredMarkerHalo.remove(); hoveredMarkerHalo = null; }
if (!preserveSelection) {
show('stop-detail', false);
show('results-panel');
@ -281,6 +284,10 @@ function renderStops(data, fitMap = true, sortOrigin = null, preserveSelection =
.filter(Boolean).join(' · ');
button.append(title, meta);
button.addEventListener('click', () => selectStop(stop));
button.addEventListener('mouseenter', () => highlightHoveredStop(stop));
button.addEventListener('mouseleave', clearHoveredStop);
button.addEventListener('focus', () => highlightHoveredStop(stop));
button.addEventListener('blur', clearHoveredStop);
list.appendChild(button);
const tooltipParts = [stop.name, bearingLabel(stop), stop.transport_type || 'Transport stop'];
@ -316,6 +323,7 @@ function renderGeocodeChoices(data) {
}
selectedStop = null;
markers.clearLayers();
clearHoveredStop();
if (searchMarker) { searchMarker.remove(); searchMarker = null; }
if (selectedMarkerHalo) { selectedMarkerHalo.remove(); selectedMarkerHalo = null; }
show('stop-detail', false);
@ -379,6 +387,29 @@ function highlightSelectedStop(stop) {
selectedMarkerHalo.bringToFront();
}
/** Temporarily identify the map marker corresponding to a list item. */
function highlightHoveredStop(stop) {
clearHoveredStop();
hoveredMarkerHalo = L.circleMarker([stop.lat, stop.lon], {
radius: 12,
color: '#0dcaf0',
fillColor: '#0dcaf0',
fillOpacity: 0.16,
weight: 4,
opacity: 1,
interactive: false,
className: 'hovered-stop-marker',
}).addTo(map);
hoveredMarkerHalo.bringToFront();
}
/** Remove the temporary list-hover map highlight. */
function clearHoveredStop() {
if (!hoveredMarkerHalo) return;
hoveredMarkerHalo.remove();
hoveredMarkerHalo = null;
}
function osmUrl(stop, edit = false) {
return `https://www.openstreetmap.org/${edit ? 'edit?' : ''}${edit ? `${stop.type}=${stop.id}` : `${stop.type}/${stop.id}`}`;
}
@ -397,6 +428,7 @@ function renderTags(tags) {
async function selectStop(stop, updateUrl = true) {
selectedStop = stop;
clearHoveredStop();
highlightSelectedStop(stop);
userMapInteractionPending = false;
clearTimeout(mapMoveTimer);
@ -508,6 +540,7 @@ async function loadUrl(url) {
async function loadVisibleMapStops() {
if (map.getZoom() < MIN_MAP_STOP_ZOOM) {
markers.clearLayers();
clearHoveredStop();
byId('map-status').textContent = 'Zoom in to load transport stops';
show('map-status');
return;

View file

@ -22,6 +22,7 @@ body { color: #1c2333; }
.tag-list dt { font-family: monospace; color: #495057; }
.leaflet-container { font-family: inherit; }
.selected-stop-marker { animation: selected-stop-pulse 1.5s ease-in-out infinite; }
.hovered-stop-marker { filter: drop-shadow(0 0 3px rgba(13, 202, 240, .9)); }
@keyframes selected-stop-pulse {
0%, 100% { stroke-opacity: 1; fill-opacity: .25; stroke-width: 5; }
50% { stroke-opacity: .55; fill-opacity: .08; stroke-width: 8; }