import Map from 'ol/Map.js'; import View from 'ol/View.js'; import { defaults as defaultControls } from 'ol/control.js'; // 工具类 import { getWidth, getTopLeft } from 'ol/extent.js'; import { get as getProjection } from 'ol/proj.js'; import GeoJSON from 'ol/format/GeoJSON'; import WMTSTileGrid from 'ol/tilegrid/WMTS.js'; // layer->source->feature->style // layer import { Vector as VectorLayer, Tile as TileLayer } from 'ol/layer'; // source import { WMTS } from 'ol/source'; import VectorSource from 'ol/source/Vector'; // import { // TileSuperMapRest // } from '@supermap/iclient-ol'; // feature import Feature from 'ol/Feature'; import { Point, Polygon, MultiPolygon, LineString } from 'ol/geom'; // style import { Icon, Style, Text, Fill, Stroke } from 'ol/style'; // 弹窗 import Overlay from 'ol/Overlay'; // 选择 import { Select } from 'ol/interaction'; export default class olMapClass { constructor() { this.popUp = [] //弹窗 this.mapLayers = {} //地图图层 this.layerSelect = {} //图层选择对象 this.center = [] //中心点 this.zoom = 13 } /** * @description 初始化地图 * @param {String} domId 地图容器 * @param {Array} center 中心点经纬度数组 */ initOlMap(domId, center, zoom) { this.center = center this.zoom = zoom window.olMap = new Map({ target: domId, view: new View({ projection: 'EPSG:4326', center: center, zoom: zoom, maxZoom: 22, minZoom: 1 }), controls: defaultControls({ zoom: false, rotate: false, attribution: false }) }); } /** * @description 回到原点 */ resetMap() { window.olMap.getView().setCenter(this.center) window.olMap.getView().setZoom(this.zoom) } /** * @description 销毁地图 */ destoryOlMap() { window.olMap && window.olMap.dispose(); window.olMap = null; } /** * @description 创建地图监听事件 * @param {String} type 监听事件类型 * @param {Function} callBack 执行函数 */ initOlMapEvent(type, callBack) { window.olMap.on(type, (event) => { callBack(event) }); } /** * @description 注销地图事件, handler必须是创建地图事件时的执行函数 * @param {String} type 监听事件类型 * @param {Function} handler 执行函数 */ destoryOlMapEvent(type, handler) { window.olMap.un(type, handler) } /** * @description 添加图层选择事件 * @param {Array} layers 需要选择的图层 * @param {String} id 创建的选择器id * @param {Function} getOption 生成marker配置的函数 * @param {Object} iconOption 图标的配置 * @param {Object} textOption 文字的配置 * @param {Function} callBack 执行函数 */ addLayerSelect(layers, id, getOption, callBack, falied) { let select = new Select({ layers: layers, style: (feature) => { let options = getOption(feature) feature.setStyle( new Style({ image: options.icon ? new Icon(options.icon) : null, text: options.text ? new Text(options.text) : null }) ) } }) this.layerSelect[id] = select window.olMap.addInteraction(select) // 选择事件 select.on('select', (evt) => { // 没选中则自动清除已选的feature if (evt.selected.length === 0) { select.getFeatures().clear() if (falied) falied() return } // 选中后执行后续操作 callBack(evt) }) } /** * @description 添加feature到选择器 * @param {String} selectId 选择器id * @param {Object} feature 要选择的feature */ _addFeatureToSelect(selectId, feature) { if (this.layerSelect[selectId]) { this.layerSelect[selectId].getFeatures().push(feature) } } /** * @description 从图层中查找对应的feature并添加到选择器 * @param {String} layerTypeName 图层大类名称 * @param {String} layerName 图层名称 * @param {String} featureId 图层中feature的内置id * @param {String} selectId 选择器id */ addFeatureToSelectFromLayer(layerTypeName, layerName, featureId, selectId) { if (!this.mapLayers[layerTypeName]) { return } if (!this.mapLayers[layerTypeName][layerName]) { return } let layer = this.mapLayers[layerTypeName][layerName] let features = layer.getSource().getFeatures() features.forEach(feature => { if (feature.values_.id === featureId) { this._addFeatureToSelect(selectId, feature) } }) } /** * @description 添加地图图层(天地图、超图) * @param {String} layerTypeName 图层大类名称 * @param {String} layerName 图层名称, 用作控制显示隐藏 * @param {String} type 图层类型, 用来判断添加方法 tdt:天地图, super:超图 * @param {String} url 地图url * @param {Boolean} show 是否显示 */ addMapLayers(layerTypeName, layerName, type, url, show) { if (!url) { return } let layer = null if (type === 'tdt') { layer = this._addWmtsLayer(url) } if (type === 'super') { // layer = this._addSuperMapLayer(url) } layer.setVisible(show) // 第一次出现图层大类 if (!this.mapLayers[layerTypeName]) { this.mapLayers[layerTypeName] = {} this.mapLayers[layerTypeName][layerName] = layer } else { this.mapLayers[layerTypeName][layerName] = layer } window.olMap.addLayer(layer) } /** * @description 添加marker、高亮图层等 * @param {String} layerTypeName 图层大类名称 * @param {String} layerName 图层名称, 用作控制显示隐藏 * @param {Boolean} show 是否显示 * @param {Array} dataList 用于创建图层的原始数据 * @param {Boolean} ifSource 是否需要添加source * @param {Object} iconOption 图标的配置 * @param {Object} textOption 文字的配置 */ addVectorLayers(layerTypeName, layerName, show, dataList, ifSource, iconOption, textOption) { let vectorSource = new VectorSource({}); // 需要source才循环添加 if (ifSource) { dataList.map((marker, index) => { let iconFeature = new Feature({ geometry: new Point([marker.longitude, marker.latitude]), name: marker.name + '-' + index, id: marker.id, population: 4000, rainfall: 500, position: [marker.longitude, marker.latitude], ...marker }); let iconStyle = new Style({ image: iconOption ? new Icon(iconOption) : null, text: textOption ? new Text(textOption) : null }); iconFeature.setStyle(iconStyle); vectorSource.addFeature(iconFeature) }) } let layer = new VectorLayer({ source: vectorSource }); layer.setVisible(show) // 第一次出现图层大类 if (!this.mapLayers[layerTypeName]) { this.mapLayers[layerTypeName] = {} this.mapLayers[layerTypeName][layerName] = layer } else { this.mapLayers[layerTypeName][layerName] = layer } window.olMap.addLayer(layer) } /** * @description 更新图层的显示属性或设置geometry * @param {String} layerTypeName 图层大类名称 * @param {String} layerName 图层名称 * @param {Boolean} show 是否显示 * @param {String} updateType 更新类型,feature:更新feature内的geometry,source:更新source * @param {Object} geometry {type:类型,coordinates:点位数组} */ updateLayer(layerTypeName, layerName, show, updateType = 'feature', geometry) { if (!this.mapLayers[layerTypeName]) { return } if (!this.mapLayers[layerTypeName][layerName]) { return } let layer = this.mapLayers[layerTypeName][layerName] // 是否设置显示隐藏属性 if (typeof show === 'boolean') { layer.setVisible(show) } if (geometry) { // 更新feature内的geometry if (updateType === 'feature') { let originFeatures = layer.getSource().getFeatures() if (originFeatures.length) { originFeatures.forEach(feature => { feature.setGeometry(this._getFeatureGeometry(geometry)) }) } else { let newGeometry = this._getFeatureGeometry(geometry) let newFeature = new Feature({ geometry: newGeometry }) let style = new Style({ stroke: new Stroke({ color: '#ff8c00', width: 5, lineCap: 'round', lineJoin: 'round' }) }) newFeature.setStyle(style) layer.getSource().addFeature(newFeature); } } // 更新source if (updateType === 'source') { layer.getSource().clear(); let newGeometry = this._getFeatureGeometry(geometry) let newFeature = new Feature({ geometry: newGeometry }) let style = new Style({ fill: new Fill({ color: '#ff0000' }), stroke: new Stroke({ color: '#ff0000', width: 3 }) }) newFeature.setStyle(style) layer.getSource().addFeature(newFeature); } } } /** * @description 清除图层source * @param {String} layerTypeName 图层大类名称 * @param {String} layerName 图层名称 */ clearLayerSource(layerTypeName, layerName) { if (!this.mapLayers[layerTypeName]) { return } if (!this.mapLayers[layerTypeName][layerName]) { return } let layer = this.mapLayers[layerTypeName][layerName] layer.getSource().clear(); } /** * @description 更新图层的显示属性或设置geometry * @param {String} layerTypeName 图层大类名称 * @param {String} layerName 图层名称 */ getLayer(layerTypeName, layerName) { if (!this.mapLayers[layerTypeName]) { return } let resLayerList = [] if (!layerName) { for (let key in this.mapLayers[layerTypeName]) { resLayerList.push(this.mapLayers[layerTypeName][key]) } } else { resLayerList = [this.mapLayers[layerTypeName][layerName]] } return resLayerList } /** * @description 删除图层 * @param {String} layerTypeName 图层大类名称 * @param {String} layerName 图层名称 */ removeLayer(layerTypeName) { if (!this.mapLayers[layerTypeName]) { return } for (let key in this.mapLayers[layerTypeName]) { let layer = this.mapLayers[layerTypeName][key] window.olMap.removeLayer(layer) } this.mapLayers[layerTypeName] = {} } /** * @description 内部方法, 用于创建wmts图层, 添加天地图底图 * @param {String} url 地图url * @return {TileLayer} TileLayer 返回图层 */ _addWmtsLayer(url) { if (!url) return null let projection = getProjection('EPSG:4326') let extent = projection.getExtent() let width = getWidth(extent) let resolutions = [], matrixIds = [] for (let z = 1; z < 19; z++) { resolutions[z] = width / (256 * Math.pow(2, z)) matrixIds[z] = z } let tileGrid = new WMTSTileGrid({ origin: getTopLeft(extent), resolutions, matrixIds }) // 匹配坐标系、图层类型 let type = url.match(new RegExp(/\/(.{3})_(c|w)\//)) return new TileLayer({ source: new WMTS({ crossOrigin: 'anonymous', url: url, layer: type[1], matrixSet: type[2], format: 'tiles', style: 'default', wrapX: true, projection: projection, tileGrid }) }) } /** * @description 内部方法,根据geometry类型返回对应的feature * @param {Object} geometry 原始geometry数据{type, coordinates} */ _getFeatureGeometry(geometry) { if (!geometry.type) { return } let featureGeometry; if (geometry.type === 'Point') { featureGeometry = new Point(geometry.coordinates) } if (geometry.type === 'Polygon') { featureGeometry = new Polygon(geometry.coordinates) } if (geometry.type === 'MultiPolygon') { featureGeometry = new MultiPolygon(geometry.coordinates) } if (geometry.type === 'LineString') { featureGeometry = new LineString(geometry.coordinates) } return featureGeometry; } /** * @description 添加popUp弹窗 * @param {String} id 弹窗的id * @param {String} domId 弹窗的domId * @param {Boolean} show 初始化弹窗时是否显示 * @param {Array} position 要添加弹窗图的坐标数组 */ addPopUp(id, domId, show, position) { let popup = new Overlay({ element: document.getElementById(domId), // 当前窗口可见 autoPan: true, stopEvent: true, autoPanAnimation: { duration: 250 } }) window.olMap.addOverlay(popup) if (position && position instanceof Array) { show ? popup.setPosition(position) : popup.setPosition(undefined) } else { popup.setPosition(undefined) } this.popUp.push({ popId: id, popObj: popup }) } /** * @description 更新弹窗位置或显示隐藏 * @param {String} id 弹窗的id * @param {Boolean} show 是否显示 * @param {Array} position 要添加弹窗图的坐标数组 */ updatePopUp(id, show, position) { if (!this.popUp.length) { return } let popup = this.popUp.find(pop => pop.popId === id)?.popObj if (!popup) { return } // 是否显示弹窗 if (position && position instanceof Array) { show ? popup.setPosition(position) : popup.setPosition(undefined) } else { popup.setPosition(undefined) } } /** * @description 移除弹窗, 多个则传入弹窗id数组, 该方法会删除弹窗dom * @description 如果不想删除弹窗dom, 请使用updatePopUp() * @param {Array & String} id 弹窗的id */ removePopUp(id) { this.popUp.forEach(pop => { if (id && id instanceof Array) { id.indexOf(pop.popId) > -1 && window.olMap.removeOverlay(pop.popObj) } if (id && typeof id === 'string') { id === pop.popId && window.olMap.removeOverlay(pop.popObj) } }) } /** * @description 移除所有弹窗, delDom会删除弹窗dom * @param {Boolean} delDom 是否移除dom */ removeAllPopUp(delDom) { if (delDom) { window.olMap.getOverlays().clear() } else { this.popUp.forEach(pop => { pop.popObj.setPosition(undefined) }) } } }