Highlight map stops from result list
This commit is contained in:
parent
7da704d837
commit
aeb429768b
3 changed files with 37 additions and 0 deletions
|
|
@ -13,6 +13,7 @@ let selectedStop = null;
|
||||||
let markers = L.featureGroup().addTo(map);
|
let markers = L.featureGroup().addTo(map);
|
||||||
let searchMarker = null;
|
let searchMarker = null;
|
||||||
let selectedMarkerHalo = null;
|
let selectedMarkerHalo = null;
|
||||||
|
let hoveredMarkerHalo = null;
|
||||||
let userMapInteractionPending = false;
|
let userMapInteractionPending = false;
|
||||||
let mapMoveTimer = null;
|
let mapMoveTimer = null;
|
||||||
let mapRequestController = null;
|
let mapRequestController = null;
|
||||||
|
|
@ -132,6 +133,7 @@ function restoreSearchFromUrl() {
|
||||||
markers.clearLayers();
|
markers.clearLayers();
|
||||||
if (searchMarker) { searchMarker.remove(); searchMarker = null; }
|
if (searchMarker) { searchMarker.remove(); searchMarker = null; }
|
||||||
if (selectedMarkerHalo) { selectedMarkerHalo.remove(); selectedMarkerHalo = null; }
|
if (selectedMarkerHalo) { selectedMarkerHalo.remove(); selectedMarkerHalo = null; }
|
||||||
|
if (hoveredMarkerHalo) { hoveredMarkerHalo.remove(); hoveredMarkerHalo = null; }
|
||||||
selectedStop = null;
|
selectedStop = null;
|
||||||
show('results-panel', false);
|
show('results-panel', false);
|
||||||
show('stop-detail', false);
|
show('stop-detail', false);
|
||||||
|
|
@ -249,6 +251,7 @@ function renderStops(data, fitMap = true, sortOrigin = null, preserveSelection =
|
||||||
}
|
}
|
||||||
if (fitMap) show('map-status', false);
|
if (fitMap) show('map-status', false);
|
||||||
markers.clearLayers();
|
markers.clearLayers();
|
||||||
|
if (hoveredMarkerHalo) { hoveredMarkerHalo.remove(); hoveredMarkerHalo = null; }
|
||||||
if (!preserveSelection) {
|
if (!preserveSelection) {
|
||||||
show('stop-detail', false);
|
show('stop-detail', false);
|
||||||
show('results-panel');
|
show('results-panel');
|
||||||
|
|
@ -281,6 +284,10 @@ function renderStops(data, fitMap = true, sortOrigin = null, preserveSelection =
|
||||||
.filter(Boolean).join(' · ');
|
.filter(Boolean).join(' · ');
|
||||||
button.append(title, meta);
|
button.append(title, meta);
|
||||||
button.addEventListener('click', () => selectStop(stop));
|
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);
|
list.appendChild(button);
|
||||||
|
|
||||||
const tooltipParts = [stop.name, bearingLabel(stop), stop.transport_type || 'Transport stop'];
|
const tooltipParts = [stop.name, bearingLabel(stop), stop.transport_type || 'Transport stop'];
|
||||||
|
|
@ -316,6 +323,7 @@ function renderGeocodeChoices(data) {
|
||||||
}
|
}
|
||||||
selectedStop = null;
|
selectedStop = null;
|
||||||
markers.clearLayers();
|
markers.clearLayers();
|
||||||
|
clearHoveredStop();
|
||||||
if (searchMarker) { searchMarker.remove(); searchMarker = null; }
|
if (searchMarker) { searchMarker.remove(); searchMarker = null; }
|
||||||
if (selectedMarkerHalo) { selectedMarkerHalo.remove(); selectedMarkerHalo = null; }
|
if (selectedMarkerHalo) { selectedMarkerHalo.remove(); selectedMarkerHalo = null; }
|
||||||
show('stop-detail', false);
|
show('stop-detail', false);
|
||||||
|
|
@ -379,6 +387,29 @@ function highlightSelectedStop(stop) {
|
||||||
selectedMarkerHalo.bringToFront();
|
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) {
|
function osmUrl(stop, edit = false) {
|
||||||
return `https://www.openstreetmap.org/${edit ? 'edit?' : ''}${edit ? `${stop.type}=${stop.id}` : `${stop.type}/${stop.id}`}`;
|
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) {
|
async function selectStop(stop, updateUrl = true) {
|
||||||
selectedStop = stop;
|
selectedStop = stop;
|
||||||
|
clearHoveredStop();
|
||||||
highlightSelectedStop(stop);
|
highlightSelectedStop(stop);
|
||||||
userMapInteractionPending = false;
|
userMapInteractionPending = false;
|
||||||
clearTimeout(mapMoveTimer);
|
clearTimeout(mapMoveTimer);
|
||||||
|
|
@ -508,6 +540,7 @@ async function loadUrl(url) {
|
||||||
async function loadVisibleMapStops() {
|
async function loadVisibleMapStops() {
|
||||||
if (map.getZoom() < MIN_MAP_STOP_ZOOM) {
|
if (map.getZoom() < MIN_MAP_STOP_ZOOM) {
|
||||||
markers.clearLayers();
|
markers.clearLayers();
|
||||||
|
clearHoveredStop();
|
||||||
byId('map-status').textContent = 'Zoom in to load transport stops';
|
byId('map-status').textContent = 'Zoom in to load transport stops';
|
||||||
show('map-status');
|
show('map-status');
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ body { color: #1c2333; }
|
||||||
.tag-list dt { font-family: monospace; color: #495057; }
|
.tag-list dt { font-family: monospace; color: #495057; }
|
||||||
.leaflet-container { font-family: inherit; }
|
.leaflet-container { font-family: inherit; }
|
||||||
.selected-stop-marker { animation: selected-stop-pulse 1.5s ease-in-out infinite; }
|
.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 {
|
@keyframes selected-stop-pulse {
|
||||||
0%, 100% { stroke-opacity: 1; fill-opacity: .25; stroke-width: 5; }
|
0%, 100% { stroke-opacity: 1; fill-opacity: .25; stroke-width: 5; }
|
||||||
50% { stroke-opacity: .55; fill-opacity: .08; stroke-width: 8; }
|
50% { stroke-opacity: .55; fill-opacity: .08; stroke-width: 8; }
|
||||||
|
|
|
||||||
|
|
@ -95,11 +95,14 @@ def test_search_and_stop_details_in_browser(chromium_browser: Any, flask_url: st
|
||||||
assert page.locator("#stop-list .stop-title").all_inner_texts() == ["Central Stop", "Nearby Stop"]
|
assert page.locator("#stop-list .stop-title").all_inner_texts() == ["Central Stop", "Nearby Stop"]
|
||||||
playwright_api.expect(page.locator("#stop-list .stop-meta").first).to_contain_text("m · Bus stop")
|
playwright_api.expect(page.locator("#stop-list .stop-meta").first).to_contain_text("m · Bus stop")
|
||||||
playwright_api.expect(page.locator("#stop-list .stop-meta").first).to_contain_text("NW-bound")
|
playwright_api.expect(page.locator("#stop-list .stop-meta").first).to_contain_text("NW-bound")
|
||||||
|
page.get_by_text("Central Stop", exact=True).hover()
|
||||||
|
playwright_api.expect(page.locator(".hovered-stop-marker")).to_be_visible()
|
||||||
assert page.evaluate("map.getZoom()") > 6
|
assert page.evaluate("map.getZoom()") > 6
|
||||||
page.evaluate("markers.getLayers()[0].openTooltip()")
|
page.evaluate("markers.getLayers()[0].openTooltip()")
|
||||||
playwright_api.expect(page.get_by_text("Central Stop · NW-bound · Bus stop", exact=True)).to_be_visible()
|
playwright_api.expect(page.get_by_text("Central Stop · NW-bound · Bus stop", exact=True)).to_be_visible()
|
||||||
page.get_by_text("Central Stop", exact=True).click()
|
page.get_by_text("Central Stop", exact=True).click()
|
||||||
playwright_api.expect(page).to_have_url(re.compile(r"\?node=123$"))
|
playwright_api.expect(page).to_have_url(re.compile(r"\?node=123$"))
|
||||||
|
playwright_api.expect(page.locator(".hovered-stop-marker")).to_be_hidden()
|
||||||
playwright_api.expect(page.locator("#atco-code")).to_have_text("0100BRP90314")
|
playwright_api.expect(page.locator("#atco-code")).to_have_text("0100BRP90314")
|
||||||
playwright_api.expect(page.locator("#stop-type")).to_have_text("Bus stop")
|
playwright_api.expect(page.locator("#stop-type")).to_have_text("Bus stop")
|
||||||
playwright_api.expect(page.locator("#stop-bearing")).to_have_text("NW-bound")
|
playwright_api.expect(page.locator("#stop-bearing")).to_have_text("NW-bound")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue