Files
frontend/packages/common/business_components/src/ui/map/lib/gis.select.js
T
swcho 49c475709f feat:
- 시설 검색, 다중 시설 검색 시 이전 검색 시설 레이어 삭제 기능 추가
- 시설 위치 정보 없을 때 alert 추가
- 시설 검색 시 해당 시설 아이콘 이미지 표출
2025-08-28 17:11:35 +09:00

449 lines
11 KiB
JavaScript

import GisApp from './gis.core';
import Style from 'ol/style/Style.js';
import { click, mouseOnly, never } from 'ol/events/condition';
import DragBox from 'ol/interaction/DragBox.js';
import Draw from 'ol/interaction/Draw.js';
import Select from 'ol/interaction/Select.js';
import VectorLayer from 'ol/layer/Vector.js';
import Overlay from 'ol/Overlay.js';
import VectorSource from 'ol/source/Vector.js';
import CircleStyle from 'ol/style/Circle.js';
import Fill from 'ol/style/Fill.js';
import Stroke from 'ol/style/Stroke.js';
const GisOlSelect = function (map, options) {
GisApp.select = {};
GisApp.select.helpTooltipElement = null;
GisApp.select.helpTooltip = null;
GisApp.select.helpMsg = null;
this.initialize(map, options);
};
GisOlSelect.prototype = {
map: null,
defaults: {
hitTolerance: 10,
useAreaControl: false,
},
selectInteraction: null,
dragBox: null,
dragPolygon: null,
selectedFeatures: [],
selectFeatureFlag: false,
initialize: function (map, options) {
this.map = map;
Object.assign(this.defaults, options);
this.setInteraction();
this.pointerMoveEventHandler();
},
/**
* SELECT 이벤트 등록
*/
setInteraction: function () {
let me = this;
let map = this.map;
if (this.selectInteraction) {
this.removeInteration();
}
let baseStyle = new Style({
image : new CircleStyle({
fill : new Fill({
color : 'rgba(135, 116, 243, 0.4)',
}),
radius : 30
}),
stroke : new Stroke({
color : 'rgba(135, 116, 243, 0.4)',
width : 10,
})
});
this.selectInteraction = new Select({
style: function (feature, resolution) {
let styles = [];
let layer = feature.getLayer();
let styleFn = GisApp.Module.style.getLayerStyleFunction(layer, null);
if (styleFn) {
const style = styleFn(feature, resolution);
if (Array.isArray(style)) {
styles.push(...style);
} else {
styles.push(style);
}
}
styles.push(baseStyle);
return styles;
},
layers: function (layer) {
let clickPsblYn = layer?.get('clickPsblYn');
return clickPsblYn === 'Y';
},
condition: click,
hitTolerance: me.defaults.hitTolerance,
});
map.addInteraction(this.selectInteraction);
this.selectedFeatures = this.selectInteraction.getFeatures();
// 선택된 피처 중심으로 지도 이동
this.selectInteraction.on('select', function (e) {
const feature = e.selected[0];
if (feature) {
const geometry = feature.getGeometry();
if (geometry) {
const extent = geometry.getExtent();
map.getView().fit(extent, {
duration: 300,
padding: [50, 50, 50, 50],
maxZoom: 16
});
}
}
});
},
/**
* SELECT 피처 초기화
*/
reset: function () {
let me = this;
if (GisApp.Module.edit) {
GisApp.Module.edit.setDrawActive(false);
}
if (GisApp.Module.draw) {
GisApp.Module.draw.setDrawActive(false);
}
me.setActive(true);
me.removeHelpTooltip();
let map = this.map;
map.removeInteraction(me.dragBox);
map.removeInteraction(me.dragPolygon);
this.selectInteraction.addCondition_ = never;
this.selectFeatureFlag = false;
if (GisApp.Module.measure) {
GisApp.Module.measure.removeFeature();
GisApp.Module.core.deleteOverlay('measure');
}
GisApp.Module.core.deleteLayer(GisApp.hLayerId);
GisApp.Module.core.deleteLayer(GisApp.hlLayerId);
this.resetSelectedFeature();
},
/**
* 단일 SELECT 이벤트 등록
*/
setSingleInteration: function () {
this.reset();
this.selectInteraction.addCondition_ = click;
this.selectFeatureFlag = true;
},
/**
* 박스 SELECT 이벤트 등록
*/
setBoxInteration: function () {
//초기화
this.reset();
this.selectFeatureFlag = true;
let me = this;
let map = this.map;
me.dragBox = new DragBox({
condition: mouseOnly,
});
map.addInteraction(this.dragBox);
GisApp.select.helpMsg = '직사각형 시작점을 클릭하고 드래그하세요.';
me.createHelpTooltip();
me.dragBox.on('boxend', function () {
let rotation = map.getView().getRotation();
let oblique = rotation % (Math.PI / 2) !== 0;
let candidateFeatures = oblique ? [] : me.selectedFeatures;
let extent = me.dragBox.getGeometry().getExtent();
let layers = map.getLayers();
for (let i in layers.array_) {
let layer = layers.array_[i];
if (layer?.get('clickPsblYn') == 'Y' && me.getVisible(layer)) {
layer.getSource().forEachFeatureIntersectingExtent(extent, function (feature) {
candidateFeatures.push(feature);
});
}
}
if (oblique) {
let anchor = [0, 0];
let geometry = me.dragBox.getGeometry().clone();
geometry.rotate(-rotation, anchor);
let extent$1 = geometry.getExtent();
candidateFeatures.forEach(function (feature) {
let geometry = feature.getGeometry().clone();
geometry.rotate(-rotation, anchor);
if (geometry.intersectsExtent(extent$1)) {
me.selectedFeatures.push(feature);
}
});
}
me.selectInteraction.dispatchEvent({
type: 'select',
selected: me.selectedFeatures,
deselected: [],
});
map.removeInteraction(me.dragBox);
});
me.dragBox.on('boxstart', function () {
me.removeHelpTooltip();
me.selectedFeatures.clear();
});
},
/**
* 폴리곤 SELECT 이벤트 등록
*/
setPolygonInteration: function () {
this.reset();
this.selectFeatureFlag = true;
let me = this;
let map = this.map;
//폴리곤 레이어 생성
let polygonSource = new VectorSource({
useSpatialIndex: false,
});
let polygonLayer = new VectorLayer({
source: polygonSource,
});
map.addLayer(polygonLayer);
//폴리곤 draw 객체 생성
me.dragPolygon = new Draw({
source: polygonSource,
type: 'Polygon',
condition: mouseOnly,
});
map.addInteraction(me.dragPolygon);
//툴팁 추가
GisApp.select.helpMsg = '시작점을 클릭하세요.';
me.createHelpTooltip();
me.dragPolygon.on('drawstart', function () {
me.removeHelpTooltip();
me.selectedFeatures.clear();
});
me.dragPolygon.on('drawend', function (evt) {
setTimeout(function () {
let polygon = evt.feature.getGeometry();
let layers = map.getLayers();
for (let i in layers.array_) {
let layer = layers.array_[i];
if (layer?.get('clickPsblYn') == 'Y' && me.getVisible(layer)) {
let features = layer.getSource().getFeatures();
for (let j = 0; j < features.length; j++) {
if (polygon.intersectsExtent(features[j].getGeometry().getExtent())) {
me.selectedFeatures.push(features[j]);
}
}
}
}
me.selectInteraction.dispatchEvent({
type: 'select',
selected: me.selectedFeatures,
deselected: [],
});
map.removeInteraction(me.dragPolygon);
map.removeLayer(polygonLayer);
}, 300);
});
return me.dragPolygon;
},
/**
* 레이어 추가
*/
addLayer: function (layer) {
if (layer) {
layer.set('clickPsblYn', 'Y');
}
},
/**
* 레이어 삭제
*/
removeLayer: function (layer) {
if (layer) {
layer.set('clickPsblYn', 'N');
}
},
/**
* 선택된 객체 초기화
*/
resetSelectedFeature: function () {
const selectedFeatures = this.selectedFeatures;
selectedFeatures.forEach(feature => {
selectedFeatures.remove(feature);
});
selectedFeatures.clear();
},
/**
* SELECT 이벤트 활성화
*/
setActive: function (active) {
this.selectInteraction.setActive(active);
},
/**
* SELECT 이벤트 삭제
*/
removeInteration: function () {
let map = this.map;
map.removeInteraction(this.selectInteraction);
this.selectInteraction = null;
//포인터 변경 삭제
this.removePointerMoveEventHandler('pointerMoveForSelect');
},
/**
* 피처 위에 마우스 오버시 포인터 변경
*/
pointerMoveEventHandler: function () {
let me = this;
let map = this.map;
let pointerMoveForSelect = function (evt) {
let hit = this.forEachFeatureAtPixel(
evt.pixel,
function (feature, layer) {
let returnFlag = true;
if (layer?.get('clickPsblYn') === 'N') {
returnFlag = false;
}
return returnFlag;
},
{ hitTolerance: me.defaults.hitTolerance }
);
if (hit && me.selectInteraction.getActive()) {
this.getTargetElement().style.cursor = 'pointer';
} else {
this.getTargetElement().style.cursor = '';
}
};
map.on('pointermove', pointerMoveForSelect);
},
/**
* 포인터 이벤트 삭제
*/
removePointerMoveEventHandler: function (fnNm) {
GisApp.Module.core.removeMapEventFnNm('pointermove', fnNm);
},
/**
* 선택된 피처 정보 반환(callback)
*/
getSelectedInfo: function (callback) {
let me = this;
this.selectInteraction.on('select', function (e) {
if (!e.auto) {
let features = me.selectInteraction.getFeatures();
if(features.getArray().length == 0) return;
let layers = [];
for (let i in features.array_) {
let feature = features.array_[0];
let layer = me.selectInteraction.getLayer(feature);
layers.push(layer);
}
callback(features.array_, layers);
}
});
},
/**
* 선택된 피처 정보 반환
*/
getSelectedFeatures: function () {
return this.selectInteraction.getFeatures();
},
/**
* 마지막으로 선택된 피처 정보 반환
*/
getLastSelectedFeatures: function () {
return this.selectInteraction.getFeatures();
},
/**
* 툴팁 생성
*/
createHelpTooltip: function () {
let me = this;
let map = this.map;
GisApp.select.helpTooltipElement = document.createElement('div');
GisApp.select.helpTooltipElement.className = 'ol-tooltip hidden';
GisApp.select.helpTooltip = new Overlay({
element: GisApp.select.helpTooltipElement,
offset: [15, 0],
positioning: 'center-left',
});
map.addOverlay(GisApp.select.helpTooltip);
map.on('pointermove', me.pointerMoveTooltipHandler);
},
/**
* 툴팁 삭제
*/
removeHelpTooltip: function () {
if (GisApp.select.helpTooltipElement) {
let map = this.map;
this.removePointerMoveEventHandler('pointerMoveTooltipHandler');
map.removeOverlay(GisApp.measure.helpTooltip);
GisApp.select.helpTooltipElement.remove();
}
},
/**
* 툴팁용 포인터 move 이벤트
*/
pointerMoveTooltipHandler: function (evt) {
if (evt.dragging) {
return;
}
//GisApp.select.helpTooltipElement.innerHTML = DOMPurify.sanitize(GisApp.select.helpMsg);
GisApp.select.helpTooltipElement.innerHTML = GisApp.select.helpMsg;
GisApp.select.helpTooltip.setPosition(evt.coordinate);
GisApp.select.helpTooltipElement.classList.remove('hidden');
},
getVisible: function (layer) {
let maxZoom = layer.getMaxZoom();
let minZoom = layer.getMinZoom();
let map = this.map;
let curZoom = map.getView().getZoom();
if (layer.getVisible() && maxZoom > curZoom && minZoom < curZoom) {
return true;
}
return false;
},
/**
* 피처 셀렉트
*/
selectFeature: function (feature, auto) {
let me = this;
me.selectedFeatures.clear();
me.selectedFeatures.push(feature);
me.selectInteraction.dispatchEvent({
type: 'select',
selected: me.selectedFeatures,
deselected: [],
auto: auto,
});
},
/**
* 피처 다중 셀렉트
*/
selectMultiFeature: function (feature, auto) {
let me = this;
me.selectedFeatures.push(feature);
me.selectInteraction.dispatchEvent({
type: 'select',
selected: me.selectedFeatures,
deselected: [],
auto: auto,
});
},
};
export default GisOlSelect;