feat: implement geometry binding functionality within the map interaction engine
This commit is contained in:
@@ -57,6 +57,7 @@ type MapProps = {
|
||||
focusPadding?: number | import("maplibre-gl").PaddingOptions;
|
||||
imageOverlay?: MapImageOverlay | null;
|
||||
onImageOverlayChange?: (overlay: MapImageOverlay) => void;
|
||||
onBindGeometries?: (targetId: string | number, sourceIds: (string | number)[]) => void;
|
||||
};
|
||||
|
||||
const Map = forwardRef<MapHandle, MapProps>(function Map({
|
||||
@@ -85,6 +86,7 @@ const Map = forwardRef<MapHandle, MapProps>(function Map({
|
||||
focusPadding,
|
||||
imageOverlay = null,
|
||||
onImageOverlayChange,
|
||||
onBindGeometries,
|
||||
}, ref) {
|
||||
// Ref giữ mode mới nhất cho MapLibre handlers được register một lần.
|
||||
const modeRef = useRef<MapProps["mode"]>(mode);
|
||||
@@ -108,7 +110,9 @@ const Map = forwardRef<MapHandle, MapProps>(function Map({
|
||||
const imageOverlayRef = useRef<MapImageOverlay | null>(imageOverlay);
|
||||
// Ref callback update overlay mới nhất để interaction không stale.
|
||||
const onImageOverlayChangeRef = useRef<MapProps["onImageOverlayChange"]>(onImageOverlayChange);
|
||||
|
||||
// Ref callback bind geometry mới nhất để interaction không stale.
|
||||
const onBindGeometriesRef = useRef<MapProps["onBindGeometries"]>(onBindGeometries);
|
||||
|
||||
useEffect(() => { modeRef.current = mode; }, [mode]);
|
||||
useEffect(() => { draftRef.current = draft; }, [draft]);
|
||||
useEffect(() => { onSelectFeatureIdsRef.current = onSelectFeatureIds; }, [onSelectFeatureIds]);
|
||||
@@ -120,6 +124,7 @@ const Map = forwardRef<MapHandle, MapProps>(function Map({
|
||||
useEffect(() => { onUpdateRef.current = onUpdateFeature; }, [onUpdateFeature]);
|
||||
useEffect(() => { imageOverlayRef.current = imageOverlay; }, [imageOverlay]);
|
||||
useEffect(() => { onImageOverlayChangeRef.current = onImageOverlayChange; }, [onImageOverlayChange]);
|
||||
useEffect(() => { onBindGeometriesRef.current = onBindGeometries; }, [onBindGeometries]);
|
||||
|
||||
// Hook sở hữu lifecycle MapLibre instance và các control camera/projection.
|
||||
const {
|
||||
@@ -164,6 +169,7 @@ const Map = forwardRef<MapHandle, MapProps>(function Map({
|
||||
onHideRef,
|
||||
onUpdateRef,
|
||||
onHoverFeatureChangeRef,
|
||||
onBindGeometriesRef,
|
||||
});
|
||||
|
||||
// Hook đồng bộ draft/layer/filter/highlight từ React state xuống MapLibre source/layer.
|
||||
|
||||
@@ -16,6 +16,7 @@ type EngineBinding = {
|
||||
cleanup: () => void;
|
||||
cancel?: () => void;
|
||||
clearSelection?: (skipNotify?: boolean) => void;
|
||||
syncSelection?: (ids: (string | number)[]) => void;
|
||||
};
|
||||
|
||||
type UseMapInteractionProps = {
|
||||
@@ -32,6 +33,7 @@ type UseMapInteractionProps = {
|
||||
onHideRef: React.MutableRefObject<((id: string | number) => void) | undefined>;
|
||||
onUpdateRef: React.MutableRefObject<((id: string | number, geometry: Geometry) => void) | undefined>;
|
||||
onHoverFeatureChangeRef: React.MutableRefObject<((payload: MapHoverPayload | null) => void) | undefined>;
|
||||
onBindGeometriesRef?: React.MutableRefObject<((targetId: string | number, sourceIds: (string | number)[]) => void) | undefined>;
|
||||
};
|
||||
|
||||
export function useMapInteraction({
|
||||
@@ -48,6 +50,7 @@ export function useMapInteraction({
|
||||
onHideRef,
|
||||
onUpdateRef,
|
||||
onHoverFeatureChangeRef,
|
||||
onBindGeometriesRef,
|
||||
}: UseMapInteractionProps) {
|
||||
const editingEngineRef = useRef<ReturnType<typeof createEditingEngine> | null>(null);
|
||||
const engineBindingsRef = useRef<Partial<Record<EditorMode, EngineBinding>>>({});
|
||||
@@ -72,6 +75,13 @@ export function useMapInteraction({
|
||||
}
|
||||
}, [mode, selectedFeatureIds]);
|
||||
|
||||
useEffect(() => {
|
||||
const selectEngine = engineBindingsRef.current.select;
|
||||
if (selectEngine?.syncSelection) {
|
||||
selectEngine.syncSelection(selectedFeatureIds);
|
||||
}
|
||||
}, [selectedFeatureIds]);
|
||||
|
||||
useEffect(() => {
|
||||
const previousMode = previousModeRef.current;
|
||||
if (previousMode !== mode) {
|
||||
@@ -170,7 +180,8 @@ export function useMapInteraction({
|
||||
: undefined,
|
||||
(ids) => onSelectFeatureIdsRef.current?.(ids),
|
||||
(id: string | number) => onSetModeRef.current?.("replay", id),
|
||||
() => Boolean(editingEngineRef.current?.editingRef.current)
|
||||
() => Boolean(editingEngineRef.current?.editingRef.current),
|
||||
(targetId, sourceIds) => onBindGeometriesRef?.current?.(targetId, sourceIds)
|
||||
);
|
||||
|
||||
const cleanupPoint = initPoint(
|
||||
|
||||
Reference in New Issue
Block a user