leaflet-draw 手动绘制插件的使用和封装
参考文档:https://blog.csdn.net/sinat_31213021/article/details/119735922
手动绘制一个区域:
编辑拖拽区域顶点:
查看详情回显区域:
业务中使用:
<!-- 地图 --> <div class="map"> <map-draw-area ref="parkPlanningEiaMap" id="park_planning_eia_map" height="500px" :geoJson="geoJsonData" :visible="visible" :operate-type="operateType" @submitCenterMarker="submitCenterMarker" @submitLatlngs="submitLatlngs" :center="{ latitude: form.latitude, longitude: form.longitude }" />
</div>
data() {
return {
geoJsonData: '', // 获取到的面图 geoJson 数据
}
},
methods: {
// 回显区域中心点坐标
submitCenterMarker(latitude, longitude) {
this.form.latitude = latitude
this.form.longitude = longitude
},
// 绘制区域回调事件
submitLatlngs(latlngs, hasAreaLayer) {
// latlngs: 绘制的区域数据,hasAreaLayer:在绘制之前是否已存在面图区域
}
}
封装好的区域绘制 MapDrawArea.vue 组件:
<template>
<!-- leaflet 地图组件,内嵌于页面中
功能: 支持手动绘制区域、编辑区域、删除区域,以及渲染 geoJson 面图
-->
<div class="map-box">
<div :id="id" :style="{ width, height }" />
<div
v-show="isShowClearBtn"
@click="clearAreaLayer()"
class="button"
title="删除已保存的区域"
>
<a-icon type="delete" />
</div>
</div>
</template>
<script>
import * as L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import 'proj4leaflet'
import 'leaflet.chinatmsproviders'
import '@/assets/map/leaflet.ChineseTmsProviders'
import 'leaflet-draw'
export default {
name: 'TxMap',
props: {
id: {
type: String,
default: () => ''
},
width: {
type: String,
default: () => '100%'
},
height: {
type: String,
default: () => '280px'
},
center: {
type: Object,
default: () => {
return {
latitude: '36.70261',
longitude: '119.16160'
}
}
},
geoJson: {
type: String,
default: () => ""
},
// 操作类型: add-新增 edit-编辑
operateType: {
type: String,
default: () => ''
},
visible: {
type: Boolean,
default: () => false
}
},
data() {
return {
isShowClearBtn: false,
// L.map 对象
map: null,
// L.Control.Draw 控件对象
drawControl: null,
// 图形图层组
drawLayerGroup: null
}
},
watch: {
visible(newVal) {
if (newVal) {
if (this.isAdd()) { // 新增
this.init()
this.clearAreaLayer()
} else if (this.isEdit()) { // 编辑
this.init()
this.addLayers(this.geoJson)
} else { // 查看详情,没有绘图控件
this.init('noControl')
this.addLayers(this.geoJson)
}
this.handleClearBtn()
}
}
},
mounted() {
if (this.isDetail()) {
this.init('noControl')
} else {
this.init()
}
this.handleClearBtn()
this.addLayers(this.geoJson)
},
methods: {
init(data) {
// 初始化地图
this.initMap()
if (data !== 'noControl') {
// 初始化绘制控件
this.initDrawCtrl()
}
},
initMap() {
const { latitude, longitude } = this.center
if (!this.map) {
this.map = L.map(document.getElementById(this.id), {
center: [latitude || '36.70261', longitude || '119.16160'],
zoom: 9,
//不添加属性说明控件
attributionControl: false,
})
}
this.tileLayer = [
L.tileLayer.chinaProvider('GaoDe.Normal.Map', {
maxZoom: 16,
minZoom: 4
})
]
this.tileLayer.map(layer => {
this.map.addLayer(layer)
})
},
handleClearBtn() {
if (this.isAdd() || this.isDetail()) {
this.isShowClearBtn = false
} else {
if (this.hasGeoJson()) {
this.isShowClearBtn = true
} else {
this.isShowClearBtn = false
}
}
},
// 初始化绘制控件
initDrawCtrl() {
// 判断当前没有图层组,需先添加
if (!this.drawLayerGroup) {
//图层组
this.drawLayerGroup = new L.FeatureGroup()
}
if (!this.map.hasLayer(this.drawLayerGroup)) {
// 添加
this.map.addLayer(this.drawLayerGroup)
}
// 初始化绘制控件
if (!this.drawControl) {
this.initDrawTooltip()
this.drawControl = new L.Control.Draw({
position: 'topleft', // 控件位置 'topleft'(默认), 'topright', 'bottomleft' or 'bottomright'
draw: {
polygon: true,
polyline: false,
rectangle: false,
circle: false,
marker: false,
circlemarker: false
},
edit:{
// 绘制图层
featureGroup: this.drawLayerGroup,
// 图形编辑控件
edit: true,
// 图形删除控件
remove: true,
}
}).addTo(this.map) // 要添加到 L.map 对象中
this.Edit =new L.EditToolbar.Edit(this.map, {featureGroup: this.drawLayerGroup})
this.Delete =new L.EditToolbar.Delete(this.map, {featureGroup: this.drawLayerGroup})
}
// 添加绘制完监听事件
this.map.on(L.Draw.Event.CREATED, this.drawCreatedBack)
// 删除事件
this.map.on(L.Draw.Event.DELETED, this.handleDelete)
// 编辑事件
this.map.on(L.Draw.Event.EDITED, this.handleEdited)
},
// 交互绘制回调
drawCreatedBack(e) {
// 绘制的图形图层对象
let drawLayer = e.layer
// 添加到图层组
this.drawLayerGroup.addLayer(drawLayer)
let { lat, lng } = drawLayer.getCenter()
lat = parseFloat(lat).toFixed(5)
lng = parseFloat(lng).toFixed(5)
// 更新中心点坐标
this.$emit('submitCenterMarker', lat, lng)
this.$emit('submitLatlngs', this.drawLayerGroup._layers, this.isHasAreaLayer())
},
handleDelete() {
this.$emit('submitLatlngs', this.drawLayerGroup._layers, this.isHasAreaLayer())
},
handleEdited() {
this.$emit('submitLatlngs', this.drawLayerGroup._layers, this.isHasAreaLayer())
},
isHasAreaLayer() {
let flag
if (this.areaLayer) {
flag = this.map.hasLayer(this.areaLayer)
} else {
flag = false
}
return flag
},
// 改变绘制控件的按钮文本及提示语
initDrawTooltip() {
L.drawLocal.draw.handlers.polygon = {
tooltip: {
start: "点击地图开始绘制多边形",
cont: "继续选择",
end: "点击第一个顶点完成绘制"
}
}
L.drawLocal.draw.toolbar.buttons.polygon = "绘制"
L.drawLocal.edit.toolbar.actions.save.text = '保存'
L.drawLocal.edit.toolbar.actions.save.title = '保存'
L.drawLocal.edit.toolbar.actions.cancel.text = '取消'
L.drawLocal.edit.toolbar.actions.cancel.title = '取消'
L.drawLocal.edit.toolbar.actions.clearAll.text = '清除全部'
L.drawLocal.edit.toolbar.actions.clearAll.title = '清除全部'
L.drawLocal.edit.toolbar.buttons.editDisabled = '暂无区域可编辑'
L.drawLocal.edit.toolbar.buttons.removeDisabled = '暂无区域可删除'
L.drawLocal.edit.handlers.remove.tooltip.text = '选中一个区域去清除'
L.drawLocal.edit.toolbar.buttons.edit = '编辑'
L.drawLocal.edit.toolbar.buttons.remove = '删除'
L.drawLocal.edit.toolbar.buttons.cancel = '取消'
L.drawLocal.edit.toolbar.buttons.save = '保存'
L.drawLocal.draw.toolbar.actions.text = '取消'
L.drawLocal.draw.toolbar.actions.title = '取消绘制'
L.drawLocal.draw.toolbar.finish.text = '完成'
L.drawLocal.draw.toolbar.finish.title = '完成绘制'
L.drawLocal.draw.toolbar.undo.text = '撤销'
L.drawLocal.draw.toolbar.undo.title = '撤销'
L.drawLocal.edit.handlers.edit.tooltip.subtext = '点击取消以撤消更改'
L.drawLocal.edit.handlers.edit.tooltip.text = '拖动标记以编辑图形'
},
// 销毁地图以及绘制控件
destroyDrawCtrl() {
// 移除地图上的控制组件
if (this.drawControl) {
this.map.removeControl(this.drawControl)
}
// L.Control.Draw 控件对象
this.drawControl = null
// 删除全部绘制的图层
if (this.drawLayerGroup) {
this.drawLayerGroup.clearLayers()
}
// 移除已保存的区域
if (this.map.hasLayer(this.areaLayer)) {
this.map.removeLayer(this.areaLayer)
}
// 取消监听事件,避免其它地方也监听了 CREATED 事件
this.map.off(L.Draw.Event.CREATED, this.drawCreatedBack)
this.map.off(L.Draw.Event.DELETED, this.handleDelete)
this.map.off(L.Draw.Event.EDITED, this.handleEdited)
// 销毁该地图
this.map.remove()
this.map = null
},
addLayers(geoJson) {
if (this.hasGeoJson()) {
this.areaLayer = L.geoJSON(JSON.parse(geoJson), {
style: feature => {
return {
fillOpacity: 0.3,
weight: 2,
fillColor: '#40a9ff',
}
}
})
if (!this.map.hasLayer(this.areaLayer)) {
this.map.addLayer(this.areaLayer)
}
this.map.fitBounds(this.areaLayer.getBounds())
// this.Delete.options.featureGroup._layers = this.areaLayer._layers
// this.Edit.options.featureGroup._layers = this.areaLayer._layers
// this.map.removeControl(this.drawControl)
// L.Control.Draw 控件对象
// this.drawControl = null
// this.initDrawCtrl()
}
},
hasGeoJson() {
return this.geoJson && this.geoJson.length > 0 && JSON.parse(this.geoJson).features && JSON.parse(this.geoJson).features.length > 0
},
// 删除已保存的区域
clearAreaLayer() {
if (this.map.hasLayer(this.areaLayer)) [
this.map.removeLayer(this.areaLayer)
]
this.isShowClearBtn = false
this.$emit('submitLatlngs', [], false)
},
isAdd() {
return this.operateType === 'add'
},
isEdit() {
return this.operateType === 'edit'
},
isDetail() {
return this.operateType === 'detail'
}
}
}
</script>
<style scoped lang="scss">
@import '~leaflet-draw/dist/leaflet.draw.css';
.map-box {
width: auto;
height: auto;
position: relative;
}
.button {
position: absolute;
top: 203px;
left: 10px;
z-index: 1001;
width: 34px;
padding: 0;
height: 30px;
background: #ffffff;
line-height: 30px;
text-align: center;
border: 1px solid #a79f9f;
border-radius: 3px;
cursor: pointer;
&:hover {
background: #efefef;
}
}
::v-deep .ant-btn:hover,
::v-deep .ant-btn:focus {
color: rgba(0, 0, 0, 0.65);
">#fff;
}
</style>
生活是痛苦的白天,死亡是凉爽的夜晚。