- 여러 개의 검색 결과를 GeoJSON으로 표시 함수 추가
- 피쳐 ID로 지오서버에서 검색해서 여러개 피처의 벡터소스 리턴하는 함수 추가
- 여러 extent 배열을 받아 중앙값 extent를 반환하는 함수 추가
This commit is contained in:
swcho
2025-08-20 18:50:08 +09:00
parent 4df286b086
commit ebfc520d67
@@ -569,14 +569,224 @@ GisOlLayer.prototype = {
cesiumScene.camera.moveEnd.addEventListener(cesiumScene._moveEndListener);
}
},
getFeatureById: function(featureId){
this.layers
.getArray()
.forEach(layer => {
const source = layer.getSource();
const feature = source.getFeatureById(String(featureId).trim());
if (feature) return feature;
});
getFeatureById: function (featureId) {
let returnFeature;
this.layers.getArray().some(function (layer) {
const source = layer.getSource();
if (source instanceof VectorSource) {
const feature = source.getFeatureById(featureId);
if (feature) {
returnFeature = feature;
return true;
}
}
});
return returnFeature;
},
getOpenLayersZoom: function (cesiumScene) {
const cameraHeight = cesiumScene.camera.positionCartographic.height;
const maxResolution = 156543.03392804097; // OpenLayers 기본 해상도 (Google Mercator 기준)
const tileSize = 256; // 기본 타일 크기
return Math.ceil(Math.log2(maxResolution / (cameraHeight / tileSize)));
},
ensureSearchLayer: function () {
let layer = this.searchLayer;
if (!layer) {
layer = new VectorLayer({
source: new VectorSource(),
zIndex: 9999
});
let map = GisApp.Module.core.map;
map.addLayer(layer);
}
return layer;
},
clearSearchLayer: function () {
const layer = this.ensureSearchLayer();
layer.getSource().clear(true);
},
showSearchResultsFromGeoJSON: function (lyrTyNm, featureId) {
const layer = this.ensureSearchLayer();
// 이전 검색결과는 깨끗이
const prev = layer.getSource();
if (prev) prev.clear(true);
//레이어 타입 설정(point, line 등. 이걸 style에서 사용)
const layerCode = GisApp.layerCode;
const matched = Object.values(layerCode).find(obj => obj.lyrTyNm === lyrTyNm);
layer.set("gobjTy", matched.gobjTy);
// 새 소스 만들기
const source = this.getFeatureSourceFromGeoserver(lyrTyNm, featureId);
// 1) 로드 완료시 extent 맞추기
const onLoadEnd = () => {
const feats = source.getFeatures();
if (feats && feats.length > 0) {
const select = GisApp.Module.select;
select.selectFeature(feats[0], false);
} 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);
};
// 이벤트를 먼저 걸고 → setSource
source.once('featuresloadend', onLoadEnd);
source.once('featuresloaderror', onLoadError);
// 레이어에 소스 적용(이때부터 로딩 시작)
layer.setSource(source);
// 필요시 명시적으로 재요청
source.refresh();
},
/**
* 피쳐 ID로 지오서버에서 검색해서 피처의 벡터소스를 리턴
* @param {} lyrTyNm
* @param {*} featureId
* @returns
*/
getFeatureSourceFromGeoserver: function (lyrTyNm, featureId) {
const typeName = this.storageNm + lyrTyNm;
const srsName = GisApp.TO_PROJ;
const baseUrl = GisApp.GEOSERVER_URL;
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: featureId,
});
return `${baseUrl}?${params.toString()}`;
},
strategy: all,
});
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<Array<number>>} extents [[minX,minY,maxX,maxY], ...]
* @returns {Array<number>|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];
}
};