【vue+leaflet】自定义控件(五)

在这里插入图片描述
请添加图片描述
老规矩, 一健三连, 先赞后看
先看效果图
在这里插入图片描述
自定义控件: 支持和自带控件有相同的增删改查功能, 处理与自带控件来回切换,互相使用的部分问题
新建一个组件
imgControl.vue

1, html

没什么东西,就一个div盒子装leaflet图层

<template><div class="imgBox"><div id="imageMap"></div></div>
</template>

2,导入对应的包,css

<script>
import 'leaflet/dist/leaflet.css'
import 'leaflet/dist/leaflet'
import 'leaflet/dist/leaflet-src'
import 'leaflet/dist/leaflet-src.esm'
import * as L from 'leaflet'
import 'leaflet.pm'
import 'leaflet.pm/dist/leaflet.pm.css'
export default {data() {return {map: null,bounds: [[0, 0],[0, 0],], // 平面图大小url: require('../../../public/home/bgc0.jpg'), // 平面图地址devArrList: [], // 设备列表imageOverlay: '', // 图层isDrawingImageMarker: false,cancelButton: null, // 控件激活后旁边的取消按钮}},}
</script>

3, 初始化函数

初始化就开始注册自定义控件

initMap() {this.map = L.map('imageMap', {...// 省略, 与自定义控件无关,不知道参数的可以去往期文章观看})this.map.pm.addControls({position: 'topleft',.....// 省略, 与自定义控件无关,不知道参数的可以去往期文章观看})// 重点!!!// 自定义控件权限const addImageControl = L.Control.extend({options: { position: 'topleft' }, // 控件的位置,与默认的相同就可以onAdd: (map) => {const container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom')container.innerHTML = '<i class="fa fa-image" style="line-height:26px;"></i>'container.title = '绘制门' // 鼠标hover时候的title// 控件点击事件container.onclick = (event) => {// 阻止事件冒泡,防止地图点击事件触发event.stopPropagation()event.preventDefault()// 禁用双击放大map.doubleClickZoom.disable()// 切换绘制模式this.isDrawingImageMarker = !this.isDrawingImageMarker// 设置按钮激活样式, 激活控件旁边显示取消按钮if (this.isDrawingImageMarker) {container.style.boxShadow = 'inset 0 -1px 5px 2px rgba(81, 77, 77, 0.31)'// 添加自定义鼠标指针样式document.getElementById('imageMap').classList.add('custom-cursor')// 取消其他图层绘制map.pm.disableDraw()// 禁用全局编辑,拖拽,删除模式,  只让一个控件处于激活状态map.pm.disableGlobalEditMode()if (map.pm.globalDragModeEnabled()) {map.pm.toggleGlobalDragMode()}// 创建取消按钮及样式if (!this.cancelButton) {this.cancelButton = this.createCancelButton()this.cancelButton.addEventListener('click', (e) => {// 阻止事件冒泡,防止首次点击不生效e.stopPropagation()this.onCancelButtonClick()})container.appendChild(this.cancelButton)}this.cancelButton.style.display = 'block'} else {container.style.boxShadow = 'none'// 移除自定义鼠标指针样式document.getElementById('imageMap').classList.remove('custom-cursor')if (this.cancelButton) {this.cancelButton.style.display = 'none'this.cancelButton = null}}}return container},})// 注册控件this.map.addControl(new addImageControl())// 处理地图点击事件this.map.on('click', (e) => {// 按钮激活 且点击的不是按钮 才绘制图片图层if (this.isDrawingImageMarker && !e.originalEvent.target.closest('.leaflet-control-custom')) {const marker = new L.Marker(e.latlng, {icon: L.icon({iconUrl: require('../../../public/home/doorClose.png'),iconSize: [24, 30],iconAnchor: [12, 15],}),}).addTo(this.map)this.map.fire('pm:create', {shape: 'ImageMarker',layer: marker,})}})},

4, 取消按钮及其点击事件

设置取消按钮的样式

    // 取消按钮createCancelButton() {const button = document.createElement('div')button.className = 'cancel-button'button.innerHTML = '取消'button.onclick = (event) => {// 阻止事件冒泡event.stopPropagation()this.onCancelButtonClick()}return button},// 取消按钮点击事件onCancelButtonClick() {this.isDrawingImageMarker = falseconst control = document.querySelector('.leaflet-control-custom')if (control) control.style.boxShadow = 'none'if (this.cancelButton) {this.cancelButton.style.display = 'none'this.cancelButton = null}// 移除自定义鼠标指针样式document.getElementById('imageMap').classList.remove('custom-cursor')},

5, 初始化图层及绘制方法注册,绘制已图层的回显

主图层绘制, 绘制的图层回显, 部分系统事件,图层事件注册

    initDate() {// 循环遍历图层删除this.map.eachLayer((layer) => {if (layer._latlngs != null || layer._latlng != null) {layer.remove()}})// 获取图片宽高let img = new Image()img.src = this.urlimg.onload = () => {let w = img.widthlet h = img.heightthis.bounds = [[0, 0],[h, w],]// 添加图片,更换图片if (this.imageOverlay) {this.imageOverlay.setUrl(this.url)this.imageOverlay.setBounds(this.bounds)} else {this.imageOverlay = L.imageOverlay(this.url, this.bounds).addTo(this.map)}this.map.fitBounds(this.bounds)}// 循环绘制图层this.devArrList.forEach((rs) => {if (rs.point) {let re = JSON.parse(rs.point)// 画图片,门if (re.imageDoor && re.imageDoor.length) {re.imageDoor.forEach((e) => {let icon = L.divIcon({html,className: 'my-div-icon',iconAnchor: [20, 10],iconSize: [40, 20],})L.marker(e.latlng, {icon,type: 'imageDoor',textName: e.options.textName,}).addTo(this.map).on('click', this.imageDoorClick)})}}})// 监听图层绘制完成this.map.on('pm:create', this.createClick)this.map.on('pm:remove', this.removeClick)this.map.on('pm:drawstart', this.drawstartClick)this.map.on('pm:drawend', this.drawendClick)this.map.on('pm:globalremovalmodetoggled', this.globalDeleteClick)this.map.on('pm:globaleditmodetoggled', this.globalEditClick)this.map.on('pm:globaldragmodetoggled', this.globalDragClick)// 禁止背景图拖拽this.map.dragging.disable()// 禁止双击缩放this.map.doubleClickZoom.disable()// 禁止滚动缩放this.map.scrollWheelZoom.disable()},

6, 注册的事件方法,逻辑处理模块

1, 监听绘制过程中点击右键快速结束绘制
2, 与系统控件来回切换处理自定义控件的样式及取消按钮的显影

  // 开始绘制drawstartClick(e) {// 关闭门图片绘制this.onCancelButtonClick()// 绘制圆形右键快速结束绘制if (e.shape == 'CircleMarker') {// 监听右键事件this.map.on('contextmenu', () => {this.map.pm.Draw[e.shape].disable()})}},// 结束绘制drawendClick(e) {console.log('结束绘制', e)// 卸载右键事件this.map.off('contextmenu')},// 删除控件globalDeleteClick(e) {// console.log('删除', e)// enabled ture开始删除才取消激活门绘制// if (e.enabled) {this.onCancelButtonClick()// }},// 编辑控件globalEditClick(e) {// console.log('编辑', e)// enabled ture开始编辑才取消激活门绘制if (e.enabled) {this.onCancelButtonClick()}},// 拖拽控件globalDragClick(e) {// console.log('拖拽', e)// enabled ture开始拖拽才取消激活门绘制if (e.enabled) {this.onCancelButtonClick()}},// 图层绘制完成createClick(e) {console.log('图层绘制完成', e)if (e.shape == 'ImageMarker') {// 画图片门e.layer.on('click', this.imageDoorClick)e.layer.options.type = 'imageDoor'}},// 图层删除removeClick(e) {console.log('图层删除', e)},// 图片门点击imageDoorClick(e) {console.log('图片门点击', e)},// 图片门拖拽dragendImageDoorClick(e) {console.log('图片门拖拽', e)},

7, 调用方法

  mounted() {this.initMap()this.initDate()},

8, 自定义的样式,激活的鼠标指针样式

.imgBox {width: calc(100% - 20px);height: 100%;padding: 0 10px;#imageMap {height: 100%;box-sizing: border-box;}
}
.leaflet-container {font-size: 0.2rem;background: #fff;
}
.leaflet-div-icon {background: transparent;text-align: center;color: #fff;
}
/deep/.my-div-icon {color: #000;text-align: center;
}
// 控件样式
/deep/.leaflet-control-custom {background-color: white;background-image: url('../../../public/home/doorClose.png');background-size: 80% 80%;background-repeat: no-repeat;background-position: center;width: 30px;height: 30px;cursor: pointer;&:hover {background-color: #f4f4f4;}
}
// 取消按钮
/deep/.cancel-button {background-color: #666666;color: white;width: 52px;text-align: center;line-height: 30px;height: 30px;cursor: pointer;position: absolute;border-radius: 0px 3px 3px 0px;top: 0px;left: 31px;z-index: 2;
}
// 鼠标指针
/deep/.custom-cursor {cursor: url('/home/cursor.ico') 12 15, auto !important;
}
// 门
/deep/.door {position: relative;.name {position: absolute;left: 7px;top: 7px;}
}

9, 引入组件

直接导入就可以了

<template><div class="imgBox"><ImgControl /></div>
</template>
<script>
import ImgControl from '@/components/imgLayout/imgControl.vue'
export default {components: {ImgControl,},data() {return {}},methods: {},mounted() {},
}
</script>
<style lang="less" scoped>
.imgBox {width: 100%;height: 100%;
}
</style>

如果主页是在模态框中导入这个组件, 会出现多次点击模态框组件内容的图层内容不会重新绘制的问题, 给组件绑定一个key更新组件就可以了
例如:

  <!-- key 模态框关闭,再开启时更新重载组件 --><ImgLayout v-if="isDevBind" ref="layout" :key="updateKey" />....updateKey:new Date().getTime()

到这里基本上就可以实现自定义控件通过组件的形式在主页面中使用了
组件的增删改查方法前几篇文章都有写, 这里就省略了, 简洁一点
实例代码及使用到的图片已上传, 点击前往获取—>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java | Leetcode Java题解之第513题找树左下角的值

题目&#xff1a; 题解&#xff1a; class Solution {public int findBottomLeftValue(TreeNode root) {int ret 0;Queue<TreeNode> queue new ArrayDeque<TreeNode>();queue.offer(root);while (!queue.isEmpty()) {TreeNode p queue.poll();if (p.right ! nu…

Cursor的composer和chat的应用

提到 Cursor 就不得不提及它的 Composer 功能。“Composer” 的中文释义为 “作曲家”&#xff0c;在此处它有着特定的含义。 Cursor 提供了两种人机对话方式。一种是 Chat&#xff0c;它与 ChatGPT 之类的工具差别不大。另一种则是强大的 Compose。 在编写程序时&#xff0c…

基于GA遗传优化的风光储微电网削峰填谷能量管理系统matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 削峰填谷的基本概念与意义 4.2 GA优化 5.完整工程文件 1.课题概述 基于GA遗传优化的风光储微电网削峰填谷能量管理系统matlab仿真。通过遗传算法优化风光储微电网的充放电控制过程&#xff0c;然后…

配置smaba (Linux与windows通信)

在Ubuntu上安装Samba是一个简单的过程。以下是详细的步骤&#xff0c;帮助你从安装到基本配置。 步骤1&#xff1a;更新软件包列表 首先&#xff0c;打开终端&#xff0c;确保你的软件包列表是最新的&#xff1a; sudo apt update 步骤2&#xff1a;安装 Samba 接下来…

项目部署 —— 前端、后端

一、 前端 ● 二号标题 在命令框里输入 npm run build 打包成功&#xff1a; 项目就会出现一个 dist 文件夹 将Linux的nginx文件夹中&#xff0c;重命名为 news 二、 后端 ● 通过maven打包后端程序 最终会在项目中生成一个 target 文件夹&#xff0c;将 news-1.0-SNAPSHOT.…

汇编语言

前言 汇编语言是各种CPU提供的机器指令的助记符的集合&#xff0c;可以通过汇编语言直接控制硬件系统进行工作&#xff1b; Q&#xff1a;为什么说汇编语言可以直接操作硬件&#xff1f;那么汇编过程还有什么意义呢&#xff1f; A&#xff1a;汇编语言利用助记符代替机器指令的…

Python数据分析——Numpy

纯个人python的一个小回忆笔记&#xff0c;当时假期花两天学的python&#xff0c;确实时隔几个月快忘光了&#xff0c;为了应付作业才回忆起来&#xff0c;不涉及太多基础&#xff0c;适用于有一定编程基础的参考回忆。 这一篇笔记来源于下面哔哩哔哩up主的视频&#xff1a; 一…

反编译华为-研究功耗联网监控日志

摘要 待机功耗中联网目前已知的盲点&#xff1a;App自己都不知道的push类型的被动联网、app下载场景所需时长、组播联网、路由器打醒AP。 竞品 策略 华为 灭屏使用handler定时检测&#xff08;若灭屏30分钟内则周期1分钟&#xff0c;否则为2分钟&#xff09;&#xff0c;检…

基于知识图谱的紧急事故决策辅助系统

现代社会紧急事故频发&#xff0c;而处理这些突发事件的效率直接决定了后续影响的大小。这时候&#xff0c;数据智能的解决方案会显得尤为重要&#xff01;今天为大家分享一个用【知识图谱】技术驱动的紧急事故决策辅助系统&#xff0c;不仅能帮助你快速处理事故信息&#xff0…

HarmonyOS Next API12最新版 端云一体化开发-云函数篇

一、新建一个端云一体化项目 见文章&#xff1a; HarmonyOS NEXT API12最新版 端云一体化开发-创建端云一体化项目流程_鸿蒙appapi-CSDN博客 二、官方文档 使用限制-云函数 - 华为HarmonyOS开发者 (huawei.com) Cloud Foundation Kit简介-Cloud Foundation Kit&#xff0…

1通道10GSPS或2通道5G 14 bit数字化仪

ADQ7DC是一款高端14位数据采集平台&#xff0c;旨在满足最具挑战性的测量环境。ADQ7DC特性: 单通道和双通道操作 单通道10GSPS或双通道5GSPS 7 GByte/s持续数据传输速率开放式FPGA支持实时DSP 脉冲检测固件选项波形平均固件选项 ADQ7DC数据手册 特征 单通道和双通道工作模式…

javaScript整数反转

function _reverse(number) { // 补全代码 return (number ).split().reverse().join(); } number &#xff1a;首先&#xff0c;将数字 number 转换为字符串。在 JavaScript 中&#xff0c;当你将一个数字与一个字符串相加时&#xff0c;JavaScript 会自动将数字转换为字符串…

Ajax:跨域 JSONP

Ajax&#xff1a;跨域 & JSONP 同源与跨域同源跨域 JSONPjQuery发送JSONP 同源与跨域 同源 如果两个页面的协议、域名、端口号都相同&#xff0c;则两个页面同源 例如&#xff1a; http://www.test.com/index.html与其同源的网页&#xff1a; http://www.test.com/other…

MySql中表的复合查询

复合查询 ​ 本篇开始将介绍在MySql中进行复合查询的操作。平时在开发过程中只对一张表进行查询的操作是远远不够的&#xff0c;更多的都是多张表一起查询&#xff0c;所以本篇将介绍多张表中的复合查询&#xff0c;主要介绍多表查询、自连接以及子查询。 文章目录 复合查询导…

Discourse 是否可以简化文本操作

当下的文本处理很多都在慢慢转换到 MD。 有一段时间&#xff0c;论坛都会使用默认的 BBCode&#xff0c;包括 Discuz 现在也是这样的。 MD 文件有一定的入门使用门槛&#xff0c;但习惯了还好。 我们这里用得最多的就是标题和图片&#xff0c;其他的排版用得比较少&#xff…

如何找到适合的工程管理系统?9款对比

本文推荐的9款精选工程项目综合管理系统有: 1. Worktile&#xff1b;2. 广联达&#xff1b;3. 斯维尔&#xff1b;4. 品茗工程管理软件&#xff1b;5. 明源云&#xff1b;6. 泛微OA&#xff1b;7. Microsoft Project&#xff1b;8. Procore&#xff1b;9. Buildertrend。 在管理…

安卓在windows连不上fastboot问题记录

fastboot在windows连不上fastboot 前提是android studio安装 google usb driver 搜索设备管理器 插拔几次找安卓设备 在其他设备 或者串行总线设备会出现安卓 右键更新驱动 下一步下一步然后可以了

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-24

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-24 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-24目录1. Optimizing Preference Alignment with Differentiable NDCG Ranking摘要研究背景问题与挑战如何解决创新点算法模型算…

Linux基础知识作业

关卡任务 任务描述闯关任务完成SSH连接与端口映射并运行hello_world.py可选任务 1将Linux基础命令在开发机上完成一遍可选任务 2使用 VSCODE 远程连接开发机并创建一个conda环境可选任务 3创建并运行test.sh文件

【STM32】单片机ADC原理详解及应用编程

本篇文章主要详细讲述单片机的ADC原理和编程应用&#xff0c;希望我的分享对你有所帮助&#xff01; 目录 一、STM32ADC概述 1、ADC&#xff08;Analog-to-Digital Converter&#xff0c;模数转换器&#xff09; 2、STM32工作原理 二、STM32ADC编程实战 &#xff08;一&am…