From b8c26b33ac3f4909562f1f6a9eb1cc767484e51e Mon Sep 17 00:00:00 2001 From: thkim Date: Tue, 25 Nov 2025 11:10:07 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B8=89=EA=B2=BD=EC=82=AC=EC=A7=80=20?= =?UTF-8?q?feature=20=EC=A0=95=EB=B3=B4=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/webapp/js/map/main/map.js | 178 +++++++++++++++++++++++++---- 1 file changed, 155 insertions(+), 23 deletions(-) diff --git a/src/main/webapp/js/map/main/map.js b/src/main/webapp/js/map/main/map.js index 96b4e700..a4d93998 100644 --- a/src/main/webapp/js/map/main/map.js +++ b/src/main/webapp/js/map/main/map.js @@ -358,6 +358,8 @@ var MINERAL_LAYER; // 광물 레이어 var MINE_LAYER; // 광산 레이어 var WELL_LAYER; // 관정 레이어 var STEEP_SLOPE_LAYER; // 급경사지 레이어 +var CTL_SELECT_SLOPE; // 급경사지 선택 + var HOLE_SELECT; // 시추공 선택 var HOLE_SELECT2; // 3d지반 var HOLE_AREA; // 영역 선택 @@ -1145,6 +1147,21 @@ function initApp(param){ }); CTL_SELECT.events.register("getfeatureinfo", CTL_SELECT, addHole); BASE_MAP.addControl(CTL_SELECT); + + + // 급경사지 선택 컨트롤 생성 + // 급경사지 레이어 전용 컨트롤을 별도로 만듭니다. + CTL_SELECT_SLOPE = new OpenLayers.Control.WMSGetFeatureInfo({ + url: O2MAP_URL, + crs: "EPSG:3857", + infoFormat: "application/json", + layers: [STEEP_SLOPE_LAYER], + queryVisible: true, + maxFeatures: 1 + }); + // 급경사지 정보를 처리할 콜백 함수(addSteepSlope)를 등록합니다. + CTL_SELECT_SLOPE.events.register("getfeatureinfo", CTL_SELECT_SLOPE, addSteepSlope); + BASE_MAP.addControl(CTL_SELECT_SLOPE); HOLE_SELECT2 = new OpenLayers.Layer.Vector("SELECT"); @@ -2722,15 +2739,20 @@ function isSelectHole(){ function onSelectHole(){ - offSelectHole(); + offSelectHole(); // 모든 컨트롤 초기화 (initControl 호출됨) - CTL_TOOLTIP.deactivate(); - CTL_SELECT.activate(); + CTL_TOOLTIP.deactivate(); + CTL_SELECT.activate(); // 기본 시추공 선택 활성화 - CTL_INFO.setText("선택 모드"); - CTL_INFO.activate(); - $("#CTL_INFO").css("bottom","65px"); - $("#CTL_INFO").css("left","20px"); + // 컨트롤이 초기화되었으므로, 급경사지 레이어가 눈에 보인다면 다시 선택 기능을 켜줍니다. + if (STEEP_SLOPE_LAYER && STEEP_SLOPE_LAYER.getVisibility()) { + if (CTL_SELECT_SLOPE) CTL_SELECT_SLOPE.activate(); + } + + CTL_INFO.setText("선택 모드"); + CTL_INFO.activate(); + $("#CTL_INFO").css("bottom","65px"); + $("#CTL_INFO").css("left","20px"); } @@ -2779,6 +2801,112 @@ function addHole(evt){ } +//급경사지 선택 시 호출될 콜백 함수 (팝업 표시) +function addSteepSlope(evt){ + if (evt.text.length > 50) { + // 1. 서버 응답(JSON) 파싱 + var values = JSON.parse(evt.text); + + if(values.features && values.features.length > 0) { + var feature = values.features[0]; + var props = feature.properties; + + // 2. 팝업을 띄울 위치 계산 (클릭한 지점) + // evt.xy는 화면 픽셀 좌표이므로 지도 좌표(LonLat)로 변환합니다. + var lonlat = BASE_MAP.getLonLatFromPixel(evt.xy); + + // 기존 팝업 제거 + removeTooltip(); + + // 3. 컬럼명 -> 한글 주석 매핑 객체 정의 + var colLabels = { + "GID": "고유번호", "MNGNO": "관리번호", "DISTRICTNM": "지구명", + "MNGORG": "관리기관", "MNGDEPT": "관리부서", "MNGTYPE": "관리주체", + "SIDO": "시도", "SGG": "시군구", "EMD": "읍면동", "LI": "리", "BUNJI": "지번", "JIMOK": "지목", + "AREAM2": "지정면적(㎡)", "AREACODE": "구역코드", + "SLATI": "시점 위도", "SLONG": "시점 경도", "ELATI": "종점 위도", "ELONG": "종점 경도", + "USETYPE": "토지이용현황", "SLOPETYPE": "사면유형", "STRUCTTYPE": "구조물유형", + "MAXHEIGHT": "최대수직고(m)", "JDLENGTH": "연장(m)", "AVGSLOPE": "평균경사(°)", "AVGSLOPEDO": "평균경사도", + "SLOPESHAPE": "사면형상", "WATERSOUR": "용출수", "CEILDITCH": "산마루측구", "COLLAPSEHIS": "붕괴이력", + "CONSTYEAR": "설치년도", "CONSTRUCTOR": "시공자", "SOILSLOPE": "토사상태", + "WALLCONCRE": "콘크리트옹벽", "WALLSTONE": "석축/개비온", "BEDROCK": "암반상태", + "TREEDENS": "식생(교목)", "PLANTDENS": "식생(관목)", "EXTFORCE": "외력인자", + "VDISTDNSTREAM": "하류거리(m)", "VDISTPUBLIC": "공공시설거리(m)", "VDISTNAME": "피해예상시설명", + "VDISTRIVER": "하천거리(m)", "VICTBUILDD": "피해예상건물", "VICTFARM": "피해예상농경지", "VICTROAD": "피해예상도로", + "ASSTOPO": "인접지형", "ASSDIST": "인접거리(m)", "ASSRATE": "인접등급/하천", + "ISSAFETY": "안전성여부", "EMERMEA": "응급대책", "REPAIRPLAN": "보수보강계획", + "NEEDMEAS": "계측필요여부", "REASONMEAS": "계측사유", "RISKRATE": "위험등급", "EVALSCORE": "평가점수", + "MNGDT": "관리일자", "MAINTYEAR": "정비년도", "MAINTDETAILS": "정비내역", + "INVESTDEPT": "조사부서", "INVESTNAME": "조사자", "INVESTDT": "조사일자", + "EXPERTOPINION": "전문가의견", "REMARK": "비고" + }; + + // 4. 팝업 내용(HTML) 생성 + var tagStr = ""; + // 내용이 많으므로 스크롤 영역 생성 + tagStr += '
'; + tagStr += ''; + tagStr += ''; + tagStr += ''; // 항목명 너비 + tagStr += ''; // 값 너비 + tagStr += ''; + tagStr += ''; + + // 제목 행 추가 (선택사항) + tagStr += ''; + tagStr += ''; + tagStr += ''; + + for (var key in props) { + var value = props[key]; + if (value === null || value === "null") value = ""; + + // geometry 정보 등 불필요한 시스템 컬럼은 제외하고 싶으면 여기서 if문으로 필터링 가능 + + var label = colLabels[key] ? colLabels[key] : key; + + tagStr += ''; + tagStr += ''; + tagStr += ''; + tagStr += ''; + } + + tagStr += ''; + tagStr += '
급경사지 상세 정보
' + label + '' + value + '
'; + tagStr += '
'; + + // 5. OpenLayers 팝업 객체 생성 + POPUP_TOOLTIP = new OpenLayers.Popup.FramedCloud( + "SteepSlopeTooltip", // 팝업 ID + lonlat, // 팝업 위치 (클릭 지점) + new OpenLayers.Size(350, 350), // 팝업 크기 (자동조절되나 초기값 설정) + tagStr, // HTML 내용 + null, // Anchor (null이면 자동) + true, // 닫기 버튼 표시 여부 + removeTooltip // 닫기 버튼 콜백 + ); + + // 6. 지도에 팝업 추가 + BASE_MAP.addPopup(POPUP_TOOLTIP); + + // 7. CSS 및 스타일 조정 (닫기 버튼 위치 및 크기 고정) + // 닫기 버튼 위치 조정 + var closeBtn = $("#SteepSlopeTooltip_close"); + if(closeBtn.length > 0 && $("#SteepSlopeTooltip_FrameDecorationDiv_0").length > 0) { + closeBtn.css("top", $("#SteepSlopeTooltip_FrameDecorationDiv_0").css("top")); + closeBtn.css("right", "25px"); + } + + // 전체 팝업 크기 및 스크롤 영역 조정 + $("#SteepSlopeTooltip").css("width", "360px"); + $("#SteepSlopeTooltip").css("height", "340px"); + $("#SteepSlopeTooltip_contentDiv").css("width", "340px"); + $("#SteepSlopeTooltip_contentDiv").css("height", "300px"); + $("#SteepSlopeTooltip_contentDiv").css("overflow", "hidden"); // 내부 스크롤만 사용 + } + } +} + function isSelectProject(){ return CTL_SELECT_PROJECT.active; } @@ -3704,6 +3832,7 @@ function initControl(){ HOLE_SELECT.removeAllFeatures(); HOLE_SELECT2.removeAllFeatures(); CTL_SELECT.deactivate(); + if(CTL_SELECT_SLOPE) CTL_SELECT_SLOPE.deactivate(); // 급경사지 선택 비활성화 CTL_SELECT_PROJECT.deactivate(); CTL_SELECT_JIBAN.deactivate(); CTL_TOOLTIP.activate(); @@ -5372,40 +5501,43 @@ function geologyWell() { //급경사지 버튼 눌렀을 때 호출됨. function geologySteepSlope() { - initControl(); // 다른 컨트롤 상태 초기화 - - // STEEP_SLOPE_LAYER 가 정상적으로 생성되었는지 확인 + if (!STEEP_SLOPE_LAYER) { console.error("급경사지 레이어가 초기화되지 않았습니다."); return; } - // 현재 레이어의 표시 상태를 가져옵니다. var isVisible = STEEP_SLOPE_LAYER.getVisibility(); - if (isVisible ) { - // 레이어가 현재 보이고 있다면, 숨깁니다. - STEEP_SLOPE_LAYER.setVisibility(false); + if (isVisible) { + // [OFF 처리] 레이어 숨김 -> 컨트롤 비활성화 + STEEP_SLOPE_LAYER.setVisibility(false); + + // 레이어가 안 보이므로 선택 기능도 끕니다. + if (CTL_SELECT_SLOPE) CTL_SELECT_SLOPE.deactivate(); + CTL_INFO.setText("급경사지 Off"); - CTL_INFO.deactivate(); // 정보창도 비활성화 + CTL_INFO.deactivate(); } else { + // [ON 처리] 레이어 표시 -> 컨트롤 활성화 (선택 모드 여부 상관없음) + STEEP_SLOPE_LAYER.setVisibility(true); + STEEP_SLOPE_LAYER.redraw(true); - // 레이어를 보이게 설정하고 강제로 다시 그립니다. - STEEP_SLOPE_LAYER.setVisibility(true); - STEEP_SLOPE_LAYER.redraw(true); + // 레이어가 보이면 무조건 선택 기능을 켭니다. + if (CTL_SELECT_SLOPE) { + CTL_SELECT_SLOPE.activate(); + } - // CTL_INFO의 infoDiv가 내부 요소를 absolute 포지셔닝할 수 있도록 'relative'로 설정 + // 정보창 표시 $(CTL_INFO.infoDiv).css("position", "relative"); - - // CTL_INFO 텍스트 설정 시 버튼 HTML을 함께 삽입 CTL_INFO.setText("급경사지 On"); CTL_INFO.activate(); $("#CTL_INFO").css("bottom", "65px"); $("#CTL_INFO").css("left", "20px"); - alert('급경사지 정보는 빨간색 선으로 보여집니다.'); + + alert('급경사지 정보는 빨간색 선으로 보여집니다.'); } - }