openlayers 测量功能实现(测距测面)- vue3
一、配置openlayer环境
借鉴:Vue 3 + OpenLayers 的简单使用_vue3 openlayers-CSDN博客
二、代码如下(测距、测面和清除)
measurs.js:
import {ref} from 'vue';
import Draw from 'ol/interaction/Draw'
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Point from "ol/geom/Point";
import {unByKey
} from 'ol/Observable.js';
import Overlay from 'ol/Overlay';
import {Feature } from "ol";
// import {
// getArea,
// getLength
// } from 'ol/sphere.js';
import {getLength} from 'ol/sphere';
import {getArea} from 'ol/sphere';
import LineString from 'ol/geom/LineString';
import Polygon from 'ol/geom/Polygon';
import {Circle as CircleStyle,Fill,Stroke,Style
} from 'ol/style.js';// 测距所需对象
const lineVectorLayer = ref(null);
const lineDraw = ref(null);// 测面所需对象
const areaVectorLayer = ref(null);
const areaDraw = ref(null);// 测距
export const measureLine = (map) => {clearMeasure(map);//清空测量图层// 创建数据源var source = new VectorSource();lineVectorLayer.value = new VectorLayer({id:'Line',source: source,style: new Style({fill: new Fill({color: 'rgba(255, 255, 255, 0.2)'}),stroke: new Stroke({color: 'red',width: 2}),image: new CircleStyle({radius: 7,fill: new Fill({color: '#ffcc33'})})}),zIndex:16});map.addLayer(lineVectorLayer.value)/*** Currently drawn feature.* @type {module:ol/Feature~Feature}*/var sketch;/** 测距* The help tooltip element.* @type {Element}*/var lineHelpTooltipElement;/*** Overlay to show the help messages.* @type {module:ol/Overlay}*/var lineHelpTooltip;/*** The measure tooltip element.* @type {Element}*/var measureTooltipElement;/*** Overlay to show the measurement.* @type {module:ol/Overlay}*/var measureTooltip;/*** Message to show when the user is drawing a line.* @type {string}*/var continueLineMsg = '';createMeasureTooltip();createHelpTooltip();/*** Handle pointer move.* @param {module:ol/MapBrowserEvent~MapBrowserEvent} evt The event.*/var pointerMoveHandler = function (evt) {if (evt.dragging) {return;}/** @type {string} */var helpMsg = '请点击开始测距';if (sketch) {// 测量时的提示文字var geom = (sketch.getGeometry());if (geom instanceof LineString) {helpMsg = continueLineMsg;}}// 设置提示对话框//lineHelpTooltipElement.innerHTML = helpMsg;// 文字没有颜色lineHelpTooltipElement.innerHTML = "<span style='color: red;'>"+helpMsg+"</span>";lineHelpTooltip.setPosition(evt.coordinate);lineHelpTooltipElement.classList.remove('hidden');};// 监听鼠标移动方法map.on('pointermove', pointerMoveHandler);map.getViewport().addEventListener('mouseout', function () {lineHelpTooltipElement.classList.add('hidden');});var draw;// 绘制对象var formatLength = function (line) {//获取投影坐标系var sourceProj = map.getView().getProjection();//ol/sphere里有getLength()和getArea()用来测量距离和区域面积,默认的投影坐标系是EPSG:3857, 其中有个options的参数,可以设置投影坐标系var length = getLength(line, {projection: sourceProj});//var length = getLength(line);var output;if (length > 100) {output = (Math.round(length / 1000 * 100) / 100) +' ' + 'km';} else {output = (Math.round(length * 100) / 100) +' ' + 'm';}return output;};// 获取存放feature的vectorlayer层。map初始化的时候可以添加好了for(let layerTmp of map.getLayers().getArray()){if(layerTmp.get("name")=="feature"){source = layerTmp.getSource();}}// 测量距离function addLineInteraction() {var type = "LineString";draw = new Draw({source: source,type: type,style: new Style({fill: new Fill({color: 'rgba(255, 255, 255, 0.2)'}),stroke: new Stroke({color: 'rgba(0, 200, 255, 0.5)',lineDash: [10, 10],width: 2}),image: new CircleStyle({radius: 5,stroke: new Stroke({color: 'rgba(0, 200, 255, 0.7)'}),fill: new Fill({color: 'rgba(255, 255, 255, 0.2)'})})})});// 赋值lineDraw.value = draw;map.addInteraction(lineDraw.value);var listener;draw.on('drawstart',function (evt) {// set sketchsketch = evt.feature;/** @type {module:ol/coordinate~Coordinate|undefined} */var tooltipCoord = evt.coordinate;listener = sketch.getGeometry().on('change', function (evt) {var geom = evt.target;var output;if (geom instanceof LineString) {output = formatLength(geom);tooltipCoord = geom.getLastCoordinate();}//measureTooltipElement.innerHTML = output;// 文字没有颜色measureTooltipElement.innerHTML = "<span style='color: red;'>"+output+"</span>";measureTooltip.setPosition(tooltipCoord);});//地图双击事件map.on('dblclick', function (evt) {var point = new Point(evt.coordinate);source.addFeature(new Feature(point));});}, this);draw.on('drawend',function () {//measureTooltipElement.className = 'tooltip tooltip-static';measureTooltip.setOffset([0, -7]);// unset sketchsketch = null;// unset tooltip so that a new one can be createdmeasureTooltipElement = null;createMeasureTooltip();unByKey(listener);map.un('pointermove', pointerMoveHandler);map.removeInteraction(draw);lineHelpTooltipElement.classList.add('hidden');}, this);}function createHelpTooltip() {if (lineHelpTooltipElement) {lineHelpTooltipElement.parentNode.removeChild(lineHelpTooltipElement);}lineHelpTooltipElement = document.createElement('div');//lineHelpTooltipElement.className = 'tooltip hidden';lineHelpTooltip = new Overlay({element:lineHelpTooltipElement,offset: [15, 0],positioning: 'center-left',});map.addOverlay(lineHelpTooltip);}function createMeasureTooltip() {if (measureTooltipElement) {measureTooltipElement.parentNode.removeChild(measureTooltipElement);}measureTooltipElement = document.createElement('div');//measureTooltipElement.className = 'tooltip tooltip-measure';measureTooltip = new Overlay({element: measureTooltipElement,offset: [0, -15],positioning: 'bottom-center'});map.addOverlay(measureTooltip);}// 量测调用addLineInteraction();
}// 测面
export const measurePolygon = (map) =>{clearMeasure(map);//清空测量图层// 创建数据源var source = new VectorSource();areaVectorLayer.value = new VectorLayer({id:'Area',source: source,style: new Style({fill: new Fill({color: 'rgba(255, 255, 255, 0.2)'}),stroke: new Stroke({color: 'red',width: 2}),image: new CircleStyle({radius: 7,fill: new Fill({color: '#ffcc33'})})}),zIndex:16});map.addLayer(areaVectorLayer.value);/*** Currently drawn feature.* @type {module:ol/Feature~Feature}*/var sketch;/*** The help tooltip element.* @type {Element}*/var areaHelpTooltipElement;/*** Overlay to show the help messages.* @type {module:ol/Overlay}*/var areaHelpTooltip;/*** The measure tooltip element.* @type {Element}*/var measureTooltipElement;/*** Overlay to show the measurement.* @type {module:ol/Overlay}*/var measureTooltip;/*** Message to show when the user is drawing a polygon.* @type {string}*/var continuePolygonMsg = '';createMeasureTooltip();createHelpTooltip();/*** Handle pointer move.* @param {module:ol/MapBrowserEvent~MapBrowserEvent} evt The event.*/var pointerMoveHandler = function (evt) {if (evt.dragging) {return;}/** @type {string} */var helpMsg = '请点击开始测面';if (sketch) {var geom = (sketch.getGeometry());if (geom instanceof Polygon) {helpMsg = continuePolygonMsg;}}//areaHelpTooltipElement.innerHTML = helpMsg;//没有颜色areaHelpTooltipElement.innerHTML = "<span style='color: red;'>"+helpMsg+"</span>";areaHelpTooltip.setPosition(evt.coordinate);areaHelpTooltipElement.classList.remove('hidden');};// 监听鼠标移动方法map.on('pointermove', pointerMoveHandler);map.getViewport().addEventListener('mouseout', function () {areaHelpTooltipElement.classList.add('hidden');});var draw;var formatArea = function (polygon) {//获取投影坐标系var sourceProj = map.getView().getProjection();var area = getArea(polygon, {projection: sourceProj})//var area = getArea(polygon);//console.info(area)var output;if (area > 10000) {output = (Math.round(area / 1000000 * 100) / 100) +' ' + 'km<sup>2</sup>';} else {output = (Math.round(area * 100) / 100) +' ' + 'm<sup>2</sup>';}return output;
};// 获取存放feature的vectorlayer层。map初始化的时候可以添加好了for(let layerTmp of map.getLayers().getArray()){if(layerTmp.get("name")=="feature"){// layer = layerTmp;// layerTmp.setSource(null)source = layerTmp.getSource();}}// 测量面function addAreaInteraction() {var type = "Polygon";draw = new Draw({source: source,type: type,style: new Style({fill: new Fill({color: 'rgba(255, 255, 255, 0.2)'}),stroke: new Stroke({color: 'rgba(0, 200, 255, 0.5)',lineDash: [10, 10],width: 2}),image: new CircleStyle({radius: 5,stroke: new Stroke({color: 'rgba(0, 200, 255, 0.7)'}),fill: new Fill({color: 'rgba(255, 255, 255, 0.2)'})})})});//赋值areaDraw.value = draw;map.addInteraction(areaDraw.value);var listener;draw.on('drawstart',function (evt) {// set sketchsketch = evt.feature;/** @type {module:ol/coordinate~Coordinate|undefined} */var tooltipCoord = evt.coordinate;listener = sketch.getGeometry().on('change', function (evt) {var geom = evt.target;var output;if (geom instanceof Polygon) {output = formatArea(geom);tooltipCoord = geom.getInteriorPoint().getCoordinates();} //measureTooltipElement.innerHTML = output;// 没有颜色measureTooltipElement.innerHTML = "<span style='color: red;'>"+output+"</span>";measureTooltip.setPosition(tooltipCoord);});//地图双击事件-绘制结束时有个小黄点/* map.on('dblclick', function (evt) {var point = new Point(evt.coordinate);source.addFeature(new Feature(point));});*/}, this);draw.on('drawend',function () {//measureTooltipElement.className = 'tooltip tooltip-static';measureTooltip.setOffset([0, -7]);// unset sketchsketch = null;// unset tooltip so that a new one can be createdmeasureTooltipElement = null;createMeasureTooltip();unByKey(listener);map.un('pointermove', pointerMoveHandler);map.removeInteraction(draw);areaHelpTooltipElement.classList.add('hidden');}, this);}function createHelpTooltip() {if (areaHelpTooltipElement) {areaHelpTooltipElement.parentNode.removeChild(areaHelpTooltipElement);}areaHelpTooltipElement = document.createElement('div');//areaHelpTooltipElement.className = 'tooltip hidden';areaHelpTooltip = new Overlay({element: areaHelpTooltipElement,offset: [15, 0],positioning: 'center-left'});map.addOverlay(areaHelpTooltip);}function createMeasureTooltip() {if (measureTooltipElement) {measureTooltipElement.parentNode.removeChild(measureTooltipElement);}measureTooltipElement = document.createElement('div');//measureTooltipElement.className = 'tooltip tooltip-measure';measureTooltip = new Overlay({element: measureTooltipElement,offset: [0, -15],positioning: 'bottom-center'});map.addOverlay(measureTooltip);}// 量测调用addAreaInteraction();}// 清空测量图层
export const clearMeasure = (map) =>{// 清除测量距离if(lineVectorLayer.value != null){lineVectorLayer.value.getSource().clear();// 清除数据源map.removeLayer(lineVectorLayer.value);// 清除图层// 结束测距绘制map.removeInteraction(lineDraw.value);lineDraw.value = null;}// 清除测面if(areaVectorLayer.value != null){areaVectorLayer.value.getSource().clear();// 清除数据源map.removeLayer(areaVectorLayer.value);// 清除图层// 结束测面绘制map.removeInteraction(areaDraw.value);areaDraw.value = null;}// 清除overlays层map.getOverlays().clear();
}
三、使用方法
在**vue中引入
import {measureLine,measurePolygon,clearMeasure} from "../js/measure.js"
方法中调用:
// 测距事件
const measureDistance = () =>{// alert("测距");measureLine(props.map);
}// 测面事件
const measureArea = () =>{//alert("测面");measurePolygon(props.map);
}const clear = () =>{//alert("清除");clearMeasure(props.map);
}
注意:props.map是map.vue中传递过来的map容器对象
父组件:
<template><div class="openlayers-map"><div id="map"><BaseVue :map="map" :mapCenter="mapCenter" :mapZoom="mapZoom"/></div></div>
</template>
<script setup>
***
***const map = ref(null)
const mapCenter = ref([125.313642, 43.898338])
const mapZoom = ref(15) // 默认缩放级别//配置地图方法
***
***</script>
子组件:
// 子组件承接父组件对象
const props = defineProps({map:Map,mapCenter:[],mapZoom:Number
});
注意:如果和绘制(点、线、面等)drawTools.js一起使用需要先清除测量绘制图层,使用如下:
// 测距事件
const measureDistance = () =>{// 清除绘制drawTools.endDraw(props.map);measureLine(props.map);
}// 测面事件
const measureArea = () =>{// 清除绘制drawTools.endDraw(props.map);measurePolygon(props.map);
}const clear = () =>{clearMeasure(props.map);// 清除测量drawTools.endDraw(props.map);// 清除绘制
}