added geolocation
This commit is contained in:
@@ -2,12 +2,15 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
const YANDEX_GEOCODER_API_KEY = process.env.REACT_APP_YANDEX_GEOCODER_KEY;
|
||||
|
||||
const DEFAULT_CENTER = [55.751574, 37.573856];
|
||||
|
||||
export function useYandexMap(enabled, initialCoords = null, initialAddress = "") {
|
||||
const mapRef = useRef(null);
|
||||
const ymapRef = useRef(null);
|
||||
const placemarkRef = useRef(null);
|
||||
const initializedRef = useRef(false); // защита от двойного вызова StrictMode
|
||||
const requestIdRef = useRef(0); // защита от гонки при быстрых кликах/драгах
|
||||
const pendingFocusRef = useRef(null); // фокус, который ждёт, пока карта инициализируется
|
||||
|
||||
const [coords, setCoords] = useState(initialCoords);
|
||||
const [address, setAddress] = useState(initialAddress ?? "");
|
||||
@@ -48,60 +51,84 @@ export function useYandexMap(enabled, initialCoords = null, initialAddress = "")
|
||||
});
|
||||
}, []);
|
||||
|
||||
const attachPlacemarkDrag = useCallback((map, pm) => {
|
||||
pm.events.add("dragend", () => {
|
||||
const [lat, lng] = pm.geometry.getCoordinates();
|
||||
setCoords({ latitude: lat, longitude: lng });
|
||||
resolveAddress(lat, lng);
|
||||
});
|
||||
}, [resolveAddress]);
|
||||
|
||||
/**
|
||||
* Устанавливает маркер и центр карты на указанные координаты.
|
||||
* Если карта ещё не инициализирована — откладывает фокус до её создания.
|
||||
*/
|
||||
const moveTo = useCallback((lat, lng) => {
|
||||
const map = ymapRef.current;
|
||||
|
||||
if (!map) {
|
||||
pendingFocusRef.current = { lat, lng };
|
||||
return;
|
||||
}
|
||||
|
||||
pendingFocusRef.current = null;
|
||||
setCoords({ latitude: lat, longitude: lng });
|
||||
|
||||
if (placemarkRef.current) {
|
||||
placemarkRef.current.geometry.setCoordinates([lat, lng]);
|
||||
} else {
|
||||
const pm = new window.ymaps.Placemark([lat, lng], {}, { draggable: true });
|
||||
map.geoObjects.add(pm);
|
||||
placemarkRef.current = pm;
|
||||
attachPlacemarkDrag(map, pm);
|
||||
}
|
||||
|
||||
map.setCenter([lat, lng], 14);
|
||||
resolveAddress(lat, lng);
|
||||
}, [attachPlacemarkDrag, resolveAddress]);
|
||||
|
||||
const init = useCallback(() => {
|
||||
if (ymapRef.current) return;
|
||||
|
||||
const startCoords = coordsRef.current;
|
||||
const center = startCoords
|
||||
? [startCoords.latitude, startCoords.longitude]
|
||||
: DEFAULT_CENTER;
|
||||
|
||||
const map = new window.ymaps.Map(mapRef.current, {
|
||||
center,
|
||||
zoom: 14,
|
||||
controls: ["zoomControl", "geolocationControl"],
|
||||
});
|
||||
ymapRef.current = map;
|
||||
|
||||
if (startCoords) {
|
||||
const pm = new window.ymaps.Placemark(center, {}, { draggable: true });
|
||||
map.geoObjects.add(pm);
|
||||
placemarkRef.current = pm;
|
||||
attachPlacemarkDrag(map, pm);
|
||||
resolveAddress(startCoords.latitude, startCoords.longitude);
|
||||
}
|
||||
|
||||
map.events.add("click", e => {
|
||||
const [lat, lng] = e.get("coords");
|
||||
moveTo(lat, lng);
|
||||
});
|
||||
|
||||
// Если геолокация успела вернуть координаты раньше, чем создалась карта,
|
||||
// применяем отложенный фокус сразу после инициализации.
|
||||
if (pendingFocusRef.current) {
|
||||
const pending = pendingFocusRef.current;
|
||||
pendingFocusRef.current = null;
|
||||
moveTo(pending.lat, pending.lng);
|
||||
}
|
||||
}, [attachPlacemarkDrag, resolveAddress, moveTo]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled || !mapRef.current) return;
|
||||
if (initializedRef.current) return; // уже инициализировали
|
||||
initializedRef.current = true;
|
||||
|
||||
const init = () => {
|
||||
if (ymapRef.current) return;
|
||||
|
||||
const startCoords = coordsRef.current;
|
||||
const center = startCoords
|
||||
? [startCoords.latitude, startCoords.longitude]
|
||||
: [55.751574, 37.573856];
|
||||
|
||||
const map = new window.ymaps.Map(mapRef.current, {
|
||||
center,
|
||||
zoom: 14,
|
||||
controls: ["zoomControl", "geolocationControl"],
|
||||
});
|
||||
ymapRef.current = map;
|
||||
|
||||
if (startCoords) {
|
||||
const pm = new window.ymaps.Placemark(center, {}, { draggable: true });
|
||||
map.geoObjects.add(pm);
|
||||
placemarkRef.current = pm;
|
||||
resolveAddress(startCoords.latitude, startCoords.longitude);
|
||||
|
||||
pm.events.add("dragend", () => {
|
||||
const [lat, lng] = pm.geometry.getCoordinates();
|
||||
setCoords({ latitude: lat, longitude: lng });
|
||||
resolveAddress(lat, lng);
|
||||
});
|
||||
}
|
||||
|
||||
map.events.add("click", e => {
|
||||
const [lat, lng] = e.get("coords");
|
||||
setCoords({ latitude: lat, longitude: lng });
|
||||
resolveAddress(lat, lng);
|
||||
|
||||
if (placemarkRef.current) {
|
||||
placemarkRef.current.geometry.setCoordinates([lat, lng]);
|
||||
} else {
|
||||
const pm = new window.ymaps.Placemark([lat, lng], {}, { draggable: true });
|
||||
map.geoObjects.add(pm);
|
||||
placemarkRef.current = pm;
|
||||
|
||||
pm.events.add("dragend", () => {
|
||||
const [la, ln] = pm.geometry.getCoordinates();
|
||||
setCoords({ latitude: la, longitude: ln });
|
||||
resolveAddress(la, ln);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (window.ymaps?.ready) {
|
||||
window.ymaps.ready(init);
|
||||
}
|
||||
@@ -111,12 +138,13 @@ export function useYandexMap(enabled, initialCoords = null, initialAddress = "")
|
||||
ymapRef.current = null;
|
||||
placemarkRef.current = null;
|
||||
initializedRef.current = false;
|
||||
pendingFocusRef.current = null;
|
||||
};
|
||||
// enabled намеренно в deps — карта инициализируется/разрушается при открытии
|
||||
// и закрытии модалки. Начальные координаты читаются из coordsRef, чтобы
|
||||
// при повторном открытии маркер вставал на последний выбранный адрес.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [enabled, resolveAddress]);
|
||||
}, [enabled, init]);
|
||||
|
||||
return { mapRef, coords, address, addressRef, loading };
|
||||
}
|
||||
return { mapRef, coords, address, addressRef, loading, moveTo };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user