노후관로 분석 - 표시 중 UX 개선 및 팝업 자동이동 제거
This commit is contained in:
@@ -24,7 +24,6 @@ import { downloadAgedPipeCsv } from "./agedPipeExport";
|
||||
const POPUP_ROW_SELECT_MESSAGE = "SN_AGED_PIPE_ROW_SELECT";
|
||||
const POPUP_MINIMIZE_MESSAGE = "SN_AGED_PIPE_POPUP_MINIMIZE";
|
||||
const POPUP_FILTER_SYNC_MESSAGE = "SN_AGED_PIPE_FILTER_SYNC";
|
||||
const POPUP_CTPV_FOCUS_MESSAGE = "SN_AGED_PIPE_CTPV_FOCUS";
|
||||
|
||||
export default function AgedPipePopupPage() {
|
||||
const searchParams = useSearchParams();
|
||||
@@ -124,7 +123,7 @@ export default function AgedPipePopupPage() {
|
||||
return () => window.removeEventListener("message", handleFilterSyncMessage);
|
||||
}, [loadRows]);
|
||||
|
||||
const handleSearch = async (page = 1, shouldFocusCtpv = false) => {
|
||||
const handleSearch = async (page = 1) => {
|
||||
if (!validateElapsedYears(Number(filters.elapsedYears))) {
|
||||
alert("경과년도는 1년~100년 범위 내에서 입력해주세요.");
|
||||
return;
|
||||
@@ -133,16 +132,6 @@ export default function AgedPipePopupPage() {
|
||||
const normalized = normalizeAgedPipeFilters(filters);
|
||||
setFilters(normalized);
|
||||
await loadRows(page, normalized);
|
||||
|
||||
if (shouldFocusCtpv && normalized.ctpvCd !== "0") {
|
||||
window.opener?.postMessage(
|
||||
{
|
||||
type: POPUP_CTPV_FOCUS_MESSAGE,
|
||||
ctpvCd: normalized.ctpvCd,
|
||||
},
|
||||
window.location.origin,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRowClick = (index?: number) => {
|
||||
@@ -250,7 +239,7 @@ export default function AgedPipePopupPage() {
|
||||
});
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") void handleSearch(1, true);
|
||||
if (event.key === "Enter") void handleSearch(1);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
@@ -299,7 +288,7 @@ export default function AgedPipePopupPage() {
|
||||
size="sm"
|
||||
color="primary"
|
||||
className="h-10 px-5 !text-[1.1rem]"
|
||||
onClick={() => void handleSearch(1, true)}
|
||||
onClick={() => void handleSearch(1)}
|
||||
>
|
||||
조회
|
||||
</Button>
|
||||
|
||||
@@ -11,6 +11,7 @@ export const AGED_PIPE_LAYER_TYPE = "tb_ms_swage_ppl";
|
||||
export const AGED_PIPE_DEFAULT_ELAPSED_YEARS = 30;
|
||||
export const AGED_PIPE_PAGE_SIZE = 10;
|
||||
export const AGED_PIPE_MIN_ZOOM = 13;
|
||||
export const AGED_PIPE_GUIDE_MIN_ZOOM = 13.1;
|
||||
export const AGED_PIPE_INVALID_INSTALL_YMD_PREFIXES = ["19000101"];
|
||||
|
||||
export type AgedPipeFilters = {
|
||||
|
||||
@@ -51,6 +51,7 @@ import {
|
||||
type AgedPipeFilters,
|
||||
type AgedPipeRow,
|
||||
AGED_PIPE_DEFAULT_FILTERS,
|
||||
AGED_PIPE_GUIDE_MIN_ZOOM,
|
||||
} from "./components/agedPipe/agedPipeUtils";
|
||||
import { downloadAgedPipeCsv } from "./components/agedPipe/agedPipeExport";
|
||||
import { PIPE_ANALYSIS_DETAIL_ROW_SELECT_MESSAGE } from "./components/pipeAnalysis/pipeAnalysisUtils";
|
||||
@@ -68,10 +69,6 @@ const AGED_PIPE_HIGHLIGHT_LAYER_ID = "SN_AGED_PIPE_HIGHLIGHT";
|
||||
const AGED_PIPE_ROW_SELECT_MESSAGE = "SN_AGED_PIPE_ROW_SELECT";
|
||||
const AGED_PIPE_POPUP_MINIMIZE_MESSAGE = "SN_AGED_PIPE_POPUP_MINIMIZE";
|
||||
const AGED_PIPE_FILTER_SYNC_MESSAGE = "SN_AGED_PIPE_FILTER_SYNC";
|
||||
// 노후관로 팝업에서 조회 버튼 클릭 시, 부모 지도를 선택 시도 범위로 이동시키는 메시지이다.
|
||||
const AGED_PIPE_CTPV_FOCUS_MESSAGE = "SN_AGED_PIPE_CTPV_FOCUS";
|
||||
// 시도 기준 자동 이동은 조회 직후 노후관로가 바로 보이는 수준까지 한 단계 더 당겨 고정한다.
|
||||
const AGED_PIPE_CTPV_FOCUS_ZOOM = 14;
|
||||
const SOUTH_KOREA_VIEW_EXTENT: [number, number, number, number] = [
|
||||
720000,
|
||||
1445000,
|
||||
@@ -956,72 +953,6 @@ const Map = () => {
|
||||
}
|
||||
}, [draftAgedPipeFilters, isAgedPipeListOpen, loadAgedPipeList, syncAgedPipePopupFilters]);
|
||||
|
||||
// 노후관로 팝업에서 시도 기준 조회를 실행하면, 부모 지도창을 해당 시도 extent로 이동시킨다.
|
||||
const focusMapToAgedPipeCtpv = useCallback(async (ctpvCd: string) => {
|
||||
const normalizedCtpvCd = String(ctpvCd ?? "").replace(/[^0-9]/g, "").slice(0, 2);
|
||||
if (!normalizedCtpvCd || normalizedCtpvCd === "0") return;
|
||||
|
||||
const map = gisMaps.current;
|
||||
if (!map) return;
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
service: "WFS",
|
||||
version: "1.0.0",
|
||||
request: "GetFeature",
|
||||
typeName: "hasudo:tb_ms_ctpv",
|
||||
outputFormat: "application/json",
|
||||
CQL_FILTER: `mctpv_cd='${normalizedCtpvCd}'`,
|
||||
});
|
||||
const payload = await getRawJson(`/geoserver/hasudo/ows?${params.toString()}`);
|
||||
// 시도 WFS는 환경마다 3857/4326 등 다른 CRS로 내려올 수 있으므로 응답 crs를 우선 신뢰한다.
|
||||
const responseCrsName = String(payload?.crs?.properties?.name ?? "");
|
||||
const resolvedDataProjection = responseCrsName.includes("EPSG::")
|
||||
? `EPSG:${responseCrsName.split("EPSG::")[1]}`
|
||||
: responseCrsName.includes("EPSG:")
|
||||
? responseCrsName.slice(responseCrsName.lastIndexOf("EPSG:"))
|
||||
: GisApp.FROM_PROJ;
|
||||
const features = new GeoJSON().readFeatures(payload, {
|
||||
dataProjection: resolvedDataProjection,
|
||||
featureProjection: map.getView().getProjection(),
|
||||
});
|
||||
|
||||
let extent: [number, number, number, number] | null = null;
|
||||
features.forEach((feature) => {
|
||||
const geometry = feature.getGeometry();
|
||||
if (!geometry) return;
|
||||
const geometryExtent = geometry.getExtent();
|
||||
if (!extent) {
|
||||
extent = [...geometryExtent] as [number, number, number, number];
|
||||
return;
|
||||
}
|
||||
extent = [
|
||||
Math.min(extent[0], geometryExtent[0]),
|
||||
Math.min(extent[1], geometryExtent[1]),
|
||||
Math.max(extent[2], geometryExtent[2]),
|
||||
Math.max(extent[3], geometryExtent[3]),
|
||||
];
|
||||
});
|
||||
|
||||
if (!extent) return;
|
||||
|
||||
const view = map.getView();
|
||||
view.fit(extent, {
|
||||
padding: AGED_PIPE_FOCUS_PADDING,
|
||||
maxZoom: 18,
|
||||
constrainResolution: true,
|
||||
nearest: true,
|
||||
});
|
||||
|
||||
const fittedZoom = view.getZoom() ?? 0;
|
||||
if (fittedZoom < AGED_PIPE_CTPV_FOCUS_ZOOM) {
|
||||
view.setZoom(AGED_PIPE_CTPV_FOCUS_ZOOM);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("노후관로 시도 이동 중 오류:", error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const openAgedPipePopupWindow = useCallback(() => {
|
||||
const popup = openWindowPopup("agedPipePopup", {
|
||||
elapsedYears: String(appliedAgedPipeFilters.elapsedYears),
|
||||
@@ -1137,12 +1068,6 @@ const Map = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data?.type === AGED_PIPE_CTPV_FOCUS_MESSAGE) {
|
||||
if (!event.data?.ctpvCd) return;
|
||||
void focusMapToAgedPipeCtpv(String(event.data.ctpvCd));
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data?.type === PIPE_ANALYSIS_DETAIL_ROW_SELECT_MESSAGE) {
|
||||
if (!event.data?.row) return;
|
||||
handlePipeAnalysisRowSelect(event.data.row as PipeAnalysisDetailRow);
|
||||
@@ -1151,7 +1076,7 @@ const Map = () => {
|
||||
|
||||
window.addEventListener("message", handleAgedPipePopupMessage);
|
||||
return () => window.removeEventListener("message", handleAgedPipePopupMessage);
|
||||
}, [agedPipeTotalCount, focusMapToAgedPipeCtpv, handleAgedPipeRowDoubleClick, handlePipeAnalysisRowSelect]);
|
||||
}, [agedPipeTotalCount, handleAgedPipeRowDoubleClick, handlePipeAnalysisRowSelect]);
|
||||
|
||||
// WaterDepth 표시 여부를 결정하는 함수
|
||||
const handleWaterDepthVisibility = useCallback((checkedIds: string[], checkedNodesData: any[]) => {
|
||||
@@ -1311,7 +1236,7 @@ const Map = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="bg-container relative h-[calc(100dvh-5rem)] overflow-hidden">
|
||||
<div className="sn-map-control-layout bg-container relative h-[calc(100dvh-5rem)] overflow-hidden">
|
||||
{layerLoadError ? (
|
||||
<div className="absolute left-4 top-4 z-[60] max-w-[520px] rounded border border-red-200 bg-white px-4 py-3 text-sm text-red-700 shadow">
|
||||
레이어 설정 조회 실패: {layerLoadError}
|
||||
@@ -1322,7 +1247,10 @@ const Map = () => {
|
||||
{agedPipeDownloadProgressText}
|
||||
</div>
|
||||
) : null}
|
||||
<AnalysisPopupMenu onOpenPopup={openAnalysisPopup} />
|
||||
<AnalysisPopupMenu
|
||||
onOpenPopup={openAnalysisPopup}
|
||||
onOpenInfoSearch={() => setIsSearchModalOpen(true)}
|
||||
/>
|
||||
<Gis
|
||||
treeData={treeData}
|
||||
isSearch={true}
|
||||
@@ -1339,7 +1267,13 @@ const Map = () => {
|
||||
setIsSearchModalOpen={setIsSearchModalOpen}
|
||||
onCheckedLayersChange={handleCheckedLayersChange}
|
||||
onOpenPopup={handleOpenLayerPopup}
|
||||
searchBar={<ProcSearchBar gisMaps={gisMaps} facilityTypes={facilityTypes} />}
|
||||
searchBar={
|
||||
<ProcSearchBar
|
||||
gisMaps={gisMaps}
|
||||
facilityTypes={facilityTypes}
|
||||
sidoSearchZoom={isAgedPipeChecked ? AGED_PIPE_GUIDE_MIN_ZOOM : undefined}
|
||||
/>
|
||||
}
|
||||
waterDepth={showWaterDepth ? WaterDepth : undefined}
|
||||
inlineLayerSettingView={inlineLayerSettingView}
|
||||
layerIconVisible={isAgedPipeLayerNode}
|
||||
@@ -1349,6 +1283,17 @@ const Map = () => {
|
||||
checkInterval={2500}
|
||||
checkedLayerChangeDelay={0}
|
||||
showZoomLevel={true}
|
||||
showZoomScaleInfo={true}
|
||||
showFloatingSearchButton={false}
|
||||
treeTogglePosition="top"
|
||||
zoomGuide={
|
||||
isAgedPipeChecked
|
||||
? {
|
||||
label: "노후관로 기준",
|
||||
zoom: AGED_PIPE_GUIDE_MIN_ZOOM,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
|
||||
defaultZoom={7.5}
|
||||
defaultLonLat={[127.75, 36]}
|
||||
@@ -1385,6 +1330,37 @@ const Map = () => {
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<style jsx global>{`
|
||||
.sn-map-control-layout .mapbtn {
|
||||
top: auto;
|
||||
right: 15px;
|
||||
bottom: 451px;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .custom-toolbar {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .tool-bar {
|
||||
top: auto;
|
||||
right: 15px;
|
||||
bottom: 248px;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .zoom-level-control {
|
||||
right: 16px;
|
||||
bottom: 56px;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .zoom-level-summary {
|
||||
right: 56px;
|
||||
bottom: -15px;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .ol-scale-line {
|
||||
display: none;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useGisContext } from './Gis';
|
||||
|
||||
export default React.memo(function GisZoomLevel() {
|
||||
const DPI = 25.4 / 0.28;
|
||||
const INCHES_PER_METER = 39.37;
|
||||
|
||||
const formatScaleValue = scale => {
|
||||
if (!Number.isFinite(scale) || scale <= 0) return '-';
|
||||
return `1:${Math.round(scale).toLocaleString()}`;
|
||||
};
|
||||
|
||||
export default React.memo(function GisZoomLevel({ zoomGuide, showZoomScaleInfo = false }) {
|
||||
const { gisMap } = useGisContext();
|
||||
const trackRef = useRef(null);
|
||||
const [zoomInfo, setZoomInfo] = useState({
|
||||
zoom: 0,
|
||||
minZoom: 0,
|
||||
maxZoom: 0,
|
||||
scale: 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -17,10 +26,16 @@ export default React.memo(function GisZoomLevel() {
|
||||
if (!view) return undefined;
|
||||
|
||||
const updateZoomInfo = () => {
|
||||
const resolution = view.getResolution?.() ?? 0;
|
||||
const projection = view.getProjection?.();
|
||||
const metersPerUnit = projection?.getMetersPerUnit?.() ?? 1;
|
||||
const scale = resolution * metersPerUnit * INCHES_PER_METER * DPI;
|
||||
|
||||
setZoomInfo({
|
||||
zoom: view.getZoom() ?? 0,
|
||||
minZoom: view.getMinZoom?.() ?? 0,
|
||||
maxZoom: view.getMaxZoom?.() ?? 20,
|
||||
scale,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -34,11 +49,30 @@ export default React.memo(function GisZoomLevel() {
|
||||
|
||||
if (!gisMap) return <></>;
|
||||
|
||||
const { zoom, minZoom, maxZoom } = zoomInfo;
|
||||
const { zoom, minZoom, maxZoom, scale } = zoomInfo;
|
||||
const range = Math.max(maxZoom - minZoom, 1);
|
||||
const normalized = Math.min(Math.max((zoom - minZoom) / range, 0), 1);
|
||||
const fillHeight = `${normalized * 100}%`;
|
||||
const thumbBottom = `calc(${fillHeight} - 1px)`;
|
||||
const guideZoom = Number(zoomGuide?.zoom);
|
||||
const hasGuide =
|
||||
Boolean(zoomGuide?.label) &&
|
||||
Number.isFinite(guideZoom) &&
|
||||
zoomGuide?.visible !== false;
|
||||
const guideNormalized = hasGuide
|
||||
? Math.min(Math.max((guideZoom - minZoom) / range, 0), 1)
|
||||
: 0;
|
||||
const guideBottom = `calc(${guideNormalized * 100}% - 1px)`;
|
||||
const isGuideActive = hasGuide ? zoom >= guideZoom : false;
|
||||
const titleParts = [`현재 줌 레벨 ${zoom.toFixed(1)}`];
|
||||
|
||||
if (hasGuide) {
|
||||
titleParts.push(
|
||||
`${zoomGuide.label} 줌 ${guideZoom}${isGuideActive ? ' 이상' : ' 미만'}`,
|
||||
);
|
||||
}
|
||||
|
||||
const controlTitle = titleParts.join(' / ');
|
||||
|
||||
const updateZoomFromClientY = clientY => {
|
||||
if (!gisMap || !trackRef.current) return;
|
||||
@@ -89,7 +123,22 @@ export default React.memo(function GisZoomLevel() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="zoom-level-control" title={`현재 줌 레벨 ${zoom.toFixed(1)}`}>
|
||||
<div
|
||||
className={`zoom-level-control ${hasGuide ? 'has-zoom-guide' : ''}`}
|
||||
title={controlTitle}
|
||||
>
|
||||
{showZoomScaleInfo && (
|
||||
<div className="zoom-level-summary" aria-live="polite">
|
||||
<div className="zoom-level-summary-row">
|
||||
<span className="zoom-level-summary-label">줌레벨</span>
|
||||
<span className="zoom-level-summary-value">{zoom.toFixed(1)}</span>
|
||||
</div>
|
||||
<div className="zoom-level-summary-row">
|
||||
<span className="zoom-level-summary-label">축척</span>
|
||||
<span className="zoom-level-summary-value">{formatScaleValue(scale)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="zoom-level-panel">
|
||||
<button type="button" className="zoom-level-btn" onClick={zoomIn} aria-label="확대">
|
||||
+
|
||||
@@ -100,6 +149,16 @@ export default React.memo(function GisZoomLevel() {
|
||||
className="zoom-level-track"
|
||||
onPointerDown={handleTrackPointerDown}
|
||||
>
|
||||
{hasGuide && (
|
||||
<div
|
||||
className={`zoom-level-guide ${isGuideActive ? 'is-active' : 'is-inactive'}`}
|
||||
style={{ bottom: guideBottom }}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span className="zoom-level-guide-label">{zoomGuide.label}</span>
|
||||
<span className="zoom-level-guide-dot" />
|
||||
</div>
|
||||
)}
|
||||
<div className="zoom-level-fill" style={{ height: fillHeight }} />
|
||||
<div className="zoom-level-thumb" style={{ bottom: thumbBottom }} />
|
||||
</div>
|
||||
|
||||
@@ -180,8 +180,44 @@
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.zoom-level-summary {
|
||||
position: absolute;
|
||||
right: 56px;
|
||||
bottom: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
min-width: 126px;
|
||||
padding: 7px 10px;
|
||||
border: 1px solid #9aa7b8;
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
box-shadow: 0 0 5px #999;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.zoom-level-summary-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.zoom-level-summary-label {
|
||||
font-weight: 700;
|
||||
color: #1d4f91;
|
||||
}
|
||||
|
||||
.zoom-level-summary-value {
|
||||
font-weight: 600;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.zoom-level-panel {
|
||||
overflow: hidden;
|
||||
overflow: visible;
|
||||
width: 40px;
|
||||
background: #fff;
|
||||
border: 1px solid #9aa7b8;
|
||||
@@ -217,12 +253,14 @@
|
||||
}
|
||||
|
||||
.zoom-level-gauge {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 128px;
|
||||
background: #fff;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.zoom-level-track {
|
||||
@@ -232,6 +270,7 @@
|
||||
border-radius: 6px;
|
||||
cursor: ns-resize;
|
||||
touch-action: none;
|
||||
overflow: visible;
|
||||
background:
|
||||
linear-gradient(to top, #b8b8b8, #b8b8b8) center / 4px 100% no-repeat,
|
||||
repeating-linear-gradient(
|
||||
@@ -267,6 +306,61 @@
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.zoom-level-guide {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transform: translate(calc(-100% - 10px), 50%);
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.zoom-level-guide::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: -10px;
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
background: currentColor;
|
||||
transform: translateY(-50%);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.zoom-level-guide-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 20px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid currentColor;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.12);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.zoom-level-guide-dot {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 999px;
|
||||
background: currentColor;
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.94);
|
||||
}
|
||||
|
||||
.zoom-level-guide.is-active {
|
||||
color: #d9363e;
|
||||
}
|
||||
|
||||
.zoom-level-guide.is-inactive {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.ol-scale-line {
|
||||
background: rgba(0, 60, 136, 0.3);
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -16,13 +16,18 @@ const FACILITY_TYPE_URL_MAP: Record<string, string> = {
|
||||
interface SearchBarProps {
|
||||
gisMaps: React.RefObject<any>;
|
||||
facilityTypes: { text: string; val: string }[];
|
||||
sidoSearchZoom?: number;
|
||||
}
|
||||
|
||||
interface CenterSelectDataType extends SelectDataType {
|
||||
center?: [number, number]; // 좌표 중심 위치
|
||||
}
|
||||
|
||||
export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => {
|
||||
export const ProcSearchBar = ({
|
||||
gisMaps,
|
||||
facilityTypes,
|
||||
sidoSearchZoom = 11,
|
||||
}: SearchBarProps) => {
|
||||
const [sidoValue, setSidoValue] = useState("0");
|
||||
const [sigunValue, setSigunValue] = useState("0");
|
||||
const [sidoData, setSidoData] = useState<CenterSelectDataType[]>([
|
||||
@@ -271,8 +276,8 @@ export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => {
|
||||
}
|
||||
}
|
||||
|
||||
moveMapToCenter(gisMaps, selectedSido.center, 11);
|
||||
}, [gisMaps, sidoValue, sigunValue, sidoData, filteredSigunData, sigunData]);
|
||||
moveMapToCenter(gisMaps, selectedSido.center, sidoSearchZoom);
|
||||
}, [gisMaps, sidoValue, sigunValue, sidoData, filteredSigunData, sigunData, sidoSearchZoom]);
|
||||
|
||||
const handleFeatureFocus = (data: any) => {
|
||||
const map = gisMaps.current;
|
||||
|
||||
Reference in New Issue
Block a user