diff --git a/packages/common/business_components/src/ui/map/lib/gis.layer.js b/packages/common/business_components/src/ui/map/lib/gis.layer.js index f8fdb2a24..9a7ffe55b 100644 --- a/packages/common/business_components/src/ui/map/lib/gis.layer.js +++ b/packages/common/business_components/src/ui/map/lib/gis.layer.js @@ -688,6 +688,111 @@ GisOlLayer.prototype = { }); return source; + }, + /** + * 여러 개의 검색 결과를 GeoJSON으로 표시 + * @param {string} lyrTyNm 레이어 타입명 + * @param {Array|string} featureIds 피처 ID 배열 또는 단일 ID + */ + showMultipleSearchResultsFromGeoJSON: function (lyrTyNm, featureIds) { + const layer = this.ensureSearchLayer(); + + const prev = layer.getSource(); + if (prev) prev.clear(true); + + const layerCode = GisApp.layerCode; + const matched = Object.values(layerCode).find(obj => obj.lyrTyNm === lyrTyNm); + layer.set("gobjTy", matched.gobjTy); + + const source = this.getMultiFeatureSourceFromGeoserver(lyrTyNm, featureIds); + + const onLoadEnd = async () => { + const feats = source.getFeatures(); + if (feats && feats.length > 0) { + const select = GisApp.Module.select; + await select.resetSelectedFeature(); + for (const feature of feats) select.selectMultiFeature(feature, true); + const geometries = feats.map(f => f.getGeometry()); + if (geometries.length > 0) { + const extent = this.combineExtents(geometries.map(g => g?.getExtent())); + + let map = GisApp.Module.core.map; + map.getView().fit(extent, { + duration: 300, + padding: [50, 50, 50, 50], + maxZoom: 16 + }); + } + } else { + console.warn('[search-layer] GeoJSON에 피처가 없습니다.'); + } + source.un('featuresloadend', onLoadEnd); + source.un('featuresloaderror', onLoadError); + }; + + const onLoadError = (e) => { + console.error('[search-layer] GeoJSON 로드 실패:', e); + source.un('featuresloadend', onLoadEnd); + source.un('featuresloaderror', onLoadError); + }; + + source.once('featuresloadend', onLoadEnd); + source.once('featuresloaderror', onLoadError); + + layer.setSource(source); + + source.refresh(); + }, + /** + * 피쳐 ID로 지오서버에서 검색해서 여러개 피처의 벡터소스를 리턴 + * @param {} lyrTyNm + * @param {*} featureId + * @returns + */ + getMultiFeatureSourceFromGeoserver: function (lyrTyNm, featureId) { + + const typeName = this.storageNm + lyrTyNm; + const srsName = GisApp.TO_PROJ; + const baseUrl = GisApp.GEOSERVER_URL; + + const ids = Array.isArray(featureId) ? featureId : [featureId]; + + const source = new VectorSource({ + format: new GeoJSON(), + url: () => { + const params = new URLSearchParams({ + SERVICE: 'WFS', + VERSION: '1.1.0', + REQUEST: 'GetFeature', + TYPENAME: typeName, + SRSNAME: srsName, + OUTPUTFORMAT: 'application/json', + FEATUREID: ids.join(','), + }); + return `${baseUrl}?${params.toString()}`; + }, + strategy: all, + }); + + return source; + }, + /** + * 여러 extent 배열을 받아 결합된 extent를 반환 + * @param {Array>} extents [[minX,minY,maxX,maxY], ...] + * @returns {Array|null} + */ + combineExtents: function (extents) { + if (!extents || extents.length === 0) return null; + let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; + for (const e of extents) { + if (!e || e.length < 4) continue; + minX = Math.min(minX, e[0]); + minY = Math.min(minY, e[1]); + maxX = Math.max(maxX, e[2]); + maxY = Math.max(maxY, e[3]); + } + if (!isFinite(minX) || !isFinite(minY) || !isFinite(maxX) || !isFinite(maxY)) return null; + return [minX, minY, maxX, maxY]; } };