104 lines
2.7 KiB
JavaScript
104 lines
2.7 KiB
JavaScript
import { useCallback, useRef, useEffect, useMemo } from 'react';
|
|
import mapboxgl, { Popup } from 'mapbox-gl';
|
|
|
|
import {
|
|
filterFeatureCollection,
|
|
findFeature,
|
|
getBounds,
|
|
getCenter
|
|
} from '../shared/mapbox/utils';
|
|
|
|
const SOURCE_CADASTRE = 'cadastre';
|
|
|
|
export function useMapbox(featureCollection) {
|
|
const mapRef = useRef();
|
|
const selectedCadastresRef = useRef(() => new Set());
|
|
const isSupported = useMemo(() => mapboxgl.supported());
|
|
|
|
const fitBounds = useCallback((bbox) => {
|
|
mapRef.current.fitBounds(bbox, { padding: 100 });
|
|
}, []);
|
|
|
|
const onLoad = useCallback(
|
|
(map) => {
|
|
if (!mapRef.current) {
|
|
mapRef.current = map;
|
|
mapRef.current.fitBounds(featureCollection.bbox, { padding: 100 });
|
|
onStyleChange();
|
|
}
|
|
},
|
|
[featureCollection]
|
|
);
|
|
|
|
const onStyleChange = useCallback(() => {
|
|
if (mapRef.current) {
|
|
selectedCadastresRef.current = new Set(
|
|
filterFeatureCollection(
|
|
featureCollection,
|
|
SOURCE_CADASTRE
|
|
).features.map(({ properties }) => properties.cid)
|
|
);
|
|
if (selectedCadastresRef.current.size > 0) {
|
|
mapRef.current.setFilter('parcelle-highlighted', [
|
|
'in',
|
|
'id',
|
|
...selectedCadastresRef.current
|
|
]);
|
|
}
|
|
}
|
|
}, [featureCollection]);
|
|
|
|
const popup = useMemo(
|
|
() =>
|
|
new Popup({
|
|
closeButton: false,
|
|
closeOnClick: false
|
|
})
|
|
);
|
|
|
|
const onMouseEnter = useCallback(
|
|
(event) => {
|
|
const feature = event.features[0];
|
|
if (feature.properties && feature.properties.description) {
|
|
const coordinates = getCenter(feature.geometry, event.lngLat);
|
|
const description = feature.properties.description;
|
|
mapRef.current.getCanvas().style.cursor = 'pointer';
|
|
popup.setLngLat(coordinates).setHTML(description).addTo(mapRef.current);
|
|
} else {
|
|
popup.remove();
|
|
}
|
|
},
|
|
[popup]
|
|
);
|
|
|
|
const onMouseLeave = useCallback(() => {
|
|
mapRef.current.getCanvas().style.cursor = '';
|
|
popup.remove();
|
|
}, [popup]);
|
|
|
|
useExternalEvents(featureCollection, { fitBounds });
|
|
|
|
return { isSupported, onLoad, onStyleChange, onMouseEnter, onMouseLeave };
|
|
}
|
|
|
|
function useExternalEvents(featureCollection, { fitBounds }) {
|
|
const onFeatureFocus = useCallback(
|
|
({ detail }) => {
|
|
const { id } = detail;
|
|
const feature = findFeature(featureCollection, id);
|
|
if (feature) {
|
|
fitBounds(getBounds(feature.geometry));
|
|
}
|
|
},
|
|
[featureCollection, fitBounds]
|
|
);
|
|
|
|
useEvent('map:feature:focus', onFeatureFocus);
|
|
}
|
|
|
|
export function useEvent(eventName, callback) {
|
|
return useEffect(() => {
|
|
addEventListener(eventName, callback);
|
|
return () => removeEventListener(eventName, callback);
|
|
}, [eventName, callback]);
|
|
}
|