From ed0fb8dd64c9292c3268e0cbe16d1caf61563946 Mon Sep 17 00:00:00 2001 From: 3dtours Date: Thu, 25 Jun 2026 11:08:13 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20Gi=E1=BB=AF=20nguy=C3=AAn=20zoom/center?= =?UTF-8?q?=20c=E1=BB=A7a=20ng=C6=B0=E1=BB=9Di=20d=C3=B9ng=20khi=20b?= =?UTF-8?q?=E1=BA=A3n=20=C4=91=E1=BB=93=20resize=20tr=C3=AAn=20mobile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Thêm userInteractedRef để theo dõi người dùng đã zoom/drag chưa - FitBounds chỉ chạy khi người dùng chưa tương tác - MapSizeHandler lưu center/zoom trước khi invalidateSize, khôi phục sau nếu user đã tương tác - MapRotationHandler xóa transform thay vì set rotate(0) khi compass tắt - Ngăn map tự động reset về mức zoom ban đầu sau khi người dùng pinch-zoom --- frontend/src/pages/TourNavigationPage.tsx | 44 ++++++++++++++++++----- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/frontend/src/pages/TourNavigationPage.tsx b/frontend/src/pages/TourNavigationPage.tsx index b0de235..8f31015 100644 --- a/frontend/src/pages/TourNavigationPage.tsx +++ b/frontend/src/pages/TourNavigationPage.tsx @@ -16,13 +16,13 @@ interface TourNavigationPageProps { onBack: () => void; } -const FitBounds = ({ coords }: { coords: [number, number][] }) => { +const FitBounds = ({ coords, userInteractedRef }: { coords: [number, number][], userInteractedRef: React.MutableRefObject }) => { const map = useMap(); useEffect(() => { - if (coords.length > 0) { + if (coords.length > 0 && !userInteractedRef.current) { map.fitBounds(coords, { padding: [60, 60], maxZoom: 15 }); } - }, [map, coords]); + }, [map, coords, userInteractedRef]); return null; }; @@ -69,14 +69,24 @@ const CompassInteractionDetector = ({ return null; }; -const MapSizeHandler = () => { +const MapSizeHandler = ({ mapRef, userInteractedRef }: { mapRef: React.MutableRefObject, userInteractedRef: React.MutableRefObject }) => { const map = useMap(); useEffect(() => { const timer = setTimeout(() => { - map.invalidateSize(); + if (!mapRef.current) return; + + const hadUserInteracted = userInteractedRef.current; + const currentCenter = map.getCenter(); + const currentZoom = map.getZoom(); + + mapRef.current.invalidateSize(); + + if (hadUserInteracted) { + mapRef.current.setView(currentCenter, currentZoom, { animate: false }); + } }, 100); return () => clearTimeout(timer); - }, [map]); + }, [map, mapRef, userInteractedRef]); return null; }; @@ -85,12 +95,28 @@ export const TourNavigationPage: React.FC = ({ tourId, const [currentHeading, setCurrentHeading] = useState(0); const [routeGeometry, setRouteGeometry] = useState<[number, number][] | null>(null); const [error, setError] = useState(null); - const [mapReady, setMapReady] = useState(false); + const userInteractedRef = useRef(false); const mapRef = useRef(null); const watchIdRef = useRef(null); const fetchLockRef = useRef(false); + useEffect(() => { + const map = mapRef.current; + if (!map) return; + + const onZoomEnd = () => { userInteractedRef.current = true; }; + const onMoveEnd = () => { userInteractedRef.current = true; }; + + map.on('zoomend', onZoomEnd); + map.on('moveend', onMoveEnd); + + return () => { + map.off('zoomend', onZoomEnd); + map.off('moveend', onMoveEnd); + }; + }, [mapRef.current]); + const originLat = routeData?.origin?.lat; const originLng = routeData?.origin?.lng; const destLat = routeData?.destination?.lat; @@ -234,8 +260,9 @@ export const TourNavigationPage: React.FC = ({ tourId, minZoom={2} > - + + {routeData.origin && ( @@ -250,7 +277,6 @@ export const TourNavigationPage: React.FC = ({ tourId, )} - {routeGeometry && } {routeGeometry && ( )}