mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-05-20 14:44:51 +02:00
fix(map): Prevent camera zoom-out when clicking features
- Track place identity with lastFlyTargetRef to avoid re-flying on metadata updates (boundary, wikidata, etc.) - Only flyTo on NEW place selection, not subsequent store updates - Apply z14 threshold to all camera movements: - flyTo for search results: only if currentZoom < 14 - fitBounds for boundaries: only if currentZoom < 14 - At z14+ camera stays put, boundary draws silently Fixes zoom-out bug where clicking a feature at high zoom would zoom back out to z14. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
869391ee4e
commit
bd372b9dc9
1 changed files with 28 additions and 17 deletions
|
|
@ -1497,6 +1497,7 @@ const MapView = forwardRef(function MapView(_, ref) {
|
|||
const highlightedFeatureRef = useRef(null) // { source, sourceLayer, id } for setFeatureState
|
||||
const hoveredFeatureRef = useRef(null) // for hover highlight
|
||||
const updateBoundaryRef = useRef(null) // boundary update function
|
||||
const lastFlyTargetRef = useRef(null) // track last fly target to avoid re-flying on metadata updates
|
||||
// Refs for measurement state (accessible in click handlers)
|
||||
const measuringRef = useRef({ active: false, points: [] })
|
||||
const measureLabelsRef = useRef([]) // HTML label elements
|
||||
|
|
@ -2420,21 +2421,16 @@ const MapView = forwardRef(function MapView(_, ref) {
|
|||
// Validate bounds before fitting
|
||||
if (minLng >= -180 && maxLng <= 180 && minLat >= -90 && maxLat <= 90 &&
|
||||
minLng < maxLng && minLat < maxLat) {
|
||||
const bounds = [[minLng, minLat], [maxLng, maxLat]]
|
||||
// Only fit bounds if zoomed out (< z14). At z14+ just draw boundary silently.
|
||||
const currentZoom = map.getZoom()
|
||||
const target = map.cameraForBounds(bounds, { padding: 50 })
|
||||
// NEVER zoom out - user's zoom level is intentional
|
||||
if (target && target.zoom < currentZoom) {
|
||||
// Would zoom out — just draw the boundary without moving camera
|
||||
return
|
||||
if (currentZoom < 14) {
|
||||
const bounds = [[minLng, minLat], [maxLng, maxLat]]
|
||||
map.fitBounds(bounds, {
|
||||
padding: 50,
|
||||
duration: 700,
|
||||
maxZoom: 16,
|
||||
})
|
||||
}
|
||||
map.fitBounds(bounds, {
|
||||
padding: 50,
|
||||
duration: 700,
|
||||
maxZoom: 16,
|
||||
})
|
||||
} else {
|
||||
console.warn('Invalid bounds:', { minLng, maxLng, minLat, maxLat })
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -2622,11 +2618,26 @@ const MapView = forwardRef(function MapView(_, ref) {
|
|||
previewMarkerRef.current = null
|
||||
}
|
||||
|
||||
if (!selectedPlace) return
|
||||
if (!selectedPlace) {
|
||||
lastFlyTargetRef.current = null
|
||||
return
|
||||
}
|
||||
|
||||
// Only fly to place if it came from search (not map-click which already centered)
|
||||
if (selectedPlace.source !== 'map_click' && selectedPlace.source !== 'basemap_label') {
|
||||
map.flyTo({ center: [selectedPlace.lon, selectedPlace.lat], zoom: 14, duration: 800 })
|
||||
// Track place identity - only fly on NEW place selection, not metadata updates
|
||||
const placeKey = `${selectedPlace.lat}-${selectedPlace.lon}-${selectedPlace.name}`
|
||||
if (placeKey === lastFlyTargetRef.current) {
|
||||
// Same place, skip flyTo (this is just a metadata update)
|
||||
} else {
|
||||
lastFlyTargetRef.current = placeKey
|
||||
|
||||
// Only fly to place if it came from search (not map-click which already centered)
|
||||
if (selectedPlace.source !== 'map_click' && selectedPlace.source !== 'basemap_label') {
|
||||
// Only fly IN if below z14. At z14+ do nothing.
|
||||
const currentZoom = map.getZoom()
|
||||
if (currentZoom < 14) {
|
||||
map.flyTo({ center: [selectedPlace.lon, selectedPlace.lat], zoom: 14, duration: 800 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Different visual feedback based on mode
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue