From 33a5996beecd06de827ec3178dcf63b72dd5466f Mon Sep 17 00:00:00 2001 From: 3dtours Date: Thu, 25 Jun 2026 12:28:37 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20Ng=C4=83n=20b=E1=BA=A3n=20=C4=91?= =?UTF-8?q?=E1=BB=93=20t=E1=BB=B1=20=C4=91=E1=BB=99ng=20reset=20v=E1=BB=81?= =?UTF-8?q?=20trung=20t=C3=A2m=20khi=20ng=C6=B0=E1=BB=9Di=20d=C3=B9ng=20?= =?UTF-8?q?=C4=91=C3=A3=20t=C6=B0=C6=A1ng=20t=C3=A1c?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TourDetailPage: MapTourBounds chỉ fitBounds 1 lần cho mỗi lần dữ liệu lộ trình thay đổi thực sự (theo locKey). Nếu người dùng đã pan/zoom rồi thì không refit khi data reload. - TourNavigationPage: FitBounds chỉ chạy khi người dùng CHƯA tương tác (hasInteractedRef). Sau khi người dùng pan/zoom/drag, bản đồ giữ nguyên vị trí. - Cả hai bản đồ đều tôn trọng vị trí người dùng đã chọn, không reset về mặc định khi có thay đổi dữ liệu phụ. --- frontend/src/pages/TourDetailPage.tsx | 31 ++++++++++++++-------- frontend/src/pages/TourNavigationPage.tsx | 32 +++++++++++++---------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/frontend/src/pages/TourDetailPage.tsx b/frontend/src/pages/TourDetailPage.tsx index fca2b74..193e466 100644 --- a/frontend/src/pages/TourDetailPage.tsx +++ b/frontend/src/pages/TourDetailPage.tsx @@ -148,20 +148,29 @@ const combineSegmentRoutes = (segmentRoutes: OSRMRoute[][], selectedIndices: num // Component Helper để tự động điều chỉnh khung nhìn bản đồ bao phủ toàn bộ lộ trình const MapTourBounds = ({ locations }: { locations: any[] }) => { const map = useMap(); - // Tạo một key dựa trên giá trị tọa độ để tránh chạy lại khi chỉ thay đổi tham chiếu mảng - const locKey = useMemo(() => JSON.stringify(locations.map(l => [l.latitude, l.longitude])), [locations]); + const shouldFitRef = useRef(true); + const prevLocKeyRef = useRef(null); + + const locKey = useMemo(() => JSON.stringify(locations.map((l: any) => [l.latitude, l.longitude])), [locations]); useEffect(() => { - if (locations.length > 0) { - const bounds = L.latLngBounds(locations.map(l => [l.latitude, l.longitude])); - if (locations.length === 1) { - // Chỉ thực hiện nếu bản đồ chưa ở đúng vị trí (tránh trigger moveend liên tục) - map.setView([locations[0].latitude, locations[0].longitude], 15, { animate: true }); - } else { - map.fitBounds(bounds, { padding: [50, 50], maxZoom: 15 }); - } + if (locations.length === 0) return; + + if (prevLocKeyRef.current !== null && prevLocKeyRef.current !== locKey) { + shouldFitRef.current = true; } - }, [locKey, map]); + prevLocKeyRef.current = locKey; + + if (!shouldFitRef.current) return; + + const bounds = L.latLngBounds(locations.map((l: any) => [l.latitude, l.longitude])); + if (locations.length === 1) { + map.setView([locations[0].latitude, locations[0].longitude], 15, { animate: true }); + } else { + map.fitBounds(bounds, { padding: [50, 50], maxZoom: 15 }); + } + shouldFitRef.current = false; + }, [locKey, map, locations.length]); return null; }; diff --git a/frontend/src/pages/TourNavigationPage.tsx b/frontend/src/pages/TourNavigationPage.tsx index 696b53a..3eca420 100644 --- a/frontend/src/pages/TourNavigationPage.tsx +++ b/frontend/src/pages/TourNavigationPage.tsx @@ -16,14 +16,13 @@ interface TourNavigationPageProps { onBack: () => void; } -const FitBounds = ({ coords, canFitRef }: { coords: [number, number][], canFitRef: React.MutableRefObject }) => { +const FitBounds = ({ coords, destination, hasInteractedRef }: { coords: [number, number][], destination: { lat: number; lng: number; name: string } | null, hasInteractedRef: React.MutableRefObject }) => { const map = useMap(); useEffect(() => { - if (coords.length > 0 && canFitRef.current) { - canFitRef.current = false; + if (coords.length > 0 && !hasInteractedRef.current && destination) { map.fitBounds(coords, { padding: [60, 60], maxZoom: 15 }); } - }, [map, coords, canFitRef]); + }, [map, coords, destination, hasInteractedRef]); return null; }; @@ -58,14 +57,16 @@ const MapRotationHandler = ({ rotation }: { rotation: number }) => { }; const CompassInteractionDetector = ({ - onUserInteraction + onUserInteraction, + hasInteractedRef }: { onUserInteraction: () => void; + hasInteractedRef: React.MutableRefObject; }) => { useMapEvents({ - movestart: onUserInteraction, - zoomstart: onUserInteraction, - dragstart: onUserInteraction, + movestart: () => { hasInteractedRef.current = true; }, + zoomstart: () => { hasInteractedRef.current = true; }, + dragstart: () => { hasInteractedRef.current = true; }, }); return null; }; @@ -78,14 +79,16 @@ const MapRefSetter = ({ mapRef }: { mapRef: React.MutableRefObject return null; }; -const MapInteractionWatcher = () => { +const MapInteractionWatcher = ({ hasInteractedRef }: { hasInteractedRef: React.MutableRefObject }) => { const map = useMap(); useEffect(() => { const onZoomEnd = () => { map._userZoomLevel = map.getZoom(); + hasInteractedRef.current = true; }; const onMoveEnd = () => { map._userCenter = map.getCenter(); + hasInteractedRef.current = true; }; map.on('zoomend', onZoomEnd); map.on('moveend', onMoveEnd); @@ -93,7 +96,7 @@ const MapInteractionWatcher = () => { map.off('zoomend', onZoomEnd); map.off('moveend', onMoveEnd); }; - }, [map]); + }, [map, hasInteractedRef]); return null; }; @@ -141,7 +144,7 @@ export const TourNavigationPage: React.FC = ({ tourId, const mapRef = useRef(null); const watchIdRef = useRef(null); const fetchLockRef = useRef(false); - const canFitRef = useRef(true); + const hasInteractedRef = useRef(false); const originLat = routeData?.origin?.lat; const originLng = routeData?.origin?.lng; @@ -226,6 +229,7 @@ export const TourNavigationPage: React.FC = ({ tourId, }, [routeData, originLat, originLng, destLat, destLng]); const handleUserInteraction = useCallback(() => { + hasInteractedRef.current = true; if (isCompassActive) { setIsCompassActive(false); } @@ -346,14 +350,14 @@ export const TourNavigationPage: React.FC = ({ tourId, > - - {/* */} + + {routeGeometry && ( )} - + {/* Locate User Button */}