하수처리시설 레이어 기준 검색 동기화
This commit is contained in:
@@ -182,6 +182,9 @@ const getFlowDirectionModeByPathname = (pathname: string | null): FlowDirectionM
|
||||
|
||||
const AGED_PIPE_FOCUS_PADDING: [number, number, number, number] = [120, 120, 120, 120];
|
||||
const DEFAULT_FEATURE_FIT_PADDING: [number, number, number, number] = [50, 50, 50, 50];
|
||||
const SWAGE_PRCS_FCLT_LAYER_TYPE = "tb_il_swage_prcs_fclt";
|
||||
|
||||
type SwagePrcsFcltLayerMode = "all" | "gte500" | "lt500" | "none";
|
||||
|
||||
// 레이어 설정 응답이 lyrTyNm/lyrTypeNm/lyr_type_nm처럼 혼재되어 내려오는 경우를 단일 기준으로 정규화한다.
|
||||
const getLayerTypeName = (layerInfo: any) =>
|
||||
@@ -191,6 +194,45 @@ const getLayerTypeName = (layerInfo: any) =>
|
||||
layerInfo?.lyr_type_nm ??
|
||||
"",
|
||||
).trim();
|
||||
const getLayerFilterSql = (layerInfo: any) =>
|
||||
String(
|
||||
layerInfo?.filtrSql ??
|
||||
layerInfo?.filtr_sql ??
|
||||
layerInfo?.flterSql ??
|
||||
layerInfo?.filterSql ??
|
||||
layerInfo?.filter_sql ??
|
||||
"",
|
||||
)
|
||||
.replace(/\s+/g, "")
|
||||
.toLowerCase();
|
||||
|
||||
const getSwagePrcsFcltCapacityKind = (layerInfo: any): Exclude<SwagePrcsFcltLayerMode, "all" | "none"> | null => {
|
||||
if (getLayerTypeName(layerInfo) !== SWAGE_PRCS_FCLT_LAYER_TYPE) return null;
|
||||
|
||||
const layerName = String(layerInfo?.lyrNm ?? layerInfo?.name ?? "").replace(/\s+/g, "");
|
||||
const filterSql = getLayerFilterSql(layerInfo);
|
||||
|
||||
if (filterSql.includes("fclt_cpct>=500") || layerName.includes("500이상") || layerName.includes("500톤이상")) return "gte500";
|
||||
if (filterSql.includes("fclt_cpct<500") || layerName.includes("500미만") || layerName.includes("500톤미만")) return "lt500";
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
const getSwagePrcsFcltLayerMode = (checkedNodesData: any[]): SwagePrcsFcltLayerMode => {
|
||||
const checkedKinds = new Set(
|
||||
checkedNodesData
|
||||
.map((node) => getSwagePrcsFcltCapacityKind(node?.data ?? node))
|
||||
.filter(Boolean),
|
||||
);
|
||||
const hasGte500 = checkedKinds.has("gte500");
|
||||
const hasLt500 = checkedKinds.has("lt500");
|
||||
|
||||
if (hasGte500 && hasLt500) return "all";
|
||||
if (hasGte500) return "gte500";
|
||||
if (hasLt500) return "lt500";
|
||||
return "none";
|
||||
};
|
||||
|
||||
// 유하방향 노드는 타입명 또는 표시명으로 식별한다. DB DML 반영 전후 응답 차이를 모두 흡수하기 위한 판별 함수이다.
|
||||
const isFlowDirectionLayerInfo = (layerInfo: any) => {
|
||||
@@ -2240,6 +2282,7 @@ const Map = () => {
|
||||
const [isAgedPipeChecked, setIsAgedPipeChecked] = useState(false);
|
||||
const [isSinkholeChecked, setIsSinkholeChecked] = useState(false);
|
||||
const [isFloodHistoryChecked, setIsFloodHistoryChecked] = useState(false);
|
||||
const [swagePrcsFcltLayerMode, setSwagePrcsFcltLayerMode] = useState<SwagePrcsFcltLayerMode>("all");
|
||||
const [activeLayerSettingOrder, setActiveLayerSettingOrder] = useState<string[]>([]);
|
||||
const [draftAgedPipeFilters, setDraftAgedPipeFilters] =
|
||||
useState<AgedPipeFilters>(AGED_PIPE_DEFAULT_FILTERS);
|
||||
@@ -3616,7 +3659,21 @@ const Map = () => {
|
||||
setIsSearchModalOpen(false);
|
||||
};
|
||||
|
||||
const facilityTypes = [{ text: "하수처리시설", val: "tb_il_swage_prcs_fclt" }];
|
||||
const swagePrcsFcltSearchFilter = useMemo(() => {
|
||||
switch (swagePrcsFcltLayerMode) {
|
||||
case "gte500":
|
||||
return { label: "하수처리시설(500톤 이상)", cqlFilter: "fclt_cpct >= 500" };
|
||||
case "lt500":
|
||||
return { label: "하수처리시설(500톤 미만)", cqlFilter: "fclt_cpct < 500" };
|
||||
case "none":
|
||||
return { label: "하수처리시설(레이어 꺼짐)", disabled: true };
|
||||
case "all":
|
||||
default:
|
||||
return { label: "하수처리시설(전체)" };
|
||||
}
|
||||
}, [swagePrcsFcltLayerMode]);
|
||||
|
||||
const facilityTypes = [{ text: "하수처리시설", val: SWAGE_PRCS_FCLT_LAYER_TYPE }];
|
||||
|
||||
const fetchAgedPipeRows = useCallback(
|
||||
async (page: number, filters: AgedPipeFilters, size: number) => {
|
||||
@@ -4482,6 +4539,7 @@ const Map = () => {
|
||||
const handleCheckedLayersChange = useCallback((checkedIds: string[], checkedNodesData: any[]) => {
|
||||
checkedNodesDataRef.current = checkedNodesData;
|
||||
setCheckedLayerLegendVersion((version) => version + 1);
|
||||
setSwagePrcsFcltLayerMode(getSwagePrcsFcltLayerMode(checkedNodesData));
|
||||
|
||||
// 유하방향은 일반 setLayerOnMap 대상이 아니므로 체크 노드 여부를 별도로 추적한다.
|
||||
const flowDirectionNode = checkedNodesData.find((node) =>
|
||||
@@ -6629,6 +6687,7 @@ const Map = () => {
|
||||
gisMaps={gisMaps}
|
||||
facilityTypes={facilityTypes}
|
||||
sidoSearchZoom={isAgedPipeChecked ? AGED_PIPE_GUIDE_MIN_ZOOM : undefined}
|
||||
facilityLayerFilter={swagePrcsFcltSearchFilter}
|
||||
/>
|
||||
}
|
||||
waterDepth={undefined}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# FE-MAP 하수처리시설 검색 동기화 구현기록
|
||||
|
||||
## 1. 작업 목적
|
||||
- 지도 레이어 트리의 하수처리시설 500톤 기준 레이어 선택 상태와 상단 시설물 검색 조건을 동기화한다.
|
||||
|
||||
## 2. 수정 대상
|
||||
- `FE_APP_ROOT/app/(map-layout)/map/page.tsx`
|
||||
- `FE_REPO_ROOT/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx`
|
||||
- `COMMON_DOCS_ROOT/DB작업.sql`
|
||||
|
||||
## 3. 구현 내용
|
||||
- 하수처리시설 하위 레이어명은 DB `tb_sn_lyr_stng`의 `lyr_nm`을 그대로 사용하고, 프론트 강제 치환은 제거했다.
|
||||
- 레이어 선택 상태에 따라 시설물 검색 셀렉트 문구를 `하수처리시설(전체)`, `하수처리시설(500톤 이상)`, `하수처리시설(500톤 미만)`, `하수처리시설(레이어 꺼짐)`으로 표시한다.
|
||||
- 하수처리시설 검색 목록 조회 시 선택된 레이어 기준에 맞춰 `fclt_cpct >= 500` 또는 `fclt_cpct < 500` 조건을 함께 적용한다.
|
||||
- WFS 목록 조회의 `cql_filter`는 `URLSearchParams`로 인코딩해 500톤 기준 조건이 실제 요청에 반영되도록 보정했다.
|
||||
- 시설 선택 시 현재 지도 source만 검색하지 않고, feature id 기준 GeoServer 재조회 후 검색 레이어를 선택하도록 보정했다.
|
||||
- 두 레이어가 모두 꺼진 경우 하수처리시설 목록은 선택 불가 placeholder만 표시한다.
|
||||
- `tb_sn_lyr_stng`의 `lyr_sn=112/113` 레이어명을 `500톤 이상`, `500톤 미만`으로 정리하는 DML 초안을 `DB작업.sql`에 추가했다.
|
||||
|
||||
## 4. 검증
|
||||
- TSX 파서 검사 통과
|
||||
- `pnpm --filter @common/business_components run build` 통과
|
||||
|
||||
## 5. 영향 범위와 리스크
|
||||
- 프론트 지도 화면의 레이어명 표시와 상단 시설물 검색 목록에 한정된다.
|
||||
- API 계약과 DB 스키마 변경은 없다.
|
||||
- DB 기준데이터 레이어명 변경 DML은 실제 대상 DB 반영 후 지도 레이어 트리에서 확인해야 한다.
|
||||
- 레이어 메타데이터의 `flterSql/filtrSql` 또는 레이어명이 변경되면 500톤 기준 판별 조건을 함께 확인해야 한다.
|
||||
@@ -12,11 +12,19 @@ const geoserverUrl =
|
||||
const FACILITY_TYPE_URL_MAP: Record<string, string> = {
|
||||
tb_il_swage_prcs_fclt: geoserverUrl,
|
||||
};
|
||||
const DEFAULT_SWAGE_PRCS_FCLT_LABEL = "하수처리시설";
|
||||
|
||||
type FacilityLayerFilter = {
|
||||
label: string;
|
||||
cqlFilter?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
interface SearchBarProps {
|
||||
gisMaps: React.RefObject<any>;
|
||||
facilityTypes: { text: string; val: string }[];
|
||||
sidoSearchZoom?: number;
|
||||
facilityLayerFilter?: FacilityLayerFilter;
|
||||
}
|
||||
|
||||
interface CenterSelectDataType extends SelectDataType {
|
||||
@@ -27,6 +35,7 @@ export const ProcSearchBar = ({
|
||||
gisMaps,
|
||||
facilityTypes,
|
||||
sidoSearchZoom = 11,
|
||||
facilityLayerFilter,
|
||||
}: SearchBarProps) => {
|
||||
const [sidoValue, setSidoValue] = useState("0");
|
||||
const [sigunValue, setSigunValue] = useState("0");
|
||||
@@ -39,14 +48,18 @@ export const ProcSearchBar = ({
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<CenterSelectDataType[]>([
|
||||
{ text: "시군구", val: "0" },
|
||||
]);
|
||||
const [facilityData, setFacilityData] = useState<SelectDataType[]>([
|
||||
{ text: "하수처리시설", val: "0" },
|
||||
const [facilityData, setFacilityData] = useState<SelectDataType[]>(() => [
|
||||
{ text: facilityLayerFilter?.label ?? DEFAULT_SWAGE_PRCS_FCLT_LABEL, val: "0" },
|
||||
]);
|
||||
const [facilityValue, setFacilityValue] = useState("0");
|
||||
|
||||
const [facilityType, setFacilityType] = useState(
|
||||
facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0",
|
||||
);
|
||||
const defaultFacilityData = useCallback(
|
||||
() => [{ text: facilityLayerFilter?.label ?? DEFAULT_SWAGE_PRCS_FCLT_LABEL, val: "0" }],
|
||||
[facilityLayerFilter?.label],
|
||||
);
|
||||
|
||||
const fetchSido = async () => {
|
||||
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_ctpv&outputFormat=application/json&propertyName=mctpv_korn_nm,mctpv_cd`;
|
||||
@@ -114,88 +127,119 @@ export const ProcSearchBar = ({
|
||||
setSigunData(list);
|
||||
};
|
||||
|
||||
const fetchFacilitiesBySggNm = async (
|
||||
sggCd: string,
|
||||
sggNm: string,
|
||||
sidoNm: string,
|
||||
currentFacilityType?: string,
|
||||
) => {
|
||||
const type = currentFacilityType ?? facilityType;
|
||||
if (!type || type === "0") return;
|
||||
const fetchFacilitiesBySggNm = useCallback(
|
||||
async (
|
||||
sggCd: string,
|
||||
sggNm: string,
|
||||
sidoNm: string,
|
||||
currentFacilityType?: string,
|
||||
) => {
|
||||
const type = currentFacilityType ?? facilityType;
|
||||
if (!type || type === "0") return;
|
||||
|
||||
const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type];
|
||||
if (!baseUrlTemplate) return;
|
||||
const activeFacilityFilter = type === "tb_il_swage_prcs_fclt" ? facilityLayerFilter : undefined;
|
||||
if (activeFacilityFilter?.disabled) {
|
||||
setFacilityData(defaultFacilityData());
|
||||
setFacilityValue("0");
|
||||
return;
|
||||
}
|
||||
|
||||
const year = new Date().getFullYear().toString();
|
||||
let url = baseUrlTemplate
|
||||
.replace("{year}", year)
|
||||
.replace("{sggCd}", sggCd)
|
||||
.replace("{sidoNm}", encodeURIComponent(sidoNm))
|
||||
.replace("{sggNm}", encodeURIComponent(sggNm));
|
||||
const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type];
|
||||
if (!baseUrlTemplate) return;
|
||||
|
||||
let list: SelectDataType[] = [];
|
||||
const year = new Date().getFullYear().toString();
|
||||
let url = baseUrlTemplate
|
||||
.replace("{year}", year)
|
||||
.replace("{sggCd}", sggCd)
|
||||
.replace("{sidoNm}", encodeURIComponent(sidoNm))
|
||||
.replace("{sggNm}", encodeURIComponent(sggNm));
|
||||
|
||||
if (type === "tb_il_swage_prcs_fclt") {
|
||||
const cqlFilter = `ctpv_nm='${encodeURIComponent(sidoNm)}' AND sgg_nm='${encodeURIComponent(sggNm)}'`;
|
||||
url = `${url}&typeName=hasudo:${type}&cql_filter=${cqlFilter}`;
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.features || [])
|
||||
.map((f: any) => ({
|
||||
text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
|
||||
val: f.id,
|
||||
}))
|
||||
.sort((a: any, b: any) => a.text.localeCompare(b.text, "ko"));
|
||||
} else if (type === "tb_wr_bdst_ruse_fclt") {
|
||||
const paramsRes = await fetch("/reuse-service/reuseFc/pubFc");
|
||||
const paramsJson = await paramsRes.json();
|
||||
const params = paramsJson.data;
|
||||
let list: SelectDataType[] = [];
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.ruseUtztnFcltNm ?? "(이름없음)",
|
||||
val: item.pbnstRuseFcltId,
|
||||
}));
|
||||
} else if (type === "tb_wr_ruse_fclt_dmd_co") {
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.dmdCoNm ?? "(이름없음)",
|
||||
val: item.dmdInfoId,
|
||||
}));
|
||||
} else if (type === "tb_wr_tmpr_dmd_co") {
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.dmdCoNm ?? "(이름없음)",
|
||||
val: item.fctryMngSn,
|
||||
}));
|
||||
} else {
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.bdstNm ?? "(이름없음)",
|
||||
val: item.bdstInfoSn,
|
||||
}));
|
||||
}
|
||||
if (type === "tb_il_swage_prcs_fclt") {
|
||||
const escapeCqlText = (value: string) => value.replace(/'/g, "''");
|
||||
const cqlFilters = [
|
||||
`ctpv_nm='${escapeCqlText(sidoNm)}'`,
|
||||
`sgg_nm='${escapeCqlText(sggNm)}'`,
|
||||
];
|
||||
if (activeFacilityFilter?.cqlFilter) cqlFilters.push(activeFacilityFilter.cqlFilter);
|
||||
const params = new URLSearchParams({
|
||||
typeName: `hasudo:${type}`,
|
||||
cql_filter: cqlFilters.join(" AND "),
|
||||
});
|
||||
url = `${url}&${params.toString()}`;
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.features || [])
|
||||
.map((f: any) => ({
|
||||
text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
|
||||
val: f.id,
|
||||
}))
|
||||
.sort((a: any, b: any) => a.text.localeCompare(b.text, "ko"));
|
||||
} else if (type === "tb_wr_bdst_ruse_fclt") {
|
||||
const paramsRes = await fetch("/reuse-service/reuseFc/pubFc");
|
||||
const paramsJson = await paramsRes.json();
|
||||
const params = paramsJson.data;
|
||||
|
||||
const sorted = list.slice().sort((a, b) => a.text.localeCompare(b.text, "ko"));
|
||||
setFacilityData([{ text: "하수처리시설", val: "0" }, ...sorted]);
|
||||
setFacilityValue("0");
|
||||
};
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.ruseUtztnFcltNm ?? "(이름없음)",
|
||||
val: item.pbnstRuseFcltId,
|
||||
}));
|
||||
} else if (type === "tb_wr_ruse_fclt_dmd_co") {
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.dmdCoNm ?? "(이름없음)",
|
||||
val: item.dmdInfoId,
|
||||
}));
|
||||
} else if (type === "tb_wr_tmpr_dmd_co") {
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.dmdCoNm ?? "(이름없음)",
|
||||
val: item.fctryMngSn,
|
||||
}));
|
||||
} else {
|
||||
const res = await fetch(url);
|
||||
const json = await res.json();
|
||||
list = (json.data || []).map((item: any) => ({
|
||||
text: item.bdstNm ?? "(이름없음)",
|
||||
val: item.bdstInfoSn,
|
||||
}));
|
||||
}
|
||||
|
||||
const sorted = list.slice().sort((a, b) => a.text.localeCompare(b.text, "ko"));
|
||||
setFacilityData([...defaultFacilityData(), ...sorted]);
|
||||
setFacilityValue("0");
|
||||
},
|
||||
[defaultFacilityData, facilityLayerFilter, facilityType],
|
||||
);
|
||||
useEffect(() => {
|
||||
fetchSido();
|
||||
fetchSigungu();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const sidoNm = sidoData.find((item) => item.val === sidoValue)?.text || "";
|
||||
const sggNm = sigunData.find((item) => item.val === sigunValue)?.text || "";
|
||||
const sggCd = sigunData.find((item) => item.val === sigunValue)?.val || "";
|
||||
|
||||
if (sggNm && sidoNm) {
|
||||
fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, facilityType);
|
||||
return;
|
||||
}
|
||||
|
||||
setFacilityData(defaultFacilityData());
|
||||
setFacilityValue("0");
|
||||
}, [defaultFacilityData, facilityLayerFilter?.cqlFilter, facilityLayerFilter?.disabled, facilityType, fetchFacilitiesBySggNm, sidoData, sidoValue, sigunData, sigunValue]);
|
||||
|
||||
const initializeSigunData = useCallback(
|
||||
(nextSidoCd: string) => {
|
||||
@@ -218,7 +262,7 @@ export const ProcSearchBar = ({
|
||||
if (type === "ctpvCd") {
|
||||
setSidoValue(val);
|
||||
initializeSigunData(val);
|
||||
setFacilityData([{ text: "하수처리시설", val: "0" }]);
|
||||
setFacilityData(defaultFacilityData());
|
||||
setFacilityValue("0");
|
||||
return;
|
||||
}
|
||||
@@ -235,7 +279,7 @@ export const ProcSearchBar = ({
|
||||
if (type === "facilityType") {
|
||||
setFacilityType(val);
|
||||
setFacilityValue("0");
|
||||
setFacilityData([{ text: "하수처리시설", val: "0" }]);
|
||||
setFacilityData(defaultFacilityData());
|
||||
const sidoNm = sidoData.find((item) => item.val === sidoValue)?.text || "";
|
||||
const sggNm = sigunData.find((item) => item.val === sigunValue)?.text || "";
|
||||
const sggCd = sigunData.find((item) => item.val === sigunValue)?.val || "";
|
||||
@@ -253,7 +297,7 @@ export const ProcSearchBar = ({
|
||||
}
|
||||
}
|
||||
},
|
||||
[initializeSigunData, sigunData, sigunValue, sidoData, sidoValue, facilityType],
|
||||
[defaultFacilityData, fetchFacilitiesBySggNm, initializeSigunData, sigunData, sigunValue, sidoData, sidoValue, facilityType],
|
||||
);
|
||||
|
||||
const handleSearch = useCallback(() => {
|
||||
@@ -279,48 +323,20 @@ export const ProcSearchBar = ({
|
||||
moveMapToCenter(gisMaps, selectedSido.center, sidoSearchZoom);
|
||||
}, [gisMaps, sidoValue, sigunValue, sidoData, filteredSigunData, sigunData, sidoSearchZoom]);
|
||||
|
||||
const handleFeatureFocus = (data: any) => {
|
||||
const map = gisMaps.current;
|
||||
if (!map) {
|
||||
console.warn("지도가 초기화되지 않았습니다.");
|
||||
const handleFeatureFocus = async (data: any) => {
|
||||
const layerNm = String(data?.layerNm ?? "").trim();
|
||||
let featureId = String(data?.fid ?? "").trim();
|
||||
|
||||
if (!layerNm || !featureId) return;
|
||||
if (!featureId.includes(".")) featureId = `${layerNm}.${featureId}`;
|
||||
|
||||
const searchLayer = GisApp.Module.layer as any;
|
||||
if (!searchLayer?.showSearchResultsFromGeoJSON) {
|
||||
console.warn("Search layer module is not ready:", data);
|
||||
return;
|
||||
}
|
||||
|
||||
const select = GisApp.Module.select as any;
|
||||
if (!select) return;
|
||||
|
||||
let foundFeature: any = null;
|
||||
const featureId = data.fid;
|
||||
|
||||
map
|
||||
.getLayers()
|
||||
.getArray()
|
||||
.forEach((layer: any) => {
|
||||
const source = layer.getSource?.();
|
||||
if (source?.getFeatureById) {
|
||||
const feature = source.getFeatureById(String(featureId).trim());
|
||||
if (feature) foundFeature = feature;
|
||||
}
|
||||
});
|
||||
|
||||
if (foundFeature) {
|
||||
const geometry = foundFeature.getGeometry();
|
||||
if (geometry) {
|
||||
const extent = geometry.getExtent();
|
||||
map.getView().fit(extent, {
|
||||
duration: 300,
|
||||
padding: [50, 50, 50, 50],
|
||||
maxZoom: 16,
|
||||
constrainResolution: true,
|
||||
nearest: true,
|
||||
});
|
||||
} else {
|
||||
alert("위치정보를 찾을 수 없습니다.");
|
||||
console.warn("geometry를 찾을 수 없습니다:", data);
|
||||
}
|
||||
} else {
|
||||
console.warn("Feature를 찾을 수 없습니다:", data);
|
||||
}
|
||||
await searchLayer.showSearchResultsFromGeoJSON(layerNm, featureId);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user