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

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

1, html

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

javascript 复制代码
<template>
  <div class="imgBox">
    <div id="imageMap"></div>
  </div>
</template>

2,导入对应的包,css

javascript 复制代码
<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, 初始化函数

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

javascript 复制代码
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, 取消按钮及其点击事件

设置取消按钮的样式

javascript 复制代码
    // 取消按钮
    createCancelButton() {
      const button = document.createElement('div')
      button.className = 'cancel-button'
      button.innerHTML = '取消'
      button.onclick = (event) => {
        // 阻止事件冒泡
        event.stopPropagation()
        this.onCancelButtonClick()
      }
      return button
    },
    // 取消按钮点击事件
    onCancelButtonClick() {
      this.isDrawingImageMarker = false
      const 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, 初始化图层及绘制方法注册,绘制已图层的回显

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

javascript 复制代码
    initDate() {
      // 循环遍历图层删除
      this.map.eachLayer((layer) => {
        if (layer._latlngs != null || layer._latlng != null) {
          layer.remove()
        }
      })
      // 获取图片宽高
      let img = new Image()
      img.src = this.url
      img.onload = () => {
        let w = img.width
        let h = img.height
        this.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, 与系统控件来回切换处理自定义控件的样式及取消按钮的显影

javascript 复制代码
  // 开始绘制
    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, 调用方法

javascript 复制代码
  mounted() {
    this.initMap()
    this.initDate()
  },

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

css 复制代码
.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, 引入组件

直接导入就可以了

javascript 复制代码
<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更新组件就可以了 例如:

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

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

相关推荐
爱笑的眼睛111 小时前
uniapp 云开发全集 云数据库
javascript·数据库·oracle·uni-app
赵大仁1 小时前
微前端统一状态树实现方案
前端·前端框架
阿珊和她的猫2 小时前
钩子函数和参数:Vue组件生命周期中的自定义逻辑
前端·javascript·vue.js
勘察加熊人3 小时前
vue展示graphviz和dot流程图
前端·vue.js·流程图
软件2053 小时前
【登录流程图】
java·前端·流程图
2501_915373884 小时前
Electron 从零开始:构建你的第一个桌面应用
前端·javascript·electron
贩卖黄昏的熊5 小时前
JavaScript 笔记 --- part8 --- JS进阶 (part3)
前端·javascript·笔记
CodeCipher5 小时前
Java后端程序员学习前端之CSS
前端·css·学习
Enti7c6 小时前
JavaScript 实现输入框的撤销功能
开发语言·javascript·ecmascript
武昌库里写JAVA6 小时前
Java 设计模式
java·vue.js·spring boot·课程设计·宠物管理