废话不多说,代码端上来
<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 款式这玩意就不展现了,菜鸟一个,请多指教