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;