Vue实现leafletMap自定义绘制线段 并且删除指定的已绘制的点位
效果:点击表格可实现选中地图点位,删除按钮点击可删除对应点位并且重新绘制线段,点击确定按钮 保存已经绘制的点位信息传给父组件 并且该组件已实现回显


完整的组件代码如下 文件名称为:
leafletMakePointYt
<!--* @Description: leaflet 地图选择点位 实现画线 页面* @Author: mhf* @Date: 2023-05-30 18:23:37
-->
<template><el-dialogwidth="1300px"append-to-bodyv-dialog-outv-if="dialogVisible":title="title":visible.sync="dialogVisible":close-on-click-modal="false":before-close="hideDialog"><div><!-- 地图盒子 --><div id="map"></div><!-- 左侧坐标展示框 --><div class="points-box"><!-- 顶部标题 --><div class="points-box-title"><span> 线路坐标 </span></div><!-- 坐标展示表 --><div class="points-box-table"><el-tablehighlight-current-row@current-change="handleCurrentChange":data="pointsArr"style="width: 100%":height="tableHeight"><el-table-column label="#" type="index" /><el-table-column prop="lat" label="经度" width="158" /><el-table-column prop="lng" label="纬度" width="158" /><el-table-columnlabel="操作"width="60"fixed="right"v-if="showBtn"><template slot-scope="scope"><el-button type="text" size="small" @click="delRow(scope)">删除</el-button></template></el-table-column></el-table></div><!-- 坐标盒子 底部按钮组 --><div v-if="showBtn" class="points-box-btn"><el-button type="" size="" @click="clearMapLine"> 清除</el-button><el-button type="primary" size="" @click="makeMapLine">开始</el-button><el-button type="primary" size="" @click="endMakeLine">结束</el-button></div></div></div><!-- 弹窗底部按钮组 --><div v-if="showBtn" slot="footer" class="dialog-footer"><el-button @click="hideDialog">取 消</el-button><el-button type="primary" @click="submitPoints()">确 定</el-button></div></el-dialog>
</template><script>
import L from "leaflet";
import "leaflet/dist/leaflet.css";
// 引入互联网地图插件
require("@/utils/leftletMap/leaflet.ChineseTmsProviders.js");
require("@/utils/leftletMap/tileLayer.baidu.js");
// 引入互联网地图纠偏插件
require("@/utils/leftletMap/leaflet.mapCorrection.min.js");export default {name: "leafletMakePointYt",components: {},props: {showBtn: {type: Boolean,default: true,},},data() {return {dialogVisible: false,title: "",map: null,iconStyle: {icon: L.icon({iconUrl: require("/public/img/mapIcon/point.png"),iconSize: [12, 12],// iconAnchor: [19, 19],// popupAnchor: [0, -10]}),}, // 点位图标样式chooseIconStyle: {icon: L.icon({iconUrl: require("/public/img/mapIcon/marker.png"),iconSize: [30, 30],iconAnchor: [18, 22],}),}, // 表格中选中的点位图标样式startIconStyle: {icon: L.icon({iconUrl: require("/public/img/mapIcon/startPoint.png"),iconSize: [30, 30],iconAnchor: [18, 22],}),}, // 起点点位图标样式endIconStyle: {icon: L.icon({iconUrl: require("/public/img/mapIcon/endPoint.png"),iconSize: [30, 30],iconAnchor: [18, 22],}),}, // 终点点位图标样式polylineStyle: {color: "#FF6B00",weight: 4,}, // 线条样式pointsArr: [], // 标记点位列表 [{lat: 30, lng: 120}, {lat: 31, lng: 121}]pointsArrMarker: [], // 已经绘制的点位polylineArr: [], // 已经绘制多条线段chooseMarker: undefined, // 当前选中的点位tableHeight: 440,loading: false, // loading 动画loadingInstance: null,};},methods: {hideDialog() {this.dialogVisible = false;this.map.remove();this.map = null;},submitPoints() {if (this.pointsArr.length < 2) {this.$message.warning("请先绘制线路");} else {this.$emit("on-response", this.pointsArr); // 将绘制好的坐标传递给父组件this.hideDialog();}},showDialog(data) {this.dialogVisible = true;this.title = data.title;this.$nextTick(() => {/* 避免重复渲染 */if (!this.map) this.initMap();this.handleResize();if (data.data) {this.pointsArr = JSON.parse(data.data);/* 线段回显 */var polyline = L.polyline(this.pointsArr, this.polylineStyle).addTo(this.map);this.polylineArr.push(polyline);/* 点位回显 */this.pointsArr.forEach((item, index) => {var marker = L.marker([item.lat, item.lng], this.iconStyle).addTo(this.map); // 添加标记点this.pointsArrMarker.push(marker);});}});},/*** @Event 方法* @description: 初始化 leaflet 地图* */initMap() {this.map = L.map("map", {center: [30.194637, 120.122247],zoom: 13,attributionControl: false, // 隐藏logozoomControl: false, // 默认缩放控件(仅当创建地图时该 zoomControl 选项是 true)。crs: L.CRS.Baidu, // 用于 WMS 请求的坐标参考系统,默认为映射 CRS。 如果您不确定它的含义,请不要更改它。});L.control.zoom({position: "bottomright",}).addTo(this.map);L.tileLayer.baidu({ layer: "vec" }).addTo(this.map); // 添加底图},/*** @Event 方法* @description: 开始画线* */makeMapLine() {this.map.getContainer().style.cursor = "crosshair"; // 更改鼠标样式// let index = -1var marker, polyline;this.map.on("click", (e) => {// index++// if (index === 0) {/* 设置起点 */// L.marker([e.latlng.lat, e.latlng.lng], this.startIconStyle).addTo(this.map);/* 设置起点 */// } else {marker = L.marker([e.latlng.lat, e.latlng.lng], this.iconStyle).addTo(this.map); // 添加标记点// }this.pointsArrMarker.push(marker);this.pointsArr.push(e.latlng); // 添加点位坐标至点位数组polyline = L.polyline(this.pointsArr, this.polylineStyle).addTo(this.map); // 创建单条线段this.polylineArr.push(polyline);});},/*** @Event 方法* @description: 结束画线* */endMakeLine() {if (this.pointsArr === [] || this.pointsArr.length === 0) {this.$message.warning("请先绘制线路");} else {this.map.getContainer().style.cursor = "grab"; // 更改鼠标样式this.map.fitBounds(this.polylineArr[this.polylineArr.length - 1].getBounds()); // 缩放地图以适应标记和线条this.map.on("mousedown", (e) => {this.map.getContainer().style.cursor = "grabbing"; // 更改鼠标样式});this.map.on("mouseup", (e) => {this.map.getContainer().style.cursor = "grab"; // 更改鼠标样式});this.map.off("click"); // 关闭点击事件}},/*** @Event 方法* @description: 移除线段和点位* */clearMapLine() {if (this.pointsArr === [] || this.pointsArr.length === 0) {} else {/* 移除点位 */this.pointsArrMarker.forEach((marker) => {this.map.removeLayer(marker);});/* 移除线段 */this.polylineArr.forEach((polyline) => {polyline.remove();});this.endMakeLine(); // 结束画线this.polylineArr = [];this.pointsArr = [];}},/*** @Event 方法* @description: 动态改变表格的高度* */handleResize() {const height = document.querySelector(".points-box-table").offsetHeight;this.tableHeight = height - 10;},/*** @Event 方法* @description: 表格单行选中事件,实现每次点击时都能删除上一次点击的图标* */handleCurrentChange(row) {if (this.chooseMarker) {this.map.removeLayer(this.chooseMarker);}this.chooseMarker = L.marker([row.lat, row.lng],this.chooseIconStyle).addTo(this.map); // 添加标记点},/*** @Event 方法* @description: 删除表格单行数据并且移除该点位* */delRow(row) {this.loading = true;this.$nextTick(() => {const target = document.querySelector(".el-dialog__body");let options = {lock: true,text: "重新绘制中...",spinner: "el-icon-loading",background: "rgba(0, 0, 0, 0.7)",};this.loadingInstance = this.$loading(options, target);});setTimeout(() => {this.loading = false;this.loadingInstance.close();/* 删除点位 */this.map.removeLayer(this.pointsArrMarker[row.$index]);this.pointsArrMarker.splice(row.$index, 1); // 已经绘制的点位this.pointsArr.splice(row.$index, 1); // 标记点位列表/* 删除点位 *//* 删除线段 */this.polylineArr.forEach((polyline) => {polyline.remove();});var polyline = L.polyline(this.pointsArr, this.polylineStyle).addTo(this.map);this.polylineArr.push(polyline);/* 删除线段 */}, 500);},},created() {},mounted() {window.addEventListener("resize", this.handleResize);},destroyed() {window.removeEventListener("resize", this.handleResize);},
};
</script><style lang="scss" scoped>
.dialog-footer {text-align: center;
}#map {height: 68vh;
}.points-box {width: 426px;height: 570px;position: absolute;top: 100px;z-index: 99999 !important;background-color: #fff;left: 40px;&-title {height: 40px;background-color: #1492ff;font-size: 18px;color: #ffffff;line-height: 40px;padding: 0 20px;}&-table {height: 490px;}&-btn {height: 50px;position: absolute;padding-bottom: 18px;bottom: 0;left: 0;right: 0;margin: auto;width: 80%;display: flex;justify-content: space-around;align-items: center;}
}
</style>
<el-form-item label="线路轨迹 : " prop="assetSection.point"><el-inputv-model="formData.assetSection.point"disabledplaceholder=""><template slot="append"><div class="choose-class" @click="showLeafletMap"><i class="iconfont if-ditudingwei" /> <span>选择</span></div></template></el-input></el-form-item><leafletMakePointYt ref="leafletMakePointYt" @on-response="getPoints" />// 打开弹窗 showLeafletMap() {let passData = {title: "选择线路轨迹",data: this.formData.assetSection.point,};this.$refs.leafletMakePointYt.showDialog(passData);},// passData: {
title: "选择线路轨迹",
data: "[{"lat":30.19398904706604,"lng":120.1454230189172},{"lat":30.204226626758985,"lng":120.19285355280543},{"lat":30.22270148713875,"lng":120.13162504542244},{"lat":30.189494160206575,"lng":120.15490912569484}]"
}// 接收弹窗的点位数据getPoints(data) {this.$set(this.formData.assetSection, "point", JSON.stringify(data));this.$set(this.formData.assetSection, "startLongitude", data[0].lng);this.$set(this.formData.assetSection, "startLatitude", data[0].lat);this.$set(this.formData.assetSection,"endLongitude",data[data.length - 1].lng);this.$set(this.formData.assetSection,"endLatitude",data[data.length - 1].lat);},

相关文章:
Vue实现leafletMap自定义绘制线段 并且删除指定的已绘制的点位
效果:点击表格可实现选中地图点位,删除按钮点击可删除对应点位并且重新绘制线段,点击确定按钮 保存已经绘制的点位信息传给父组件 并且该组件已实现回显 完整的组件代码如下 文件名称为: leafletMakePointYt <!--* Descripti…...
ChatGPT辅助写论文:提升效率与创造力的利器
写作是人类最重要的交流方式之一,也是学术研究中不可或缺的环节。然而,写作并不是一件容易的事情,尤其是对于科研人员来说,他们需要花费大量的时间和精力来撰写高质量的论文,并且面临着各种各样的挑战,如语…...
面试攻略,Java 基础面试 100 问(六)
JAVA 泛型 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本 质是参数化类型,也就是说所操作的数据类型被指定为一个参数。比如我们要写一个排序方法, 能够对整型数组、字符串数组甚至其他任何类型的…...
图解系列 DNS查找过程和DNS缓存
DNS 充当地址簿。它将人类可读的域名 (google.com) 转换为机器可读的 IP 地址 (142.251.46.238)。 开局一张图 来自:https://xiaolishen.medium.com/the-dns-lookup-journey-240e9a5d345c 寻址流程 查询浏览器缓存:当你输入一个域名后,浏览…...
《吐血整理》高级系列教程-吃透Fiddler抓包教程(21)-如何使用Fiddler生成Jmeter脚本-上篇
1.简介 我们知道Jmeter本身可以录制脚本,也可以通过BadBoy,BlazeMeter等工具进行录制,其实Fiddler也可以录制Jmter脚本(而且有些页面,由于安全设置等原因,使用Jmeter直接无法打开录制时,这时就…...
vim中出现复制不对齐-乱码问题
不对齐解决: 使用纯文本模式粘贴:在进入 Vim 编辑器后,先按下 :set paste 进入插入模式,然后再进行粘贴操作。这样可以确保粘贴的文本以纯文本格式插入,而不会触发自动缩进或其他格式化操作 中文乱码问题:…...
华为OD机考真题--单词接龙--带答案
2023华为OD统一考试(AB卷)题库清单-带答案(持续更新)or2023年华为OD真题机考题库大全-带答案(持续更新) 题目描述: 单词接龙的规则是: 用于接龙的单词首字母必须要前一个单词的尾字母…...
排序进行曲-v3.0
文章目录 小程一言归并排序步骤举例总结时间复杂度分析:空间复杂度分析:注意 应用场景总结 实际举例Other 代码实现结果解释 小程一言 这篇文章是在排序进行曲2.0之后的续讲, 这篇文章主要是对归并排序进行细致分析,以及操作。 希…...
编辑列表操作时的一些思考,关于全量和增量操作
假设我有一个这样的页面,需要对用户的信息做编辑操作 角色下面有一些菜单项,通过一张角色-菜单关系表来维护,那么我要在编辑用户后也要对用户角色关系表做修改,是经过两次比较分别计算出需要增加或者删除的角色用户关系࿰…...
【python】Python tkinter库实现重量单位转换器的GUI程序
文章目录 前言学到什么?导入模块和库创建一个GUI窗口定义函数 from_kg()创建标签、输入框、文本框和按钮设置组件的布局运行窗口循环完整代码运行效果结束语 前言 这段代码是一个简单的重量单位转换器的 GUI 程序,使用了 Python 的 tkinter 库来创建图形界面。该程…...
CVPR2023新作:源数据集对迁移学习性能的影响以及相应的解决方案
Title: A Data-Based Perspective on Transfer Learning (迁移学习的基于数据的观点) Affiliation: MIT (麻省理工学院) Authors: Saachi Jain, Hadi Salman, Alaa Khaddaj, Eric Wong, Sung Min Park, Aleksander Mądry Keywords: transfer learning, source dataset, dow…...
《TCP IP 网络编程》第十五章
第 15 章 套接字和标准I/O 15.1 标准 I/O 的优点 标准 I/O 函数的两个优点: 除了使用 read 和 write 函数收发数据外,还能使用标准 I/O 函数收发数据。下面是标准 I/O 函数的两个优点: 标准 I/O 函数具有良好的移植性标准 I/O 函数可以利用…...
新特性解读 | MySQL 8.0 字段信息统计机制
作者通过一个案例详细说明了 MySQL 8.0 字段信息统计机制的相关参数和使用方式。 作者:杨奇龙 网名“北在南方”,资深 DBA,主要负责数据库架构设计和运维平台开发工作,擅长数据库性能调优、故障诊断。 本文来源:原创投…...
基于Java+Swing实现超级玛丽游戏
基于JavaSwing实现超级玛丽游戏 一、系统介绍二、功能展示三、其他系统 一、系统介绍 超级玛丽小游戏的JAVA程序,进入游戏后首先按空格键开始,利用方向键来控制的马里奥的移动,同时检测马里奥与场景中的障碍物和敌人的碰撞,并判断…...
Day12-1-Webpack前端工程化开发
Webpack前端工程化 1 案例-webpack打包js文件 1 在index.html中编写代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><me…...
JUnit教程_编程入门自学教程_菜鸟教程-免费教程分享
教程简介 JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。 JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。JUnit是由 Erich Gamma 和…...
Hive 安装介绍
介绍 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。 其本质是将SQL转换为MapReduce的任务进行运算,底层由HDFS来提供数据的存储,说白了hive可以理解为一个将SQL转换为Ma…...
npm ERR! code EPERM npm ERR! syscall unlink npm ERR!错误解决方法
npm ERR! code EPERM npm ERR! syscall unlink npm ERR!错误解决方法 1、问题描述2、解决方法 1、问题描述 由于之前电脑系统的原因,电脑重置了一下,之前安装的环境都没了,然后在重新安装node.js后在使用npm安装时总是报如下错误:…...
redis 高级篇4 分布式锁
一 redis架构图 1.1 redis的架构图 1.2 分布式锁满足条件 1.独占性;2.高可用;3.防死锁;4.不乱抢;5.重入性 二 分布式锁的案例情况 2.1 分布式锁1:单机分布式部署 描述: 使用lock锁和synchronized,单机…...
TPU-NNTC 编译部署LPRNet 车牌识别算法
TPU-NNTC 编译部署LPRNet 车牌识别算法 注意: 由于SOPHGO SE5微服务器的CPU是基于ARM架构,以下步骤将在基于x86架构CPU的开发环境中完成 初始化开发环境(基于x86架构CPU的开发环境中完成)模型转换 (基于x86架构CPU的开发环境中完成) 处理后的LPRNet 项…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
