import OLMap from 'ol/Map' import View from 'ol/View' import * as proj from 'ol/proj' import * as interaction from 'ol/interaction' import {Draw,Modify} from 'ol/interaction' import 'ol/ol.css' import './css/KMap.css' import * as Enum from './Enum' import Common from './Common' import VectorLayer from './VectorLayer' import * as Extent from 'ol/extent' import Overlay from 'ol/Overlay' import WMTSLayer from './WMTSLayer' import XYZLayer from './XYZLayer' import config from "@/api/config.js"; import {Feature} from "ol"; import {GeoJSON, WKT} from 'ol/format' import { Style, Text,Icon } from 'ol/style'; import { Circle, Fill, Stroke } from 'ol/style.js'; import { LineString, Point } from 'ol/geom'; import {getArea} from "ol/sphere" /** * @description KMap.Map 地图类 */ class Map { /** * @description 地图实例 * @static * @memberof Map */ Instance = null /** * @description 信息窗体像素对象 * @memberof Map */ infoWindowPixel = null /** * @description 鼠标移动事件弹窗UID * @memberof Map */ InfowindowmoveUID = -1 /** * @description 鼠标点击事件弹窗UID * @memberof Map */ InfowindowclickUID = -1 /** * @description 是否有鼠标移动弹窗 * @memberof Map */ ClearMouseMoveInfoWindow = false /** * @description X方向缩放 * @memberof Map */ scaleX = 1 /** * @description Y方向缩放 * @memberof Map */ scaleY = 1 /** * @param {string} id DOM元素ID * @param {number} zoomLevel 地图层级 * @param {number} lng 纬度 * @param {number} lat 经度 * @description Map初始化方法 * @constructor */ constructor(id,zoomLevel,lng,lat,projection, minZoom,maxZoom){ this.defaultCursor = 'default' if(Map.Instance){ Map.Instance = false; } if(projection){ projection = proj.get(projection) } projection = projection || proj.get("EPSG:4326"); const vm = this Map.Instance = this let lnglat = [lng,lat] if(projection.getCode() == "EPSG:3857"){ lnglat = proj.fromLonLat(lnglat); } Common.checkLngLat(lng,lat) let view = new View({ center: lnglat, zoom: zoomLevel, minZoom: minZoom || Common.ShowLevel[0], maxZoom: maxZoom || Common.ShowLevel[1], projection:projection }) this.view = view this.map = new OLMap({ interactions: interaction.defaults().extend([ new interaction.DragRotateAndZoom()]), target: id, layers: [],//vm.baseLayer view: view, control: [] }) this.initBaseLayer(projection) //初始化业务图层 this.initBusinessLayer() //初始化地图信息弹窗 this.initInfoWindow() //初始化地图基础事件 this.initMapBaseEvent() } /** * 初始化地图底图图层 * @return {array} * @memberof Map */ async initBaseLayer(projection){ const img_wmts = await VE_API.system.getCfg({"k":"img_wmts_mkt","resultType":"json"}); const cva_wmts = await VE_API.system.getCfg({"k":"cva_wmts_mkt","resultType":"json"}); this.tdtImgLayer = new WMTSLayer(img_wmts.data, projection,this); this.cva_torLayer = new WMTSLayer(cva_wmts.data,projection,this); let xyz2 = config.base_img_url3 + 'map/lby/{z}/{x}/{y}.png'; this.addXYZLayer(xyz2,{minZoom:15,maxZoom:22}); } addXYZLayer(url,options){ let xyz = new XYZLayer(url,options,3); return xyz; } /** * @description 初始化业务图层 * @memberof Map */ initBusinessLayer(){ const vm = this let map = vm.map //创建默认点标记图层 vm.markerLayer = new VectorLayer("defaultMarkerLayer",101) //创建默认线标记图层 vm.polyLineLayer = new VectorLayer("defaultPolylineLayer",101) //创建默认面图层 vm.polygonLayer = new VectorLayer("defaultPolygonLayer",1000,{ style: vm.polygonStyle }) //创建文本标记图层 vm.labelLayer = new VectorLayer("defaultLabelLayer",99) map.addLayer(vm.polygonLayer.layer) map.once('postrender', function(event) { map.addLayer(vm.markerLayer.layer) map.addLayer(vm.polyLineLayer.layer) map.addLayer(vm.labelLayer.layer) map.on('click',function(evt){ let coordinate = evt.coordinate; // let newPoints = proj.transform(coordinate, 'EPSG:3857', 'EPSG:4326'); // debugger; }) // map.addLayer(layer) }) } initDraw(callback){ const vm = this this.draw = new Draw({ type: 'MultiPolygon', source: this.polygonLayer.source, free: true, style: vm.drawStyleFunc }) this.draw.setActive(false) this.map.addInteraction(this.draw); this.draw.on("drawstart",callback) this.draw.on("drawend",callback) } startDraw(){ this.draw.setActive(true) } endDraw(){ this.draw.setActive(false) } modifyDraw(callback, condition) { this.modify = new Modify({ source: this.polygonLayer.source, condition:condition || function(){return true;}, pixelTolerance: 10, //设置吸附像素值 }) this.modify.setActive(false) this.map.addInteraction(this.modify); this.modify.on("modifyend",callback) this.modify.on("modifystart",callback) } startModify(){ this.modify.setActive(true) } endModify(){ this.modify.setActive(false) } drawStyleFunc(feature) { const styles = []; const type = feature.getGeometry().getType(); const coord = feature.getGeometry().getCoordinates(); for (let i = 0; i < coord.length - 1; i++) { if (i%2) { styles.push( new Style({ geometry: new Point(coord[i]), image: new Circle({ radius: 6, fill: new Fill({ color: '#06F7A1' }), stroke: new Stroke({ color: '#fff', width: 1 }) }) }) ); } else { styles.push( new Style({ geometry: new Point(coord[i]), image: new Circle({ radius: 6, fill: new Fill({ color: '#fff' }), }) }) ); } } if (type === 'LineString') { for (let i = 0; i < coord.length - 1; i++) { styles.push( new Style({ geometry: new LineString([coord[i], coord[i + 1]]), stroke: new Stroke({ color: '#06F7A1', width: 2 }) }) ); } } return styles; } polygonStyle(feature) { const styles = []; let fillStyle = {} const coord = feature.getGeometry().getCoordinates()[0]; if(feature.get("icon")==="point-act"){ for (let i = 0; i < coord[0].length - 1; i++) { if (i%2) { styles.push( new Style({ geometry: new Point(coord[0][i]), image: new Circle({ radius: 6, fill: new Fill({ color: '#06F7A1' }), stroke: new Stroke({ color: '#fff', width: 1 }), }), }), new Style({ geometry: new Point(coord[0][i]), text: new Text({ font: "11px sans-serif", text: "A"+(i+1), offsetX: 0, offsetY: -21, fill: new Fill({ color: "#161616" }), // 字体颜色 }), image: new Icon({ src: require(`@/assets/images/map/text-green-bg.png`), scale: 0.32, displacement: [0, 60], }), }) ); } else { styles.push( new Style({ geometry: new Point(coord[0][i]), image: new Circle({ radius: 6, fill: new Fill({ color: '#fff' }) }), }), new Style({ geometry: new Point(coord[0][i]), text: new Text({ font: "11px sans-serif", text: "A"+(i+1), offsetX: 0, offsetY: -21, fill: new Fill({ color: "#161616" }), // 字体颜色 }), image: new Icon({ src: require(`@/assets/images/map/text-bg.png`), scale: 0.32, displacement: [0, 60], }), }) ); } } fillStyle = new Style({ fill: new Fill({ color: [1, 41, 52, 0.6] }), stroke: new Stroke({ color: '#06F7A1', width: 2 }) }) }else{ fillStyle = new Style({ fill: new Fill({ color: [1, 41, 52, 0.3] }), stroke: new Stroke({ color: '#fff', width: 2 }) }) } let geom = feature.getGeometry().clone() geom.transform(proj.get("EPSG:4326"), proj.get("EPSG:38572")) let area = getArea(geom) area = (area + area / 2) / 1000; let areaValStyle = new Style({ text: new Text({ font: "16px sans-serif", text: area.toFixed(2) + "亩", // offsetX: 28, // offsetY: -100, fill: new Fill({ color: "#fff" }), // 字体颜色 }), }) styles.push(fillStyle); return styles; } getLayerFeatures() { const vm = this let features = vm.polygonLayer.source.getFeatures() return features } // 传入geojson,回显到polygon setLayerPolygon(geometry) { const vm = this vm.polygonLayer.source.addFeatures(new GeoJSON().readFeatures(geometry)) } setLayerWkt(wkt,data,isView, padding) { const vm = this let f = new Feature({geometry:new WKT().readGeometry(wkt),...data}) const extent = f.getGeometry().getExtent() vm.polygonLayer.source.addFeature(f) if(isView){ vm.map.getView().fit(extent, { padding: padding || [20, 20, 20, 20] }); } } addLayer(layer){ const vm = this vm.map.addLayer(layer) } removeLayer(layer){ const vm = this vm.map.removeLayer(layer) } /** * @description 初始化信息弹窗 * @memberof Map */ initInfoWindow(){ const vm = this //创建地图弹窗容器 let infoWindowBoxClick = document.createElement("div") let infoWindowBoxMove = document.createElement("div") let mapTarget = vm.map.getTargetElement() infoWindowBoxClick.id = "infowindow-click" infoWindowBoxMove.id = "infowindow-move" infoWindowBoxClick.style.zIndex = 999 infoWindowBoxMove.style.zIndex = 999 mapTarget.appendChild(infoWindowBoxClick) mapTarget.appendChild(infoWindowBoxMove) vm.infoWindow_click = new Overlay({ element: infoWindowBoxClick }) vm.infoWindow_move = new Overlay({ element: infoWindowBoxMove }) //添加点击弹窗 vm.map.addOverlay(vm.infoWindow_click) //添加悬停弹窗 vm.map.addOverlay(vm.infoWindow_move) } /** * @description 初始化地图基础事件 * @memberof Map */ initMapBaseEvent(){ const vm = this var allowTriggerEvent = function(pixel) { var infoWindowPixel = vm.infoWindowPixel if(infoWindowPixel == null){ return true } var x = pixel[0] var y = pixel[1] if(x>=infoWindowPixel[0] && x<=infoWindowPixel[2] && y>=infoWindowPixel[1] && y<=infoWindowPixel[3]) { return false } return true } vm.map.on('click',function(event){ event.pixel[0] = (event.pixel[0] / vm.scaleX) event.pixel[1] = (event.pixel[1] / vm.scaleY) var clickFeature = vm.map.forEachFeatureAtPixel(event.pixel, function(feature){ if(!allowTriggerEvent(event.pixel)) return // 为点击到的feature发送自定义的click消息 if(feature.dispatchEvent != undefined){ feature.dispatchEvent({type: 'click', event: event}) } return feature }) //点击在地图空白处时清空弹窗 if(clickFeature == undefined){ vm.clearInfoWindow() } }) //为地图注册鼠标点击事件的监听 vm.map.on('pointermove', function(event) { event.pixel[0] = (event.pixel[0] / vm.scaleX) event.pixel[1] = (event.pixel[1] / vm.scaleY) var mousemoveFeature = vm.map.forEachFeatureAtPixel(event.pixel, function(feature){ if(!allowTriggerEvent(event.pixel)){ return } // 为点击到的feature发送自定义的mousemove消息 if(feature.dispatchEvent != undefined){ feature.dispatchEvent({type: 'mousemove', event: event}) } return feature }) //悬停在地图空白处时清空悬停弹窗 if(mousemoveFeature == undefined) { vm.clearMouseMoveInfoWindow() } //设置鼠标悬停到覆盖物上的样式 let mapContainer = vm.getTarget() if(mousemoveFeature) { mapContainer.style.cursor = "pointer" } else { mapContainer.style.cursor = this.defaultCursor } }) } setScale(x, y) { const vm = this // var mapContainer = vm.getTarget() // mapContainer.style.overflow = 'hidden' // var mapContent = mapContainer.getElementsByClassName('ol-viewport')[0] // var scaleX = 1 / Number(x); // var scaleY = 1 / Number(y); vm.scaleX = Number(x) vm.scaleY = Number(y) // mapContent.style.transform = "scale("+scaleX+","+scaleY+")" } /** * @description 清除鼠标点击弹窗 * @memberof Map */ clearInfoWindow() { const vm = this vm.infoWindow_click.setPosition(undefined) vm.infoWindow_move.setPosition(undefined) vm.infoWindowPixel = null vm.InfowindowmoveUID = -1 vm.InfowindowclickUID = -1 } /** * @description 清除鼠标移动弹窗 * @memberof Map */ clearMouseMoveInfoWindow() { const vm = this if(vm.ClearMouseMoveInfoWindow) { vm.infoWindow_move.setPosition(undefined) vm.infoWindowPixel = null vm.InfowindowmoveUID = -1 } } /** * @description 获取地图容器div * @returns 地图容器div * @memberof Map */ getTarget() { let target = this.map.getTargetElement() return target } /** * @description 获取地图容器尺寸 * @returns KMap.Size格式的尺寸 * @memberof Map */ getSize() { let size = this.map.getSize() console.log(Common) size = Common.MapSize2KMapSize(size) return size } /** * @description 获取地图投影EPSG类型 * @returns 地图投影类型 * @memberof Map */ getProjection() { let projection = this.view.getProjection() return projection } /** * @description 获取地图中心 * @returns 地图中心,KMap.LngLat对象格式 * @memberof Map */ getCenter() { let center = this.view.getCenter() center = proj.toLonLat(center) return Common.MapLngLat2KMapLngLat(center) } /** * @description 获取地图中心 * @returns 地图中心,KMap.LngLat对象格式 * @memberof Map */ getCenter2() { let center = this.view.getCenter() center = proj.toLonLat(center) return center } /** * @description 设置地图中心 * @param {KMap.LngLat} position 地图中心位置,KMap.LngLat对象格式,必填 * @memberof Map */ setCenter(position) { let centerlnglat = Common.KMapLngLat2MapLngLat(position) let center = proj.fromLonLat(centerlnglat) this.view.setCenter(center) } getView(){ return this.view; } /** * @description 设置地图中心 * @param {KMap.LngLat} position 地图中心位置,KMap.LngLat对象格式,必填 * @memberof Map */ setCenter2(position) { this.view.setCenter(position) } fitToView(center,zoom,dera) { this.view.fit(center,{duration: dera}) } /** * @description 地图中心点平移至指定点位置 * @param {KMap.LngLat} point 指定点经纬度坐标,KMap.LngLat对象格式,必填 * @param {number} zoom 缩放级别,选填参数,不填则使用当前缩放级别 * @memberof Map */ panTo(point,zoom) { point = Common.KMapLngLat2MapLngLat(point) let center = proj.fromLonLat(point) if(zoom) { this.view.animate({center:center},{zoom:zoom}) } else { this.view.animate({center:center}) } } /** * @description 地图放大一级显示 * @memberof Map */ zoomIn() { this.view.setZoom( this.getZoom() + 1 ) return this.getZoom() } /** * @description 地图缩小一级显示 * @memberof Map */ zoomOut() { this.view.setZoom( this.getZoom() - 1) return this.getZoom() } /** * @description 缩放到点标记图层范围 * @param {number} duration 选填参数,动画时长(单位:毫秒),不填则使用默认的0毫秒 * @memberof Map */ zoomToMarkerLayer(duration) { const vm = this duration = (duration != undefined)? duration : 0 let markers = vm.markerLayer.getSource().getFeatures() let coordinateArray = new Array() for(let i=0; i