diff --git a/src/frontend/src/Components/map/Map.js b/src/frontend/src/Components/map/Map.js index 1eca890e5..778e0a8b0 100644 --- a/src/frontend/src/Components/map/Map.js +++ b/src/frontend/src/Components/map/Map.js @@ -110,7 +110,10 @@ export default function DriveBCMap(props) { const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); - let mousePointXClicked = undefined; + // Refs so map click handler / updatePosition always see current values + const mousePointXClicked = useRef(undefined); + const largeScreenRef = useRef(largeScreen); + largeScreenRef.current = largeScreen; // Context const { mapContext, setMapContext } = useContext(MapContext); @@ -400,20 +403,17 @@ export default function DriveBCMap(props) { geometry = feature.getProperties().altFeature.getGeometry(); // use the point feature's geometry } - // Center if panel from bottom or clicked within 390px from left of the screen - if (mousePointXClicked < 390 || smallScreen) { + // Bottom drawer when !largeScreen; otherwise side panel may cover left clicks + const bottomDrawer = !largeScreenRef.current; + if (mousePointXClicked.current < 390 || bottomDrawer) { const zoom = mapView.current.getZoom(); const coords = geometry.flatCoordinates; const mapWidth = mapRef.current?.getSize()?.[0] ?? 0; - // Use anchored pan if panel from bottom or screen smaller than 1000px - const shouldUseAnchoredPan = mapWidth < 1000 || smallScreen; - - // Center on top half of the screen, if panel open from bottom - const anchorYFraction = !viewportLargeScreen || isCamDetail ? 0.25 : 0.5; - - // Center on right side of screen minus 390px panel, if panel open from left - const anchorXFraction = anchorYFraction !== 0.25 ? (((mapWidth-390)/2) + 390) / mapWidth : 0.5; + // Anchor into the visible map area (above bottom drawer / right of side panel) + const shouldUseAnchoredPan = bottomDrawer || mapWidth < 1000; + const anchorYFraction = bottomDrawer ? 0.25 : 0.5; + const anchorXFraction = bottomDrawer ? 0.5 : (((mapWidth - 390) / 2) + 390) / mapWidth; if (shouldUseAnchoredPan) { setZoomPanAnchored(mapRef, mapView, zoom, coords, anchorXFraction, anchorYFraction); @@ -664,8 +664,7 @@ export default function DriveBCMap(props) { hitTolerance: 20, }); - const mousePointX = e.pixel[0]; - mousePointXClicked = mousePointX; + mousePointXClicked.current = e.pixel[0]; pointerClickHandler( features, clickedFeatureRef, updateClickedFeature, @@ -837,7 +836,10 @@ export default function DriveBCMap(props) { ); if (localStorage.getItem("pendingFit") === 'true') { - fitMap(searchedRoutes, mapView); + // Reserve lower half of the map when the mobile route panel is open + const size = mapRef.current?.getSize(); + const bottomPad = !largeScreenRef.current && size ? Math.round(size[1] * 0.5) : 50; + fitMap(searchedRoutes, mapView, [50, 50, bottomPad, 50]); } // Remove all overlays from previously searched routes diff --git a/src/frontend/src/Components/map/helpers/map.js b/src/frontend/src/Components/map/helpers/map.js index bee904a09..3072c3b65 100644 --- a/src/frontend/src/Components/map/helpers/map.js +++ b/src/frontend/src/Components/map/helpers/map.js @@ -14,7 +14,9 @@ export const transformFeature = (feature, sourceCRS, targetCRS) => { }; // Zoom and pan -export const fitMap = (routes, mapView) => { +// padding: OpenLayers [top, right, bottom, left] — use bottom padding when a +// mobile half-panel covers the lower half of the map (visible-area fit). +export const fitMap = (routes, mapView, padding) => { // Only apply to map page when at least one route is returned if (!Array.isArray(routes) || routes.length === 0) { return; @@ -41,7 +43,12 @@ export const fitMap = (routes, mapView) => { // Transform the combined bounding box to the map's projection const routeExtent = transformExtent(combinedBbox, 'EPSG:4326', 'EPSG:3857'); - mapView.current.fit(routeExtent, { duration: 1000 }); + const fitOptions = { duration: 1000 }; + if (padding) { + fitOptions.padding = padding; + } + + mapView.current.fit(routeExtent, fitOptions); localStorage.setItem("pendingFit", 'false'); } diff --git a/src/frontend/src/Components/routing/RouteSearch.js b/src/frontend/src/Components/routing/RouteSearch.js index 2c7c1ae3e..90eeec293 100644 --- a/src/frontend/src/Components/routing/RouteSearch.js +++ b/src/frontend/src/Components/routing/RouteSearch.js @@ -145,7 +145,11 @@ const RouteSearch = forwardRef((props, ref) => { setSearchParams(searchParams); } - fitMap(routes, mapView); + // Pad bottom when a half-height mobile panel will cover the route + const mapSize = mapRef?.current?.getSize?.(); + const isNarrow = typeof window !== 'undefined' && window.innerWidth < 768; + const bottomPad = isNarrow && mapSize ? Math.round(mapSize[1] * 0.5) : 50; + fitMap(routes, mapView, [50, 50, bottomPad, 50]); setMapContext({ ...mapContext, pendingRouteFit: false