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 sketch
        sketch = 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 sketch
        sketch = null;
        // unset tooltip so that a new one can be created
        measureTooltipElement = 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 sketch
        sketch = 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 sketch
        sketch = null;
        // unset tooltip so that a new one can be created
        measureTooltipElement = 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);// 清除绘制
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/897212.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【linux】线程 (三)

13. 常见锁概念 &#xff08;一&#xff09;了解死锁 死锁是指在一组进程中的各个进程均占有不会释放的资源&#xff0c;但因互相申请被其他进程占有的&#xff0c;且不释放的资源&#xff0c;而处于的一种永久等待状态 &#xff08;二&#xff09;死锁四个必要条件 互斥条件…

基准线markLine的值超过坐标轴范围导致markline不显示

解决问题&#xff1a;动态设置yAxis的max值&#xff08;解决基准线不在y轴范围&#xff09; yAxis: [{name: 单位&#xff1a;千,...yAxis,nameTextStyle:{...yAxis.nameTextStyle,padding: [0,26,0,24]},paddingLeft:24,paddingRight:26},{name: 单位&#xff1a;百分比,...yA…

Java开发中知识点整理

正则表达式 测试网址 List<?> List<List<Object>> dataList (List<List<Object>>) httpResponseBody.getData();for (List<Object> data : dataList) {DataSourceEntity dataSource new DataSourceEntity(dataSourceEntity);dataSou…

【二刷hot100】day 4

终于有时间刷刷力扣&#xff0c;求实习中。。。。 目录 1.最大子数组和 2.合并区间 3.轮转数组 4.除自身以外数组的乘积 1.最大子数组和 class Solution {public int maxSubArray(int[] nums) {//就是说可以转换为计算左边的最大值&#xff0c;加上中间的值&#xff0c…

Git的原理和使用(六)

本文主要讲解企业级开发模型 1. 引入 交付软件的流程&#xff1a;开发->测试->发布上线 上面三个过程可以详细划分为一下过程&#xff1a;规划、编码、构建、测试、发 布、部署和维护 最初&#xff0c;程序⽐较简单&#xff0c;⼯作量不⼤&#xff0c;程序员⼀个⼈可以完…

一文详解“位运算“在算法中的应用

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; 优选算法专题 目录 位运算的相关介绍&#xff08;重要&#xff09; 136. 只出现一次的数字 191.位1的个数 461. 汉明距离 260. 只出现一…

大模型的经典面试问题及答案,非常详细收藏我这一篇就够了

大语言模型&#xff08;LLM&#xff09;在人工智能中变得越来越重要&#xff0c;在各个行业都有应用。随着对大语言模型专业人才需求的增长&#xff0c;本文提供了一套全面的面试问题和答案&#xff0c;涵盖了基本概念、先进技术和实际应用。如果你正在为面试做准备&#xff0c…

【优选算法篇】在分割中追寻秩序:二分查找的智慧轨迹

文章目录 C 二分查找详解&#xff1a;基础题解与思维分析前言第一章&#xff1a;热身练习1.1 二分查找基本实现解题思路图解分析C代码实现易错点提示代码解读 1.2 在排序数组中查找元素的第一个和最后一个位置解题思路1.2.1 查找左边界算法步骤&#xff1a;图解分析C代码实现 1…

国产大模型基础能力大比拼 - 计数:通义千文 vs 文心一言 vs 智谱 vs 讯飞-正经应用场景的 LLM 逻辑测试

在大语言模型&#xff08;LLM&#xff09;不断涌现的时代&#xff0c;如何评估这些国产大模型的逻辑推理能力&#xff0c;尤其是在处理基础计数问题上的表现&#xff0c;成为了一个备受关注的话题。随着越来越多的国产大模型进入市场&#xff0c;比较它们在不同任务中的表现尤为…

群晖通过 Docker 安装 Gitea

1. 准备工作 1.1 安装 docker 套件 2.2 安装MySQL&#xff08;可选&#xff09; 群晖通过 Docker 安装 MySQL-CSDN博客 如果安装了MySQL&#xff0c;可以创建gitea用户和gitea_db数据库&#xff0c;并且赋予权限 #创建数据库 CREATE DATABASE gitea_db; #确认数据库已创建…

【Jenkins】2024 最新版本的 Jenkins 权限修改为 root 用户启动,解决 permission-denied 报错问题

最新版本的 Jenkins 修改 /etc/sysconfig/jenkins 中的 JENKINS_USERroot不会再生效&#xff0c;需要按照以下配置进行操作&#xff1a; vim /usr/lib/systemd/system/jenkins.service然后重启就可以了 systemctl daemon-reload # 重新加载 systemd 的配置文件 systemctl res…

JavaEE 多线程第三节 (lambda方法实现多线程/Thread属性和方法/前台线程后台线程)

欢迎阅读前序课程JavaEE 多线程第二节 (多线程的简单实现Thread/Runable)-CSDN博客 1. lambda方法实现多线程 public class Test {public static void main(String[] args) throws InterruptedException {Thread t new Thread(()->{while (true){System.out.println("…

探索云边缘与边缘云:技术革新与应用前景

#1024程序员节&#xff5c;征文# 在当今数字化快速发展的时代&#xff0c;云计算已经成为了企业和个人处理和存储数据的重要手段。然而&#xff0c;随着物联网&#xff08;IoT&#xff09;设备的爆炸式增长以及对低延迟、高带宽和实时处理的需求不断增加&#xff0c;云边缘和边…

简单介绍市面上的四款录屏软件!!!!

数字化时代&#xff0c;无论是工作还是生活中&#xff0c;录屏已经成为一个不可或缺的工具。然而&#xff0c;选择一款适合自己需求的录屏软件却并不容易。今日来为大家推荐四款超好用的录屏软件&#xff0c;分析这些软件的优缺点&#xff0c;让你在各种场景下都能轻松捕捉精彩…

vue3 解决背景图与窗口留有间隙的问题

需要实现一个登录界面&#xff0c;login.vue的代码如下&#xff1a; <script> import { ref } from vue;export default {setup() {return {};}, }; </script><template><div id"login-container" class"login-container"><di…

Tcp协议讲解与守护进程

TCP协议&#xff1a;面向链接&#xff0c;面向字节流&#xff0c;可靠通信 创建tcp_server 1.创建套接字 域&#xff1a;依旧选择AF_INET 连接方式&#xff1a; 选择SOCK_STREAM 可靠的 2.bind 3.监听装置 client要通信&#xff0c;要先建立连接&#xff0…

Allegro怎么批量将弧形线改成45度角的线?

Allegro如何将弧形线改成45度角的线? 在用Allegro进行PCB设计时,有时候需要将弧形线改为45度角的线。 具体操作方法如下: 1、选择菜单栏Route 选择Unsupported Prototypes(不支持的原型)→AICC 2、在Options选项卡选择45度 3、在Find选项卡选择Nets,选择网络可以批量转换…

浮动练习(3)

##每台电脑分辨率不同&#xff0c;数值高度宽度需要自己调&#xff0c;仅供参考 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title></title> <style> div{ …

JMeter详细介绍和相关概念

JMeter是一款开源的、强大的、用于进行性能测试和功能测试的Java应用程序。 本篇承接上一篇 JMeter快速入门示例 &#xff0c; 对该篇中出现的相关概念进行详细介绍。 JMeter测试计划 测试计划名称和注释&#xff1a;整个测试脚本保存的名称&#xff0c;以及对该测试计划的注…

《使用Gin框架构建分布式应用》阅读笔记:p108-p126

《用Gin框架构建分布式应用》学习第8天&#xff0c;p108-p126总结&#xff0c;总计18页。 一、技术总结 1.Redis eviction policy (1)什么是 eviction policy? The eviction policy determines what happens when a database reaches its memory limit. (2)配置示例 在r…