237 lines
7.7 KiB
TypeScript
237 lines
7.7 KiB
TypeScript
"use client";
|
|
import type * as React from "react";
|
|
import { type VertexHandleMeta } from "@/features/gis-edit/model/vertex-handles";
|
|
import { getClosestGeometryVertexMeta } from "@/features/gis-edit/lib/geometry-mutations";
|
|
import { useEffect } from "react";
|
|
import VectorLayer from "ol/layer/Vector.js";
|
|
import { unByKey } from "ol/Observable.js";
|
|
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
|
import { useGisEdit } from "../components/gis-edit/use-gis-edit";
|
|
import { getSelectedFeatureLayerTypeName } from "./right-panel-features";
|
|
|
|
/** 편집 중 지도 클릭 우선순위와 공통 선택 interaction 활성 상태를 연결한다. */
|
|
type Options = {
|
|
mapReady: boolean;
|
|
gisMaps: React.RefObject<any>;
|
|
gisEdit: ReturnType<typeof useGisEdit>;
|
|
gisEditVertexLayerRef: React.RefObject<VectorLayer<any> | null>;
|
|
clearSelectedVertexHandle: () => void;
|
|
gisEditSelectedVertexHandleKeyRef: React.RefObject<string>;
|
|
gisEditSelectedVertexMetaListRef: React.RefObject<VertexHandleMeta[] | null>;
|
|
applySelectedVertexHandleStyle: () => void;
|
|
setGisEditDetailChangeId: React.Dispatch<React.SetStateAction<string | null>>;
|
|
setFeatureData: React.Dispatch<any>;
|
|
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
|
setIsSearchModalOpen: (open: boolean) => void;
|
|
gisEditMoveGripMetaRef: React.RefObject<{
|
|
changeId: string;
|
|
meta: VertexHandleMeta | null;
|
|
} | null>;
|
|
openGisEditPipeDetail: (changeId: string | null) => void;
|
|
};
|
|
|
|
/** 편집 중 지도 클릭 우선순위와 공통 선택 interaction 활성 상태를 연결한다. */
|
|
export function useGisEditSelection({
|
|
mapReady,
|
|
gisMaps,
|
|
gisEdit,
|
|
gisEditVertexLayerRef,
|
|
clearSelectedVertexHandle,
|
|
gisEditSelectedVertexHandleKeyRef,
|
|
gisEditSelectedVertexMetaListRef,
|
|
applySelectedVertexHandleStyle,
|
|
setGisEditDetailChangeId,
|
|
setFeatureData,
|
|
setIsOpen,
|
|
setIsSearchModalOpen,
|
|
gisEditMoveGripMetaRef,
|
|
openGisEditPipeDetail,
|
|
}: Options) {
|
|
// 편집 세션 전체 객체 대신 실제 사용하는 상태와 명령만 의존성으로 추적한다.
|
|
const {
|
|
isEditMode: editIsEditMode,
|
|
pendingInteraction: editPendingInteraction,
|
|
announceStatus: editAnnounceStatus,
|
|
activeTool: editActiveTool,
|
|
selectedLayer: editSelectedLayer,
|
|
registerFeatureSelection: editRegisterFeatureSelection,
|
|
changes: editChanges,
|
|
} = gisEdit;
|
|
|
|
useEffect(() => {
|
|
if (!mapReady || !gisMaps.current || !editIsEditMode) return;
|
|
|
|
const map = gisMaps.current;
|
|
const clickKey = map.on("singleclick", (event: any) => {
|
|
const vertexHandleFeature =
|
|
editPendingInteraction?.editType === "VERTEX_EDIT"
|
|
? map.forEachFeatureAtPixel(
|
|
event.pixel,
|
|
(feature: any, layer: any) =>
|
|
layer === gisEditVertexLayerRef.current ? feature : null,
|
|
{ hitTolerance: 14 },
|
|
)
|
|
: null;
|
|
if (vertexHandleFeature) {
|
|
event.preventDefault?.();
|
|
const handleKind = String(
|
|
vertexHandleFeature.get?.("handleKind") ?? "",
|
|
);
|
|
if (handleKind !== "vertex") {
|
|
clearSelectedVertexHandle();
|
|
editAnnounceStatus(
|
|
"흰색 midpoint는 드래그해서 새 꼭지점을 추가할 수 있습니다. Delete 삭제 대상은 주황색 실꼭지점입니다.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
gisEditSelectedVertexHandleKeyRef.current = String(
|
|
vertexHandleFeature.get?.("handleSelectionKey") ?? "",
|
|
);
|
|
gisEditSelectedVertexMetaListRef.current =
|
|
(vertexHandleFeature.get?.("handleMetaList") as
|
|
| VertexHandleMeta[]
|
|
| undefined) ?? null;
|
|
applySelectedVertexHandleStyle();
|
|
editAnnounceStatus(
|
|
"주황색 실꼭지점을 선택했습니다. Delete 키를 누르면 해당 꼭지점을 삭제합니다.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
const previewFeature = map.forEachFeatureAtPixel(
|
|
event.pixel,
|
|
(feature: any) =>
|
|
String(feature?.get?.("changeId") ?? "").trim() ? feature : null,
|
|
{ hitTolerance: 12 },
|
|
);
|
|
// 편집 도구가 켜진 동안에는 공통 Select를 우회하므로 원본 WFS 피처도 여기서 직접 판정한다.
|
|
const editableSourceFeature = previewFeature
|
|
? null
|
|
: editActiveTool && editActiveTool !== "ADD"
|
|
? map.forEachFeatureAtPixel(
|
|
event.pixel,
|
|
(feature: any) => {
|
|
if (String(feature?.get?.("changeId") ?? "").trim())
|
|
return null;
|
|
return getSelectedFeatureLayerTypeName(feature) ===
|
|
editSelectedLayer?.layerId
|
|
? feature
|
|
: null;
|
|
},
|
|
{ hitTolerance: 12 },
|
|
)
|
|
: null;
|
|
const selectedFeature = previewFeature ?? editableSourceFeature;
|
|
if (!selectedFeature) return;
|
|
clearSelectedVertexHandle();
|
|
|
|
const editSelection = editRegisterFeatureSelection(selectedFeature);
|
|
if (!editSelection.handled) return;
|
|
|
|
event.preventDefault?.();
|
|
|
|
if (editSelection.editType === "DELETE") {
|
|
const select = GisApp.Module.select as any;
|
|
select?.resetSelectedFeature?.();
|
|
setGisEditDetailChangeId(null);
|
|
setFeatureData(null);
|
|
setIsOpen(false);
|
|
setIsSearchModalOpen(false);
|
|
return;
|
|
}
|
|
|
|
if (editActiveTool === "MOVE" || editActiveTool === "VERTEX_EDIT") {
|
|
if (
|
|
editActiveTool === "MOVE" &&
|
|
typeof editSelection.changeId === "string" &&
|
|
editSelection.changeId
|
|
) {
|
|
gisEditMoveGripMetaRef.current = {
|
|
changeId: String(editSelection.changeId),
|
|
meta: getClosestGeometryVertexMeta(
|
|
selectedFeature.getGeometry?.(),
|
|
map,
|
|
event.coordinate,
|
|
),
|
|
};
|
|
}
|
|
setGisEditDetailChangeId(null);
|
|
setFeatureData(null);
|
|
setIsOpen(false);
|
|
setIsSearchModalOpen(false);
|
|
return;
|
|
}
|
|
|
|
const selectedChangeId =
|
|
typeof editSelection.changeId === "string"
|
|
? editSelection.changeId
|
|
: "";
|
|
const selectedChange = editChanges.find(
|
|
(change) => change.changeId === selectedChangeId,
|
|
);
|
|
const canOpenPipeDetail =
|
|
selectedChangeId && editSelection.editType !== "DELETE";
|
|
|
|
if (canOpenPipeDetail) {
|
|
openGisEditPipeDetail(selectedChangeId);
|
|
setFeatureData(
|
|
selectedChange?.editType === "ADD"
|
|
? {
|
|
lyrTypeNm: "tb_ms_swage_ppl",
|
|
fcltMngNo: "",
|
|
mngInstCd: "",
|
|
fclt_mng_no: "",
|
|
inst_mng_no: "",
|
|
}
|
|
: null,
|
|
);
|
|
window.setTimeout(() => {
|
|
setGisEditDetailChangeId(selectedChangeId);
|
|
setIsOpen(true);
|
|
}, 0);
|
|
setIsSearchModalOpen(false);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
unByKey(clickKey);
|
|
};
|
|
}, [
|
|
applySelectedVertexHandleStyle,
|
|
clearSelectedVertexHandle,
|
|
editActiveTool,
|
|
editChanges,
|
|
editIsEditMode,
|
|
editPendingInteraction,
|
|
editAnnounceStatus,
|
|
editRegisterFeatureSelection,
|
|
editSelectedLayer,
|
|
mapReady,
|
|
openGisEditPipeDetail,
|
|
gisMaps,
|
|
gisEditVertexLayerRef,
|
|
gisEditSelectedVertexHandleKeyRef,
|
|
gisEditSelectedVertexMetaListRef,
|
|
setGisEditDetailChangeId,
|
|
setFeatureData,
|
|
setIsOpen,
|
|
setIsSearchModalOpen,
|
|
gisEditMoveGripMetaRef,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
const select = GisApp.Module.select as any;
|
|
if (!select?.setActive) return;
|
|
|
|
if (editIsEditMode && editActiveTool) {
|
|
select.resetSelectedFeature?.();
|
|
select.setActive(false);
|
|
return;
|
|
}
|
|
|
|
select.setActive(true);
|
|
}, [editActiveTool, editIsEditMode, mapReady]);
|
|
return {};
|
|
}
|