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);// 清除绘制
}
相关文章:
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/…...
各种语言的序列化与反序列化(C/C++ c# Python Javascript Java)
序列化是指将程序中的对象转换为字节序列的过程,使得对象的状态可以在网络上传输或存储到文件中。反序列化则是将字节序列恢复为程序中的对象的过程。这两个过程是数据持久化和远程通信中的关键步骤。 1. C 序列化与反序列化 在 C 中,标准库没有提供内…...
RHCE笔记
第二章:时间服务器 东八区:UTC8CST(北京时间) 应用层的时间协议:NTP(网络时间协议):udp/端口:123 Chrony软件:由chronyd(客户端)和chronyc(服务…...
Android 设置控件为圆形
Android的圆形控件 对于所有的View有效 在开发的过程中,肯定需要实现一个圆形的控件,而且不是绘制一个圆形,那么怎么弄呢,在Android5.0后,有一个类ViewOutlineProvider,可以实现这个功能,应该是…...
qt/c++中成员函数返回成员变量并且可以赋值
#创作灵感 最近在做仪表项目,由于客户提供的仪表故障指示灯只有10个固定位置,而故障指示灯却有80多个。为了解决这个问题,进过我的设计,项目中需要返回类的成员变量。并且还可以赋值给它。于是就产生了下面的代码。 class Foo { …...
【网络安全】IDOR与JWT令牌破解相结合,实现编辑、查看和删除数万帐户
未经许可,不得转载。 文章目录 前言漏洞1漏洞2修复建议在今年4月17日,笔者发过一篇关于 JWT 的文章,未学习过或稍有遗忘的朋友可以点击跳转:【网络安全 | 密码学】JWT基础知识及攻击方式详析 现分享一篇与 JWT 有关的漏洞挖掘案例。 前言 我在某公共漏洞奖励计划的应用程…...
docker安装与镜像打包
文章目录 前言一、docker安装1.1、下载docker安装包1.2、解压1.3、移动1.4、docker注册成系统服务1.5、添加文件权限1.6、设置开机启动1.7、启动docker1.8、测试是否启动 二、镜像加载2.1、镜像准备2.2、加载镜像2.3、查看已加载镜像2.4、进入镜像 三、打包镜像3.1、创建 Docke…...
“新物种”即将上线,极氪MIX是近几年最“好玩”的新车?
像极氪MIX这样有创意的新能源车 除了概念车外,市面上真的很少能看到类似的量产车 别致可爱的造型、新颖的对开门设计、百变的空间布局 同时兼顾了MPV大空间以及SUV的操控乐趣和通过性 妥妥的“新物种” A级车车长D级车轴距,配合隐藏式双B柱电动对开…...
【Flutter】路由与导航:复杂导航与深度链接
在开发大型 Flutter 应用时,复杂的导航管理是不可避免的。除了基本的页面跳转与返回操作外,很多应用会用到 嵌套路由、页面分组、TabBar 和 Drawer 的结合使用等复杂导航场景,甚至支持 深度链接 和 动态路由。本文将深入探讨这些高级导航技巧…...
07 实战:视频捕获
代码如下: import tkinter as tk # 导入tkinter库,用于创建图形用户界面 from tkinter import ttk, filedialog, messagebox # 导入tkinter的额外部件、文件对话框和消息框 import cv2 # 导入OpenCV库,用于图像处理 import numpy as np # 导入NumPy库,用于数值计算 from P…...
前端页面使用google地图api实现导航功能,开发国外网站免费简单好用
开发国外软件的时候,想使用goole map实现导航等功能,可以使用google的api来做,官方文档地址:https://developers.google.com/maps/documentation/urls/get-started?hlzh-cn ,比如: 支持的请求的操作&…...
UE4 材质学习笔记12(水体反射和折射)
一.水体反射和折射 首先就是要断开所有连接到根节点的线,因为水有很多不同的节点成分,当所有其他节点都在用时 要分辨出其中一个是何效果是很难的。 虚幻有五种不同的方法可以创建反射,虚幻中的大多数场景使用多种这些方法 它们会同时运作。…...
Go:error处理机制和函数
文章目录 error处理机制函数函数作为参数匿名函数匿名函数和闭包闭包运用闭包与工厂模式 error处理机制 本篇总结的是Go中对于错误的处理机制 Go 语言的函数经常使用两个返回值来表示执行是否成功:返回某个值以及 true 表示成功;返回零值(或…...
智能指针(3)
目录 可能问题五: 问题分析: 答案格式: shared_ptr的模拟实现 部分1:引用计数的设计(分考点1) 代码实现: 部分2:作为类所必须的部分(分考点2) 代码实现: 部分3:拷贝构造函数…...
spring源码拓展点3之addBeanPostProcesser
概述 在refresh方法中的prepareBeanFactory方法中,有一个拓展点:addBeanPostProcessor。即通过注入Aware对象从而将容器中的某些值设置到某个bean中。 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));aware接口调用 …...
【计网】理解TCP全连接队列与tcpdump抓包
希望是火,失望是烟, 生活就是一边点火,一边冒烟。 理解TCP全连接队列与tcpdump抓包 1 TCP 全连接队列1.1 重谈listen函数1.2 初步理解全连接队列1.3 深入理解全连接队列 2 tcpdump抓包 1 TCP 全连接队列 1.1 重谈listen函数 这里我们使用…...
react18中实现简易增删改查useReducer搭配useContext的高级用法
useReducer和useContext前面有单独介绍过,上手不难,现在我们把这两个api结合起来使用,该怎么用?还是结合之前的简易增删改查的demo,熟悉vue的应该可以看出,useReducer类似于vuex,useContext类似…...
排序算法 —— 冒泡排序
目录 1.冒泡排序的思想 2.冒泡排序的实现 3.冒泡排序的总结 1.冒泡排序的思想 冒泡排序的思想就是在待排序序列中依次比较相邻两个元素,将大的or小的元素往后挪,每一趟都能保证将至少一个元素挪动到正确的位置,然后在待排序序列中重复该过…...
QT--文本框 QLineEdit、qtextedit
在Qt中,文本框(QLineEdit 或 QTextEdit)和标签(QLabel)是两种不同的部件(widget),它们的主要区别在于用途和功能: QLabel(标签) 用途࿱…...
Qt编写的modbus模拟器/支持网络和串口以及websocket/支持网络rtu
一、使用说明 1.1 设备模拟-Com 第一步,填写要模拟的设备地址,0表示自动处理,也就是收到什么地址就应答什么地址。第二步,填写对应的串口号和波特率。第三步,单击打开串口,成功后会变成关闭串口字样。单击…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
