From 9b77c34e58cbbe28d29cb7cc26133e229ef85025 Mon Sep 17 00:00:00 2001 From: thkim Date: Thu, 5 Mar 2026 10:30:32 +0900 Subject: [PATCH] . --- src/main/webapp/js/map/main/map.js | 233 +++++++++++++++++++---------- 1 file changed, 158 insertions(+), 75 deletions(-) diff --git a/src/main/webapp/js/map/main/map.js b/src/main/webapp/js/map/main/map.js index 802b336e..4b7add22 100644 --- a/src/main/webapp/js/map/main/map.js +++ b/src/main/webapp/js/map/main/map.js @@ -3796,115 +3796,198 @@ function addHole(evt){ hole.attributes.holeCode = hole.attributes.CODE; addHoleNames(hole); } - } //급경사지 선택 시 호출될 콜백 함수 (팝업 표시) -function addSteepSlope(evt){ +function addSteepSlope(evt) { if (evt.text.length > 50) { - // 1. 서버 응답(JSON) 파싱 var values = JSON.parse(evt.text); - if(values.features && values.features.length > 0) { + 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(); + 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": "비고" + "SIDO": "시도", "SGG": "시군구", "USETYPE": "토지이용", + "SLOPETYPE": "사면유형", "MAXHEIGHT": "최대높이(m)", "AVGSLOPE": "평균경사(°)", + "RISKRATE": "위험등급", "INVESTDT": "조사일자" }; - // 4. 팝업 내용(HTML) 생성 var tagStr = ""; - // 내용이 많으므로 스크롤 영역 생성 - tagStr += '
'; - tagStr += ''; - tagStr += ''; - tagStr += ''; // 항목명 너비 - 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 += ''; } - tagStr += ''; - tagStr += '
' + label + '' + value + '
' + label + '' + value + '
'; + tagStr += ' '; + tagStr += ' '; + tagStr += '
'; tagStr += ''; - // 5. OpenLayers 팝업 객체 생성 - POPUP_TOOLTIP = new OpenLayers.Popup.FramedCloud( - "SteepSlopeTooltip", // 팝업 ID - lonlat, // 팝업 위치 (클릭 지점) - new OpenLayers.Size(350, 350), // 팝업 크기 (자동조절되나 초기값 설정) - tagStr, // HTML 내용 - null, // Anchor (null이면 자동) - true, // 닫기 버튼 표시 여부 - removeTooltip // 닫기 버튼 콜백 + POPUP_TOOLTIP = new OpenLayers.Popup.Anchored( + "SteepSlopeTooltip", + lonlat, + new OpenLayers.Size(350, 300), + tagStr, + null, + true, + removeTooltip ); - // 6. 지도에 팝업 추가 + POPUP_TOOLTIP.div.style.border = "1px solid #004e99"; + POPUP_TOOLTIP.div.style.backgroundColor = "white"; + POPUP_TOOLTIP.div.style.padding = "0px"; + POPUP_TOOLTIP.div.style.overflow = "visible"; + POPUP_TOOLTIP.div.style.boxSizing = "border-box"; + 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"); + + if (window.ResizeObserver) { + var ro = new ResizeObserver(function(entries) { + for (var i = 0; i < entries.length; i++) { + var rect = entries[i].contentRect; + + // 1. 내부 레이어들 높이 100% 강제 동기화 (상단/우측 리사이즈 보정) + var groupDiv = document.getElementById("SteepSlopeTooltip_GroupDiv"); + if (groupDiv) groupDiv.style.setProperty("height", "100%", "important"); + + var contentDiv = document.getElementById("SteepSlopeTooltip_contentDiv"); + if (contentDiv) { + contentDiv.style.setProperty("height", "100%", "important"); + contentDiv.style.setProperty("width", "100%", "important"); + } + + // 2. 테이블 스크롤 영역 높이 조절 + var scrollable = document.getElementById("steepSlopePopupScrollable"); + if (scrollable && rect.height > 0) { + scrollable.style.setProperty("height", (rect.height - 32) + "px", "important"); + } + } + }); + ro.observe(POPUP_TOOLTIP.div); } + + (function() { + var target = POPUP_TOOLTIP.div; + var threshold = 15; + var isResizing = false; + var direction = ''; + var startX, startY, startW, startH, startL, startT; + var minW = 250, minH = 150; + + target.addEventListener('mousemove', function(e) { + if (isResizing) return; + var rect = target.getBoundingClientRect(); + var x = e.clientX - rect.left; + var y = e.clientY - rect.top; + + var onT = y >= 0 && y < threshold; + var onB = y > rect.height - threshold && y <= rect.height; + var onL = x >= 0 && x < threshold; + var onR = x > rect.width - threshold && x <= rect.width; + + direction = ''; + if (onT) direction += 'n'; + if (onB) direction += 's'; + if (onL) direction += 'w'; + if (onR) direction += 'e'; + + target.style.cursor = direction ? direction + '-resize' : ''; + }); + + target.addEventListener('mousedown', function(e) { + if (!target.style.cursor || target.style.cursor.indexOf('resize') === -1) return; + + isResizing = true; + // 리사이즈 중 지도 이동 차단 및 전파 중단 + if (e.stopImmediatePropagation) e.stopImmediatePropagation(); + e.preventDefault(); + + var rect = target.getBoundingClientRect(); + startX = e.clientX; startY = e.clientY; + startW = rect.width; startH = rect.height; + startL = parseInt(target.style.left, 10) || 0; + startT = parseInt(target.style.top, 10) || 0; + + var handleMouseMove = function(e) { + if (!isResizing) return; + var dx = e.clientX - startX; + var dy = e.clientY - startY; + + // 동쪽(우측) 리사이즈 시 important로 강제 업데이트 + if (direction.indexOf('e') > -1) { + target.style.setProperty("width", Math.max(minW, startW + dx) + "px", "important"); + } + if (direction.indexOf('s') > -1) { + target.style.setProperty("height", Math.max(minH, startH + dy) + "px", "important"); + } + if (direction.indexOf('w') > -1) { + var newW = startW - dx; + if (newW > minW) { + target.style.setProperty("width", newW + "px", "important"); + target.style.setProperty("left", (startL + dx) + "px", "important"); + } + } + // 북쪽(상단) 리사이즈 보정 + if (direction.indexOf('n') > -1) { + var newH = startH - dy; + if (newH > minH) { + target.style.setProperty("height", newH + "px", "important"); + target.style.setProperty("top", (startT + dy) + "px", "important"); + } + } + }; + + var handleMouseUp = function() { + isResizing = false; + document.removeEventListener('mousemove', handleMouseMove, true); + document.removeEventListener('mouseup', handleMouseUp, true); + }; + + document.addEventListener('mousemove', handleMouseMove, true); + document.addEventListener('mouseup', handleMouseUp, true); + }, true); + })(); + + dragControl = new OpenLayers.Control.DragPopup(POPUP_TOOLTIP); + var resizeTarget = POPUP_TOOLTIP.div; + var originalOnMouseDown = dragControl.onMouseDown; + + dragControl.onMouseDown = function(evt) { + if (resizeTarget.style.cursor && resizeTarget.style.cursor.indexOf('resize') > -1) { + if (evt.stopImmediatePropagation) evt.stopImmediatePropagation(); + return; + } + originalOnMouseDown.apply(this, arguments); + }; + + BASE_MAP.addControl(dragControl); + dragControl.activate(); - // 전체 팝업 크기 및 스크롤 영역 조정 - $("#SteepSlopeTooltip").css("width", "360px"); - $("#SteepSlopeTooltip").css("height", "340px"); - $("#SteepSlopeTooltip_contentDiv").css("width", "340px"); - $("#SteepSlopeTooltip_contentDiv").css("height", "300px"); - $("#SteepSlopeTooltip_contentDiv").css("overflow", "hidden"); // 내부 스크롤만 사용 + var closeBtn = document.getElementById("SteepSlopeTooltip_close"); + if (closeBtn) { + closeBtn.style.right = "8px"; + closeBtn.style.top = "6px"; + closeBtn.style.zIndex = "10005"; + } } } } + function isSelectProject(){ return CTL_SELECT_PROJECT.active; }