老规矩, 一健三连, 先赞后看 先看效果图
自定义控件: 支持和自带控件有相同的增删改查功能, 处理与自带控件来回切换,互相使用的部分问题 新建一个组件 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()
到这里基本上就可以实现自定义控件通过组件的形式在主页面中使用了 组件的增删改查方法前几篇文章都有写, 这里就省略了, 简洁一点 实例代码及使用到的图片已上传, 点击前往获取--->