fix: Luôn giữ kích thước bản đồ người dùng chọn khi tìm đường ngắn nhất

- Thay userInteractedRef bằng canFitRef - chỉ fitBounds đúng 1 lần khi route vừa load
- Sau lần fit đầu, canFitRef = false mãi mãi, không bao giờ reset khi route đổi
- FitBounds chỉ chạy khi canFitRef còn true VÀ compass đang tắt
- MapSizeHandler chỉ gọi invalidateSize() mà không setView để không kích hoạt zoomend/moveend
- Loại bỏ useEffect chết đăng ký zoomend/moveend ở page level (đã có trong MapRefSetter)
- Áp dụng cho cả 2 chế độ: compass bật (xoay theo hướng) và tắt (hướng Bắc)
This commit is contained in:
2026-06-25 11:15:09 +07:00
parent ed0fb8dd64
commit 978992057a
+27 -35
View File
@@ -16,13 +16,14 @@ interface TourNavigationPageProps {
onBack: () => void; onBack: () => void;
} }
const FitBounds = ({ coords, userInteractedRef }: { coords: [number, number][], userInteractedRef: React.MutableRefObject<boolean> }) => { const FitBounds = ({ coords, canFitRef, compassActive }: { coords: [number, number][], canFitRef: React.MutableRefObject<boolean>, compassActive: boolean }) => {
const map = useMap(); const map = useMap();
useEffect(() => { useEffect(() => {
if (coords.length > 0 && !userInteractedRef.current) { if (coords.length > 0 && canFitRef.current && !compassActive) {
canFitRef.current = false;
map.fitBounds(coords, { padding: [60, 60], maxZoom: 15 }); map.fitBounds(coords, { padding: [60, 60], maxZoom: 15 });
} }
}, [map, coords, userInteractedRef]); }, [map, coords, canFitRef, compassActive]);
return null; return null;
}; };
@@ -69,24 +70,30 @@ const CompassInteractionDetector = ({
return null; return null;
}; };
const MapSizeHandler = ({ mapRef, userInteractedRef }: { mapRef: React.MutableRefObject<L.Map | null>, userInteractedRef: React.MutableRefObject<boolean> }) => { const MapRefSetter = ({ mapRef, userInteractedRef }: { mapRef: React.MutableRefObject<L.Map | null>, userInteractedRef: React.MutableRefObject<boolean> }) => {
const map = useMap();
useEffect(() => {
mapRef.current = map;
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);
};
}, [map, mapRef, userInteractedRef]);
return null;
};
const MapSizeHandler = ({ mapRef }: { mapRef: React.MutableRefObject<L.Map | null> }) => {
const map = useMap(); const map = useMap();
useEffect(() => { useEffect(() => {
const timer = setTimeout(() => { const timer = setTimeout(() => {
if (!mapRef.current) return; mapRef.current?.invalidateSize();
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); }, 100);
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [map, mapRef, userInteractedRef]); }, [map, mapRef]);
return null; return null;
}; };
@@ -96,27 +103,12 @@ export const TourNavigationPage: React.FC<TourNavigationPageProps> = ({ tourId,
const [routeGeometry, setRouteGeometry] = useState<[number, number][] | null>(null); const [routeGeometry, setRouteGeometry] = useState<[number, number][] | null>(null);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const userInteractedRef = useRef(false); const userInteractedRef = useRef(false);
const canFitRef = useRef(true);
const mapRef = useRef<L.Map | null>(null); const mapRef = useRef<L.Map | null>(null);
const watchIdRef = useRef<number | null>(null); const watchIdRef = useRef<number | null>(null);
const fetchLockRef = useRef(false); 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 originLat = routeData?.origin?.lat;
const originLng = routeData?.origin?.lng; const originLng = routeData?.origin?.lng;
const destLat = routeData?.destination?.lat; const destLat = routeData?.destination?.lat;
@@ -260,9 +252,9 @@ export const TourNavigationPage: React.FC<TourNavigationPageProps> = ({ tourId,
minZoom={2} minZoom={2}
> >
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="" /> <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="" />
<MapSizeHandler mapRef={mapRef} userInteractedRef={userInteractedRef} /> <MapSizeHandler mapRef={mapRef} />
<MapRefSetter mapRef={mapRef} /> <MapRefSetter mapRef={mapRef} userInteractedRef={userInteractedRef} />
<FitBounds coords={routeGeometry || []} userInteractedRef={userInteractedRef} /> <FitBounds coords={routeGeometry || []} canFitRef={canFitRef} compassActive={isCompassActive} />
{routeData.origin && ( {routeData.origin && (
<Marker position={[routeData.origin.lat, routeData.origin.lng]} icon={userIcon}> <Marker position={[routeData.origin.lat, routeData.origin.lng]} icon={userIcon}>
<Popup> <Popup>