feat:
- 여러 개의 검색 결과를 GeoJSON으로 표시 함수 추가 - 피쳐 ID로 지오서버에서 검색해서 여러개 피처의 벡터소스 리턴하는 함수 추가 - 여러 extent 배열을 받아 중앙값 extent를 반환하는 함수 추가
This commit is contained in:
@@ -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];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user