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>

 

posted @ 2022-09-29 11:08  我就尝一口  阅读(1763)  评论(0编辑  收藏  举报