废话不多说,代码端上来
<template>
<div ref="map" id="map"> <div id="contextmenu_container" class="contextmenu"> <ul> <li @click="drawFeature"> <a href="#">绘制</a> </li> <li @click="toHome"> <a href="#">罕用区域</a> </li> <li @click="outputJson"> <a href="#">输入Json</a> </li> <li @click="measure('distence')"> <a href="#">测距</a> </li> <li @click="measure('area')"> <a href="#">测面</a> </li> <li @click="measure('angle')"> <a href="#">量角</a> </li> <li @click="fullscreen" v-html="textarr"> <a href="#">全屏</a> </li> <li @click="clear"> <a href="#">革除</a> </li> <li @click="pointPopup"> <a href="#">点坐标</a> </li> <li @click="zoomIn"> <a href="#">放大</a> </li> <li @click="zoomOut"> <a href="#">放大</a> </li> <li @click="refresh"> <a href="#">刷新</a> </li> </ul> </div> <div id="popup" class="ol-popup"> <a href="#" ref="external nofollow" id="popup-closer" class="ol-popup-closer" ></a> <div id="popup-content"></div> </div> </div>
<import>
import 'ol/ol.css'import Map from 'ol/Map'import View from 'ol/View'import VectorSource from 'ol/source/Vector'import OSM from 'ol/source/OSM'import VectorLayer from 'ol/layer/Vector'import TileLayer from 'ol/layer/Tile'import { GeoJSON } from 'ol/format'import { Draw } from 'ol/interaction'import Overlay from 'ol/Overlay'// 线条几何形态。import { LineString } from 'ol/geom'import Feature from 'ol/Feature'// 应用返回的键或import { unByKey } from 'ol/Observable'// 获取几何形态的球形长度和面积import { getLength, getArea, offset } from 'ol/sphere'import Style from 'ol/style/Style'import Stroke from 'ol/style/Stroke'import Fill from 'ol/style/Fill'import Circle from 'ol/style/Circle'import { ScaleLine, defaults as defaultControls } from 'ol/control'import MousePosition from 'ol/control/MousePosition'import { createStringXY } from 'ol/coordinate'import Icon from 'ol/style/Icon'import Text from 'ol/style/Text'import { transform } from 'ol/proj'import { fromLonLat } from 'ol/proj'import Point from 'ol/geom/Point'import ImageSource from 'ol/source/Image'import { fromExtent } from 'ol/geom/Polygon'
重头戏
export default
data() { return { map: null, vectorLayer: null, vectorSource: null, draw: null, select: null, modify: null, editorBtnText: '编辑', overlay: null, textarr: '全屏', measureType: 'diatence', tipDiv: null, pointermoveEvent: null, // 地图pointermove事件 sketchFeature: null, // 绘制的因素 geometryListener: null, // 因素几何change事件 measureResult: '0', // 测量后果 pointLayer: null, } },
mounted
var baseLayer = new TileLayer({ source: new OSM(), })this.vectorSource = new VectorSource({ wrapX: false, }) this.vectorLayer = new VectorLayer({ source: this.vectorSource, }) const scaleLineControl = new ScaleLine({ target: 'scalebar', className: 'ol-scale-line', }) const mousePositionControl = new MousePosition({ coordinateFormat: createStringXY(4), projection: 'EPSG:4326', className: 'custom-mouse-position', target: document.getElementById('mouse-position'), }) this.map = new Map({ layers: [baseLayer, this.vectorLayer], controls: defaultControls({ zoom: false, // rotate: false, attribution: false, }).extend([scaleLineControl, mousePositionControl]), target: 'map', view: new View({ projection: 'EPSG:4326', center: [123.476492, 25.744676], zoom: 8, }), }) this.map.addControl(scaleLineControl)
办法定义
refresh() { let that = this that.reload() }, pointPopup() { var container = document.getElementById('popup') var content = document.getElementById('popup-content') var popupCloser = document.getElementById('popup-closer') this.overlay = new Overlay({ element: container, antoPan: true, autoPanAnimation: { duration: 250, }, }) this.map.addOverlay(this.overlay) let that = this that.map.on('singleclick', function(evt) { let coordinate = transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326') let coordinate2 = evt.coordinate that.addPoints(coordinate) content.innerHTML = ` <p>你点击了这里:</p> <p>坐标:</p>X:${coordinate2[0]} Y:${coordinate2[1]}` that.overlay.setPosition(coordinate2) //把 overlay 显示到指定的 x,y坐标 }) popupCloser.onclick = function() { that.overlay.setPosition(undefined) popupCloser.blur() return false } }, addPoints(coordinate) { const feature = new Feature({ geometry: new Point(fromLonLat(coordinate)), name: 'isbig', }) const iconStyle = new Style({ image: new Icon({ anchor: [0.5, 0.5], src: 'https://openlayers.org/en/v4.6.5/examples/data/icon.png', }), }) feature.setStyle(iconStyle) const vectorSource = new VectorSource({}) this.pointLayer = new VectorLayer({ source: vectorSource, }) this.map.addLayer(this.pointLayer) this.vectorSource.addFeature(feature) return iconStyle }, drawFeature() { this.draw = new Draw({ source: this.vectorSource, // 用此实例绘制的几何形态类型。 type: 'Polygon', }) this.map.addInteraction(this.draw) // 绘制实现 this.draw.on('drawend', () => { this.map.removeInteraction(this.draw) this.draw = null }) }, toHome() { var to = [120.38, 36.07] var view = this.map.getView() view.setZoom(8), view.animate({ center: to, duration: 0, }) }, // 输入矢量图层因素为GeoJson数据 outputJson() { let features = this.vectorSource.getFeatures() let jsonObj = new GeoJSON().writeFeatures(features) console.log('->GeoJson格局数据:', jsonObj) }, creatDraw(type) { let maxPoints = null if (this.measureType == 'angle') maxPoints = 3 else maxPoints = null // 矢量图层源 let vectorSource = new VectorSource({ wrapX: false, }) // 矢量图层 this.vectorLayer = new VectorLayer({ source: vectorSource, style: new Style({ fill: new Fill({ color: 'rgba(252, 86, 49, 0.1)', }), stroke: new Stroke({ color: '#fc5531', width: 3, }), image: new Circle({ radius: 0, fill: new Fill({ color: '#fc5531', }), }), }), name: '测量图层', }) this.map.addLayer(this.vectorLayer) this.draw = new Draw({ source: vectorSource, type: type, maxPoints: maxPoints, style: new Style({ fill: new Fill({ color: 'rgba(252, 86, 49, 0.1)', }), stroke: new Stroke({ color: '#fc5531', lineDash: [10, 10], width: 3, }), image: new Circle({ radius: 0, fill: new Fill({ color: '#fc5531', }), }), }), // 绘制时点击处理事件 condition: (evt) => { // 测距时增加点标注 if ( this.measureResult != '0' && !this.map.getOverlayById(this.measureResult) && this.measureType == 'distence' ) this.creatMark( null, this.measureResult, this.measureResult ).setPosition(evt.coordinate) return true }, }) this.map.addInteraction(this.draw) /** * 绘制开始事件 */ this.draw.on('drawstart', (e) => { this.sketchFeature = e.feature let proj = this.map.getView().getProjection() //******间隔测量开始时*****// if (this.measureType == 'distence') { this.creatMark(null, '终点', 'start').setPosition( this.map.getCoordinateFromPixel(e.target.downPx_) ) this.tipDiv.innerHTML = '总长:0 m</br>单击确定地点,双击完结' this.geometryListener = this.sketchFeature .getGeometry() .on('change', (evt) => { this.measureResult = this.distenceFormat( getLength(evt.target, { projection: 'EPSG:3857', radius: 6378137, }) ) this.tipDiv.innerHTML = '总长:' + this.measureResult + '</br>单击确定地点,双击完结' }) } //******面积测量开始时*****// else if (this.measureType == 'area') { this.tipDiv.innerHTML = '面积:0 m<sup>2</sup></br>持续单击确定地点' this.geometryListener = this.sketchFeature .getGeometry() .on('change', (evt) => { if (evt.target.getCoordinates()[0].length < 4) this.tipDiv.innerHTML = '面积:0m<sup>2</sup></br>持续单击确定地点' else { this.measureResult = this.formatArea( getArea(evt.target, { projection: proj, radius: 6378137 }) ) this.tipDiv.innerHTML = '面积:' + this.measureResult + '</br>单击确定地点,双击完结' } }) } //******角度测量开始时*****// else if (this.measureType == 'angle') { this.tipDiv.innerHTML = '持续单击确定顶点' this.geometryListener = this.sketchFeature .getGeometry() .on('change', (evt) => { if (evt.target.getCoordinates().length < 3) this.tipDiv.innerHTML = '持续单击确定顶点' else { this.measureResult = this.formatAngle(evt.target) this.tipDiv.innerHTML = '角度:' + this.measureResult + '</br>持续单击完结' } }) } }) /** * 绘制开始事件 */ this.draw.on('drawend', (e) => { let closeBtn = document.createElement('span') closeBtn.innerHTML = '×' closeBtn.title = '革除测量' closeBtn.style = 'width: 10px;height:10px;line-height: 12px;text-align: center;border-radius: 5px;display: inline-block;padding: 2px;color: rgb(255, 68, 0);border: 2px solid rgb(255, 68, 0);background-color: rgb(255, 255, 255);font-weight: 600;position: absolute;top: -25px;right: -2px;cursor: pointer;' closeBtn.addEventListener('click', () => { this.clearMeasure() }) //******间隔测量完结时*****// if (this.measureType == 'distence') { this.creatMark(closeBtn, null, 'close1').setPosition( e.feature.getGeometry().getLastCoordinate() ) this.creatMark( null, '总长:' + this.measureResult + '', 'length' ).setPosition(e.feature.getGeometry().getLastCoordinate()) this.map.removeOverlay(this.map.getOverlayById(this.measureResult)) } //******面积测量完结时*****// else if (this.measureType == 'area') { this.creatMark(closeBtn, null, 'close2').setPosition( e.feature .getGeometry() .getInteriorPoint() .getCoordinates() ) this.creatMark( null, '总面积:' + this.measureResult + '', 'area' ).setPosition( e.feature .getGeometry() .getInteriorPoint() .getCoordinates() ) } //******角度测量完结时*****// else if (this.measureType == 'angle') { this.creatMark(closeBtn, null, 'close3').setPosition( e.feature.getGeometry().getCoordinates()[1] ) this.creatMark( null, '角度:' + this.measureResult + '', 'angle' ).setPosition(e.feature.getGeometry().getCoordinates()[1]) } // 进行测量 this.stopMeasure() }) }, measure(type) { if (this.draw != null) return false // 避免在绘制过程再创立测量 this.measureType = type if (this.vectorLayer != null) this.clearMeasure() this.tipDiv = document.createElement('div') this.tipDiv.innerHTML = '单击确定终点' this.tipDiv.className = 'tipDiv' this.tipDiv.style = 'width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;' let overlay = new Overlay({ element: this.tipDiv, autoPan: false, positioning: 'bottom-center', id: 'tipLay', stopEvent: false, //进行事件流传到地图 }) this.map.addOverlay(overlay) this.pointermoveEvent = this.map.on('pointermove', (evt) => { overlay.setPosition(evt.coordinate) }) if (this.measureType == 'distence' || this.measureType == 'angle') { this.creatDraw('LineString') } else if (this.measureType == 'area') { this.creatDraw('Polygon') } }, creatMark(markDom, txt, idstr) { if (markDom == null) { markDom = document.createElement('div') markDom.innerHTML = txt markDom.style = 'width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;' } let overlay = new Overlay({ element: markDom, autoPan: false, positioning: 'bottom-center', id: idstr, stopEvent: false, }) this.map.addOverlay(overlay) return overlay }, distenceFormat(length) { let output if (length > 100) { output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km' //换算成km单位 } else { output = Math.round(length * 100) / 100 + ' ' + 'm' //m为单位 } return output //返回线的长度 }, formatArea(area) { let output if (area > 10000) { output = Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>' //换算成km单位 } else { output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>' //m为单位 } return output //返回多边形的面积 }, formatAngle(line) { var coordinates = line.getCoordinates() var angle = '0°' if (coordinates.length == 3) { const disa = getLength( new Feature({ geometry: new LineString([coordinates[0], coordinates[1]]), }).getGeometry(), { radius: 6378137, projection: this.map.getView().getProjection(), } ) const disb = getLength( new Feature({ geometry: new LineString([coordinates[1], coordinates[2]]), }).getGeometry(), { radius: 6378137, projection: this.map.getView().getProjection(), } ) const disc = getLength( new Feature({ geometry: new LineString([coordinates[0], coordinates[2]]), }).getGeometry(), { radius: 6378137, projection: this.map.getView().getProjection(), } ) var cos = (disa * disa + disb * disb - disc * disc) / (2 * disa * disb) // 计算cos值 angle = (Math.acos(cos) * 180) / Math.PI // 角度值 angle = angle.toFixed(2) // 后果保留两位小数 } if (isNaN(angle)) return '0°' else return angle + '°' // 返回角度 }, // 进行测量 stopMeasure() { this.tipDiv = null this.map.removeInteraction(this.draw) this.draw = null this.map.removeOverlay(this.map.getOverlayById('tipLay')) }, //革除测量 clearMeasure() { this.vectorLayer.getSource().clear() this.map.getOverlays().clear() //移除监听事件 unByKey(this.pointermoveEvent) unByKey(this.geometryListener) this.pointermoveEvent = null this.geometryListener = null this.measureResult = '0' }, // 全屏 fullscreen() { if (this.textarr == '全屏') { this.textarr = '放大' let rfs = this.$refs.map.requestFullScreen || this.$refs.map.webkitRequestFullScreen || this.$refs.map.mozRequestFullScreen || this.$refs.map.msRequestFullScreen if (typeof rfs !== 'undefined' && rfs) { rfs.call(this.$refs.map) console.log('1全屏') } else if (typeof window.ActiveXObject !== 'undefined') { // for IE,这里其实就是模仿了按下键盘的F11,使浏览器全屏 // eslint-disable-next-line no-undef let wscript = new ActiveXObject('WScript.Shell') console.log(wscript) if (wscript != null) { wscript.SendKeys('{F11}') console.log('3全屏') } console.log('2全屏') } } else { // el.webkitExitFullscreen() this.textarr = '全屏' let cfs = document.exitFullscreen || document.msExitFullscreen || document.mozCancelFullScreen || document.webkitCancelFullScreen console.log(cfs, 'cfs') if (typeof cfs !== 'undefined' && cfs) { cfs.call(document) console.log('4全屏') } else if (typeof window.ActiveXObject !== 'undefined') { // for IE,这里和fullScreen雷同,模仿按下F11键退出全屏 // eslint-disable-next-line no-undef let wscript = new ActiveXObject('WScript.Shell') console.log('5全屏') if (wscript != null) { wscript.SendKeys('{F11}') console.log('6全屏') } } } // this.map.addControl(new FullScreen()) }, // 革除 clear() { this.vectorLayer.getSource().clear() this.map.getOverlays().clear() }, zoomIn() { let view = this.map.getView() let zoom = view.getZoom() view.setZoom(zoom + 1) }, zoomOut() { let view = this.map.getView() let zoom = view.getZoom() view.setZoom(zoom - 1) }, },
css款式这玩意就不展现了,菜鸟一个,请多指教