Fit mobile searches above results sheet
This commit is contained in:
parent
98b5951cbb
commit
ae5ad9fabc
2 changed files with 71 additions and 11 deletions
|
|
@ -270,6 +270,7 @@ function renderStops(data, fitMap = true, sortOrigin = null, preserveSelection =
|
||||||
radius: 7, color: '#0d6efd', fillColor: '#fff', fillOpacity: 1, weight: 3,
|
radius: 7, color: '#0d6efd', fillColor: '#fff', fillOpacity: 1, weight: 3,
|
||||||
}).bindTooltip(data.location.label).addTo(map);
|
}).bindTooltip(data.location.label).addTo(map);
|
||||||
}
|
}
|
||||||
|
if (isMobile() && data.kind !== 'map') setPanel(true);
|
||||||
|
|
||||||
for (const stop of stops) {
|
for (const stop of stops) {
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
|
|
@ -305,14 +306,15 @@ function renderStops(data, fitMap = true, sortOrigin = null, preserveSelection =
|
||||||
? 'No transport stops were found in this map area.'
|
? 'No transport stops were found in this map area.'
|
||||||
: 'No transport stops were found within 1 km.';
|
: 'No transport stops were found within 1 km.';
|
||||||
list.appendChild(empty);
|
list.appendChild(empty);
|
||||||
if (fitMap && data.location) moveMap(() => map.setView([data.location.lat, data.location.lon], 16));
|
if (fitMap && data.location) {
|
||||||
|
moveMap(() => centrePointInVisibleMap(data.location.lat, data.location.lon, 16));
|
||||||
|
}
|
||||||
} else if (fitMap) {
|
} else if (fitMap) {
|
||||||
const bounds = markers.getBounds();
|
const bounds = markers.getBounds();
|
||||||
if (searchMarker) bounds.extend(searchMarker.getLatLng());
|
if (searchMarker) bounds.extend(searchMarker.getLatLng());
|
||||||
moveMap(() => map.fitBounds(bounds, {padding: [30, 30], maxZoom: 17}));
|
moveMap(() => map.fitBounds(bounds, visibleMapFitOptions()));
|
||||||
if (data.kind === 'atco' && stops.length === 1) selectStop(stops[0]);
|
if (data.kind === 'atco' && stops.length === 1) selectStop(stops[0]);
|
||||||
}
|
}
|
||||||
if (isMobile() && data.kind !== 'map') setPanel(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Show UK-only Nominatim matches and wait for the user to choose one. */
|
/** Show UK-only Nominatim matches and wait for the user to choose one. */
|
||||||
|
|
@ -410,16 +412,37 @@ function clearHoveredStop() {
|
||||||
hoveredMarkerHalo = null;
|
hoveredMarkerHalo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return how many map pixels are covered by the open mobile sheet. */
|
||||||
|
function mobilePanelOverlayHeight() {
|
||||||
|
if (isMobile() && byId('sidebar').classList.contains('panel-open')) {
|
||||||
|
return Math.min(map.getSize().y, byId('sidebar').getBoundingClientRect().height);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Leaflet fit options that reserve the area hidden by the mobile sheet. */
|
||||||
|
function visibleMapFitOptions() {
|
||||||
|
const overlayHeight = mobilePanelOverlayHeight();
|
||||||
|
if (!overlayHeight) return {padding: [30, 30], maxZoom: 17};
|
||||||
|
return {
|
||||||
|
paddingTopLeft: [30, 30],
|
||||||
|
paddingBottomRight: [30, overlayHeight + 30],
|
||||||
|
maxZoom: 17,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Centre a coordinate in the portion of the map not covered by the mobile sheet. */
|
||||||
|
function centrePointInVisibleMap(lat, lon, zoom) {
|
||||||
|
const point = map.project(L.latLng(lat, lon), zoom);
|
||||||
|
const adjustedCenter = map.unproject(
|
||||||
|
point.add(L.point(0, mobilePanelOverlayHeight() / 2)), zoom
|
||||||
|
);
|
||||||
|
map.setView(adjustedCenter, zoom);
|
||||||
|
}
|
||||||
|
|
||||||
/** Centre a selected stop in the portion of the map not covered by the mobile sheet. */
|
/** Centre a selected stop in the portion of the map not covered by the mobile sheet. */
|
||||||
function centreSelectedStop(stop) {
|
function centreSelectedStop(stop) {
|
||||||
const zoom = Math.max(map.getZoom(), 17);
|
centrePointInVisibleMap(stop.lat, stop.lon, Math.max(map.getZoom(), 17));
|
||||||
let verticalOffset = 0;
|
|
||||||
if (isMobile() && byId('sidebar').classList.contains('panel-open')) {
|
|
||||||
verticalOffset = Math.min(map.getSize().y, byId('sidebar').getBoundingClientRect().height) / 2;
|
|
||||||
}
|
|
||||||
const stopPoint = map.project(L.latLng(stop.lat, stop.lon), zoom);
|
|
||||||
const adjustedCenter = map.unproject(stopPoint.add(L.point(0, verticalOffset)), zoom);
|
|
||||||
map.setView(adjustedCenter, zoom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function osmUrl(stop, edit = false) {
|
function osmUrl(stop, edit = false) {
|
||||||
|
|
|
||||||
|
|
@ -278,3 +278,40 @@ def test_mobile_selected_stop_stays_above_detail_sheet(
|
||||||
}""")
|
}""")
|
||||||
assert 0 < position["markerY"] < position["visibleBottom"]
|
assert 0 < position["markerY"] < position["visibleBottom"]
|
||||||
page.close()
|
page.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_mobile_postcode_is_fitted_above_results_sheet(
|
||||||
|
chromium_browser: Any, flask_url: str
|
||||||
|
) -> None:
|
||||||
|
"""A unique postcode marker is fitted inside the unobscured mobile map area."""
|
||||||
|
page = chromium_browser.new_page(viewport={"width": 390, "height": 844})
|
||||||
|
page.route("**/api/search?*", lambda route: route.fulfill(json={
|
||||||
|
"kind": "geocode", "query": "SW1A 1AA",
|
||||||
|
"locations": [{
|
||||||
|
"lat": 51.501, "lon": -0.142, "label": "Westminster, London",
|
||||||
|
"type": "postcode",
|
||||||
|
}],
|
||||||
|
}))
|
||||||
|
page.route("**/api/stops?*", lambda route: route.fulfill(json={
|
||||||
|
"kind": "location",
|
||||||
|
"location": {"lat": 51.501, "lon": -0.142, "label": "Westminster, London"},
|
||||||
|
"stops": [{
|
||||||
|
"type": "node", "id": 999, "lat": 51.502, "lon": -0.141,
|
||||||
|
"name": "Nearby Stop", "atco_code": "490000001", "indicator": None,
|
||||||
|
"bearing": "N", "transport_type": "Bus stop",
|
||||||
|
"tags": {"highway": "bus_stop"},
|
||||||
|
}],
|
||||||
|
}))
|
||||||
|
page.goto(flask_url, wait_until="networkidle")
|
||||||
|
page.get_by_label("Location or ATCO code").fill("SW1A 1AA")
|
||||||
|
page.get_by_role("button", name="Search").click()
|
||||||
|
playwright_api.expect(page.locator("#stop-count")).to_have_text("1 found")
|
||||||
|
page.wait_for_timeout(400)
|
||||||
|
position = page.evaluate("""() => {
|
||||||
|
const point = map.latLngToContainerPoint(searchMarker.getLatLng());
|
||||||
|
const mapRect = document.getElementById('map').getBoundingClientRect();
|
||||||
|
const sheetRect = document.getElementById('sidebar').getBoundingClientRect();
|
||||||
|
return {markerY: point.y, visibleBottom: sheetRect.top - mapRect.top};
|
||||||
|
}""")
|
||||||
|
assert 0 < position["markerY"] < position["visibleBottom"]
|
||||||
|
page.close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue