vue+leaflet笔记之地图量测

news2024/11/17 1:58:22

vue+leaflet笔记之地图量测

文章目录

  • vue+leaflet笔记之地图量测
    • 开发环境
    • 代码简介
      • 插件简介与安装
      • 使用简介
        • 图形量测
        • 动态量测
    • 详细源码(Vue3)

本文介绍了Web端使用Leaflet开发库进行距离量测的一种方法 (底图来源:天地图),结合leaflet-measure-path插件能够快速的实现地图量测功能。显示效果如下图所示。


开发环境

Vue开发库:3.2.37 & Leaflet开发库:1.9.3

Leaflet主要插件:leaflet-measure-path


代码简介

插件简介与安装

leaflet-measure-path是一个在路径的上显示测量结果的插件(目前支持线、面和圆圈),优点是简单易用,缺点是线要素的长度信息标注在最后一个点的位置觉得不太合理,测量精度的话勉强够用。

官方文档 https://github.com/ProminentEdge/leaflet-measure-path

# 插件安装
npm i leaflet-measure-path
# 插件安装(国内镜像,速度较快)
npm --registry https://registry.npm.taobao.org install leaflet-measure-path
# 引入地图量测插件 leaflet-measure-path
import 'leaflet-measure-path/leaflet-measure-path.css'
import 'leaflet-measure-path/leaflet-measure-path.js'

使用简介

图形量测

创建一些基础图形,然后利用leaflet-measure-path中的方法和属性,对图形进行量测,效果如下图所示 。

// 创建一个矢量面,并显示多边形的测量值
let polygon = L.polygon([[57.69, 11.89], [57.697, 11.88], [57.71, 11.89], [57.71, 11.91], [57.69, 11.91]], { showMeasurements: true }).addTo(map);
// 创建一个矢量面,当光标悬停在多边形上时,显示测量值的多边形
let polygonWithHover = L.polygon([[57.668, 11.89], [57.675, 11.88], [57.688, 11.89], [57.688, 11.91], [57.668, 11.91]], { showMeasurements: true, measurementOptions: { showOnHover: true } }).addTo(map);
// 创建一条折线,并显示测量值(对测量值格式化) 
L.polyline([[57.67, 11.85], [57.677, 11.86], [57.68, 11.85], [57.69, 11.86],],
  {
    showMeasurements: true, color: 'green', measurementOptions: {
      showTotalDistance:false,
      formatDistance: function valFormat(val) {
        // 测量值保留一位小数
        return '测量值:' + val.toFixed(1)
      }
    }
  }).addTo(map);
// 创建一个圆,并显示测量值
let circle = L.circle([57.699, 11.86], {
  color: 'red',
  fillColor: '#f03',
  fillOpacity: 0.5,
  radius: 300,
  showMeasurements: true,
}).addTo(map);

此外,measurementOptions还提供了几个别的属性:

属性默认值说明备注
showOnHover: Booleanfalse为true时,当用户将光标悬停在图形上时,测量值才会显示
showTotalDistance: Booleantrue为false时,则不会显示多段线的总长度
minDistance: Number30线段测量时,要素中的线段必须具有的最小长度实测,不生效
formatDistance: Function/覆盖内置函数,该函数以米为单位格式化地图中显示的字符串的距离对显示测量值格式化
formatArea: Function/覆盖内置函数,该函数将面积(平方米)格式化为地图中显示的字符串对显示测量值格式化

动态量测

在地图上动态绘制线或面,进行长度或面积的量测。

详细源码(Vue3)

源代码下载地址 链接:https://pan.baidu.com/s/1axmOSj3cc8ve26_aODISeg?pwd=GIS6
提取码:GIS6

<template>
  <div class="app-contain">
    <!-- leaflet 地图容器 -->
    <div id="myMap"></div>
    <div class="controls">
      <el-button color="#626aef" @click="handMeasureDistance()">距离量算</el-button>
      <el-button color="#626aef" @click="handMeasureArea()">面积量算</el-button>
      <el-button color="#626aef" @click="handMeasureClear()">清空</el-button>
    </div>
  </div>
</template>

<script setup>
// 引入本地标记图片
import deleteIconUrl from '/@/assets/images/deleteIcon.png'
// 引入样式
import L from 'leaflet';
import 'leaflet/dist/leaflet.css'

// 鼠标提示控件
import './store/MouseTips'
import './store/MouseTips.css'
// 引入地图量测插件 leaflet-measure-path
import 'leaflet-measure-path/leaflet-measure-path.css'
import 'leaflet-measure-path/leaflet-measure-path.js'
// 标记点
let deleteIcon = L.icon({
  iconUrl: deleteIconUrl,
  iconSize: [14, 14], // 图标大小
  iconAnchor: [7, 7], // 图标偏移量,否则无法居住显示
});
import { onMounted } from 'vue'
// 天地图TK
let tdtKey = 'YOURS_TK'
// 地图
let map = null;
// 创建鼠标提示控件
let mouseTips = L.control.mouseTips({
  show: true,
  message: '鼠标单击左键加点,双击结束'
});
// 距离测量方法
let distanceMeasure = {
  points: [],
  color: "red",
  layers: L.layerGroup(),
  polyline: null,
  polylineGroup: [],
  marker: null,
  markerGroup: [],
  init: function () {
    distanceMeasure.points = [];
    distanceMeasure.polyline = null;
    distanceMeasure.marker = null;
    map.on('click', distanceMeasure.click).on('dblclick', distanceMeasure.dblclick);
  },
  click: function (e) {
    map.doubleClickZoom.disable();
    // 添加点信息
    distanceMeasure.points.push(e.latlng);
    // 添加线
    map.on('mousemove', distanceMeasure.mousemove);
  },
  mousemove: function (e) {
    distanceMeasure.points.push(e.latlng);
    if (distanceMeasure.polyline)
      map.removeLayer(distanceMeasure.polyline);
    distanceMeasure.polyline = L.polyline(distanceMeasure.points, { showMeasurements: true, color: distanceMeasure.color });
    distanceMeasure.polyline.addTo(distanceMeasure.layers);
    distanceMeasure.layers.addTo(map);
    distanceMeasure.points.pop();
  },
  dblclick: function (e) { // 双击结束
    // 移除鼠标绘制提示
    mouseTips.hide()
    distanceMeasure.polyline.addTo(distanceMeasure.layers);
    distanceMeasure.polylineGroup.push(distanceMeasure.polyline)
    map.off('click', distanceMeasure.click).off('mousemove', distanceMeasure.mousemove).off('dblclick', distanceMeasure.dblclick);
  },
  destory: function () {
    if (distanceMeasure.polyline) {
      // map.removeLayer(distanceMeasure.polyline);
      distanceMeasure.polylineGroup.forEach(element => {
        map.removeLayer(element);
      });
    }

    if (distanceMeasure.marker) {
      // distanceMeasure.marker.remove();
      distanceMeasure.markerGroup.forEach(element => {
        element.remove()
      })
    }

  }
}
// 面积测量方法
let areaMeasure = {
  points: [],
  color: "red",
  layers: L.layerGroup(),
  polygon: null,
  polygonGroup: [],
  marker: null,
  markerGroup: [],
  init: function () {
    areaMeasure.points = [];
    areaMeasure.polygon = null;
    areaMeasure.marker = null;
    map.on('click', areaMeasure.click).on('dblclick', areaMeasure.dblclick);
  },
  close: function (latlng) {
    areaMeasure.marker = L.marker(latlng, { icon: deleteIcon }).addTo(map).on("click", function (e) {
      if (areaMeasure.polygon)
        map.removeLayer(areaMeasure.polygon);

      if (areaMeasure.marker)
        areaMeasure.marker.remove();
    });
    areaMeasure.markerGroup.push(areaMeasure.marker);
  },
  click: function (e) {
    map.doubleClickZoom.disable();
    // 添加点信息
    areaMeasure.points.push(e.latlng);
    // 添加面
    map.on('mousemove', areaMeasure.mousemove);
  },
  mousemove: function (e) {
    areaMeasure.points.push(e.latlng);
    if (areaMeasure.polygon)
      map.removeLayer(areaMeasure.polygon);
    areaMeasure.polygon = L.polygon(areaMeasure.points, { showMeasurements: true, color: areaMeasure.color });
    areaMeasure.polygon.addTo(areaMeasure.layers);
    areaMeasure.layers.addTo(map);
    areaMeasure.points.pop();
  },
  dblclick: function (e) { // 双击结束
    // 移除鼠标绘制提示
    mouseTips.hide()
    areaMeasure.polygon.addTo(areaMeasure.layers);
    areaMeasure.polygonGroup.push(areaMeasure.polygon)
    areaMeasure.close(e.latlng);
    map.off('click', areaMeasure.click).off('mousemove', areaMeasure.mousemove).off('dblclick', areaMeasure.dblclick);
  },
  destory: function () {
    if (areaMeasure.polygon) {
      areaMeasure.polygonGroup.forEach(element => {
        map.removeLayer(element);
      });
    }
    if (areaMeasure.marker) {
      areaMeasure.markerGroup.forEach(element => {
        element.remove()
      })
    }

  }
}
// 地图初始化
const initMap = () => {
  //影像地图
  const sourceMap = L.tileLayer(`https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}`)
  // 注记
  const tiandituText = L.tileLayer(`http://t0.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${tdtKey}`)
  const layers = L.layerGroup([sourceMap, tiandituText])
  map = L.map('myMap', {  //需绑定地图容器div的id
    attributionControl: false,
    zoomControl: true, // 显示缩放控件
    // 最小显示等级
    minZoom: 1,
    // 最大显示等级
    maxZoom: 18,
    crs: L.CRS.EPSG3857,//设置坐标系类型  EPSG3857伪墨卡托投影
    scrollWheelZoom: true, //默认开启鼠标滚轮缩放
    // 限制显示地理范围
    maxBounds: L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180)),
    // 限制显示地理范围
    layers: [layers] // 图层
  }).setView([30, 120], 6)
  // 添加比例尺
  L.control.scale({ maxWidth: 240, metric: true, imperial: false, position: 'bottomleft' }).addTo(map);
}
// 距离量测
const handMeasureDistance = () => {
  // 鼠标绘制提示
  mouseTips.addTo(map).show();
  distanceMeasure.init()
}
// 面积量测
const handMeasureArea = () => {
  // 鼠标绘制提示
  mouseTips.addTo(map).show();
  areaMeasure.init()
}
// 清空量测内容
const handMeasureClear = () => {
  // 鼠标绘制提示
  mouseTips.addTo(map).hide();
  // 销毁测量组件
  distanceMeasure.destory()
  areaMeasure.destory()
}
onMounted(() => {
  initMap()
})
</script>

<style scoped>
#myMap {
  width: 94vw;
  height: 96vh;
}

.controls {
  position: absolute;
  top: 0px;
  left: 200px;
  padding: 15px;
  z-index: 1000;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能术语翻译(四)

文章目录 摘要MNOP 摘要 人工智能术语翻译第四部分&#xff0c;包括I、J、K、L开头的词汇&#xff01; M 英文术语中文翻译常用缩写备注Machine Learning Model机器学习模型Machine Learning机器学习ML机器学习Machine Translation机器翻译MTMacro Average宏平均Macro-F1宏…

高忆管理:msci成分股什么意思?

MSCI&#xff08;Morgan Stanley Capital International&#xff09;是全球领先的金融指数提供商之一&#xff0c;其指数被广泛应用于全球资本商场的出资和危险办理。而MSCI成分股&#xff0c;是指MSCI指数中所包括的股票。那么&#xff0c;MSCI成分股具体意义是什么呢&#xf…

CTFshow-pwn入门-pwn67(nop sled空操作雪橇)

前言 本人由于今年考研可能更新的特别慢&#xff0c;不能把ctfshow的pwn入门题目的wp一一都写出来了&#xff0c;时间比较紧啊&#xff0c;只能做高数做累的时候做做pwn写写wp了&#xff0c;当然我之后只挑典型意义的题目写wp了&#xff0c;其余的题目就留到12月底考完之后再写…

Sugar BI : AI 问答,即问即答

AI 探索功能提供给所有用户自由探索和分析数据模型的能力。在 AI 探索页中&#xff0c;有授权的用户可以通过 AI 问答和字段拖拽两种方式对数据模型进行探索。 下面&#xff0c;我们将为大家详细指导如何使用 AI 探索 新建 AI 探索页 空间管理员可以在报表管理中新建「AI 探索…

短视频矩阵系统源码---开发技术源码能力

短视频矩阵系统开发涉及到多个领域的技术&#xff0c;包括视频编解码技术、大数据处理技术、音视频传输技术、电子商务及支付技术等。因此&#xff0c;短视频矩阵系统开发人员需要具备扎实的计算机基础知识、出色的编程能力、熟练掌握多种开发工具和框架&#xff0c;并掌握音视…

UE Web Remote Control call python script

UE Web Remote Control call python script UE 远程调用Python(UE Python API)脚本 Web Remote Control 在网页客户端远程操作虚幻引擎项目。 虚幻编辑器提供了一套强大的工具&#xff0c;几乎可以操纵项目内容的方方面面。但在某些情况下&#xff0c;要在大型内容编辑流程中…

使用SVM模型完成分类任务

SVM&#xff0c;即支持向量机&#xff08;Support Vector Machine&#xff09;&#xff0c;是一种常见的机器学习算法&#xff0c;用于分类和回归分析。SVM的基本思想是将数据集映射到高维空间中&#xff0c;在该空间中找到一个最优的超平面&#xff0c;将不同类别的数据点分开…

国企普通员工如何才能成为公务员,这三种途径可供参考

国企普通员工如何转变成公务员&#xff1f;作为国企普通员工&#xff0c;如果要成为国家公务员&#xff0c;其主要的路径有三个方面&#xff0c;一是符合国家公务员法规定的公务员招录条件要求的&#xff0c;可以报考国家公务员&#xff1b;二是在国有企业担任领导职务&#xf…

使用EM算法完成聚类任务

EM算法&#xff08;Expectation-Maximization Algorithm&#xff09;是一种基于迭代优化的聚类算法&#xff0c;用于在无监督的情况下将数据集分成几个不同的组或簇。EM算法是一种迭代算法&#xff0c;包含两个主要步骤&#xff1a;期望步骤&#xff08;E-step&#xff09;和最…

子网重叠测试

子网重叠的两个网络可以相互通 虽然子网掩码不同&#xff0c;但是 R1 可以 ping R2&#xff1a; <R1>ping 10.0.12.14PING 10.0.12.14: 56 data bytes, press CTRL_C to breakReply from 10.0.12.14: bytes56 Sequence1 ttl255 time50 msReply from 10.0.12.14: bytes5…

Verilog语法学习——LV4_移位运算与乘法

LV4_移位运算与乘法 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 题目描述&#xff1a; 已知d为一个8位数&#xff0c;请在每个时钟周期分别输出该数乘1/…

利用小波分解信号,再重构

function [ output_args ] example4_5( input_args ) %EXAMPLE4_5 Summary of this function goes here % Detailed explanation goes here clc; clear; load leleccum; s leleccum(1:3920); % 进行3层小波分解&#xff0c;小波基函数为db2 [c,l] wavedec(s,3,db2); %进行…

剑指 Offer 37. 序列化二叉树 / LeetCode297. 二叉树的序列化与反序列化(二叉树遍历(深度优先搜索))

题目&#xff1a; 链接&#xff1a;剑指 Offer 37. 序列化二叉树&#xff1b;LeetCode 297. 二叉树的序列化与反序列化 难度&#xff1a;困难 序列化是将一个数据结构或者对象转换为连续的比特位的操作&#xff0c;进而可以将转换后的数据存储在一个文件或者内存中&#xff0…

【雕爷学编程】Arduino动手做(99)---8X32 LED点阵屏模块3

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

基于Java+SpringBoot+vue前后端分离新闻推荐系统设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

windows系统MySQL5.7小版本升级

此次是windows系统下&#xff0c;将mysql 5.7.38升级到5.7.43&#xff08;当前最新版本&#xff09;。 由于是第一次升级mysql数据库&#xff0c;在网上看了好多资料&#xff0c;发现升级都挺麻烦的&#xff0c;后来无意中看到一篇文章&#xff0c;升级超级简单&#xff0c;地…

【VTK】基于读取出来的 STL 模型,当用户点击鼠标左键时,程序将获取点击位置的点,显示其坐标,并设置它为模型的旋转原点

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 文章目录 class PointPickedSignal : public QObjectclass MouseInteractorCommand : public vtkCommandvoid A::on_pushButtonSelected_clicked()void A::on…

2023牛客多校第三场 B.Auspiciousness

传送门 前题提要:没得说,赛时根本没想到dp,赛后翻各大题解看了很久,终于懂了dp的做法,故准备写一篇题解. 首先,先定义一下我们的 d p dp dp方程,考虑将处于 [ 1 , n ] [1,n] [1,n]的数当做小数,将处于 [ n 1 , 2 ∗ n ] [n1,2*n] [n1,2∗n]的数当做大数.那么对于我们的摸牌结…

CorelDraw怎么做立体字效果?CorelDraw制作漂亮的3d立体字教程

1、打开软件CorelDRAW 2019&#xff0c;用文本工具写上我们所需要的大标题。建议字体选用比较粗的适合做标题的字体。 2、给字填充颜色&#xff0c;此时填充的颜色就是以后立体字正面的颜色。我填充了红色&#xff0c;并加上了灰色的描边。 3、选中文本&#xff0c;单击界面左侧…

04-树6 Complete Binary Search Tree

思路&#xff1a; 先排序 用数组建一棵空树 中序遍历填数 顺序输出即为层次遍历