Vue实现leafletMap自定义绘制线段 并且删除指定的已绘制的点位

效果:点击表格可实现选中地图点位,删除按钮点击可删除对应点位并且重新绘制线段,点击确定按钮 保存已经绘制的点位信息传给父组件 并且该组件已实现回显

完整的组件代码如下 文件名称为:

复制代码
leafletMakePointYt
html 复制代码
<!--
 * @Description: leaflet 地图选择点位 实现画线 页面
 * @Author: mhf
 * @Date: 2023-05-30 18:23:37
-->
<template>
  <el-dialog
    width="1300px"
    append-to-body
    v-dialog-out
    v-if="dialogVisible"
    :title="title"
    :visible.sync="dialogVisible"
    :close-on-click-modal="false"
    :before-close="hideDialog"
  >
    <div>
      <!-- 地图盒子 -->
      <div id="map"></div>

      <!-- 左侧坐标展示框 -->
      <div class="points-box">
        <!-- 顶部标题 -->
        <div class="points-box-title">
          <span> 线路坐标 </span>
        </div>

        <!-- 坐标展示表 -->
        <div class="points-box-table">
          <el-table
            highlight-current-row
            @current-change="handleCurrentChange"
            :data="pointsArr"
            style="width: 100%"
            :height="tableHeight"
          >
            <el-table-column label="#" type="index" />
            <el-table-column prop="lat" label="经度" width="158" />
            <el-table-column prop="lng" label="纬度" width="158" />
            <el-table-column
              label="操作"
              width="60"
              fixed="right"
              v-if="showBtn"
            >
              <template slot-scope="scope">
                <el-button type="text" size="small" @click="delRow(scope)">
                  删除</el-button
                >
              </template>
            </el-table-column>
          </el-table>
        </div>

        <!-- 坐标盒子 底部按钮组 -->
        <div v-if="showBtn" class="points-box-btn">
          <el-button type="" size="" @click="clearMapLine"> 清除</el-button>
          <el-button type="primary" size="" @click="makeMapLine">
            开始</el-button
          >
          <el-button type="primary" size="" @click="endMakeLine">
            结束</el-button
          >
        </div>
      </div>
    </div>

    <!-- 弹窗底部按钮组 -->
    <div v-if="showBtn" slot="footer" class="dialog-footer">
      <el-button @click="hideDialog">取 消</el-button>
      <el-button type="primary" @click="submitPoints()">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>
import L from "leaflet";
import "leaflet/dist/leaflet.css";
//  引入互联网地图插件
require("@/utils/leftletMap/leaflet.ChineseTmsProviders.js");
require("@/utils/leftletMap/tileLayer.baidu.js");
// 引入互联网地图纠偏插件
require("@/utils/leftletMap/leaflet.mapCorrection.min.js");

export default {
  name: "leafletMakePointYt",
  components: {},
  props: {
    showBtn: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      dialogVisible: false,
      title: "",
      map: null,
      iconStyle: {
        icon: L.icon({
          iconUrl: require("/public/img/mapIcon/point.png"),
          iconSize: [12, 12],
          // iconAnchor: [19, 19],
          // popupAnchor: [0, -10]
        }),
      }, // 点位图标样式

      chooseIconStyle: {
        icon: L.icon({
          iconUrl: require("/public/img/mapIcon/marker.png"),
          iconSize: [30, 30],
          iconAnchor: [18, 22],
        }),
      }, // 表格中选中的点位图标样式

      startIconStyle: {
        icon: L.icon({
          iconUrl: require("/public/img/mapIcon/startPoint.png"),
          iconSize: [30, 30],
          iconAnchor: [18, 22],
        }),
      }, // 起点点位图标样式

      endIconStyle: {
        icon: L.icon({
          iconUrl: require("/public/img/mapIcon/endPoint.png"),
          iconSize: [30, 30],
          iconAnchor: [18, 22],
        }),
      }, // 终点点位图标样式

      polylineStyle: {
        color: "#FF6B00",
        weight: 4,
      }, // 线条样式
      pointsArr: [], // 标记点位列表 [{lat: 30, lng: 120}, {lat: 31, lng: 121}]
      pointsArrMarker: [], // 已经绘制的点位
      polylineArr: [], // 已经绘制多条线段

      chooseMarker: undefined, // 当前选中的点位
      tableHeight: 440,
      loading: false, // loading 动画
      loadingInstance: null,
    };
  },
  methods: {
    hideDialog() {
      this.dialogVisible = false;
      this.map.remove();
      this.map = null;
    },

    submitPoints() {
      if (this.pointsArr.length < 2) {
        this.$message.warning("请先绘制线路");
      } else {
        this.$emit("on-response", this.pointsArr); // 将绘制好的坐标传递给父组件
        this.hideDialog();
      }
    },

    showDialog(data) {
      this.dialogVisible = true;
      this.title = data.title;
      this.$nextTick(() => {
        /* 避免重复渲染 */
        if (!this.map) this.initMap();
        this.handleResize();

        if (data.data) {
          this.pointsArr = JSON.parse(data.data);
          /* 线段回显 */
          var polyline = L.polyline(this.pointsArr, this.polylineStyle).addTo(
            this.map
          );
          this.polylineArr.push(polyline);
          /* 点位回显 */
          this.pointsArr.forEach((item, index) => {
            var marker = L.marker([item.lat, item.lng], this.iconStyle).addTo(
              this.map
            ); // 添加标记点
            this.pointsArrMarker.push(marker);
          });
        }
      });
    },

    /**
     * @Event 方法
     * @description: 初始化 leaflet 地图
     * */
    initMap() {
      this.map = L.map("map", {
        center: [30.194637, 120.122247],
        zoom: 13,
        attributionControl: false, // 隐藏logo
        zoomControl: false, // 默认缩放控件(仅当创建地图时该 zoomControl 选项是 true)。
        crs: L.CRS.Baidu, // 用于 WMS 请求的坐标参考系统,默认为映射 CRS。 如果您不确定它的含义,请不要更改它。
      });
      L.control
        .zoom({
          position: "bottomright",
        })
        .addTo(this.map);
      L.tileLayer.baidu({ layer: "vec" }).addTo(this.map); // 添加底图
    },

    /**
     * @Event 方法
     * @description: 开始画线
     * */
    makeMapLine() {
      this.map.getContainer().style.cursor = "crosshair"; // 更改鼠标样式
      // let index = -1
      var marker, polyline;
      this.map.on("click", (e) => {
        // index++
        // if (index === 0) {
        /* 设置起点 */
        // L.marker([e.latlng.lat, e.latlng.lng], this.startIconStyle).addTo(this.map);
        /* 设置起点 */
        // } else {
        marker = L.marker([e.latlng.lat, e.latlng.lng], this.iconStyle).addTo(
          this.map
        ); // 添加标记点
        // }
        this.pointsArrMarker.push(marker);
        this.pointsArr.push(e.latlng); // 添加点位坐标至点位数组
        polyline = L.polyline(this.pointsArr, this.polylineStyle).addTo(
          this.map
        ); // 创建单条线段
        this.polylineArr.push(polyline);
      });
    },

    /**
     * @Event 方法
     * @description: 结束画线
     * */
    endMakeLine() {
      if (this.pointsArr === [] || this.pointsArr.length === 0) {
        this.$message.warning("请先绘制线路");
      } else {
        this.map.getContainer().style.cursor = "grab"; // 更改鼠标样式
        this.map.fitBounds(
          this.polylineArr[this.polylineArr.length - 1].getBounds()
        ); // 缩放地图以适应标记和线条
        this.map.on("mousedown", (e) => {
          this.map.getContainer().style.cursor = "grabbing"; // 更改鼠标样式
        });
        this.map.on("mouseup", (e) => {
          this.map.getContainer().style.cursor = "grab"; // 更改鼠标样式
        });
        this.map.off("click"); // 关闭点击事件
      }
    },

    /**
     * @Event 方法
     * @description: 移除线段和点位
     * */
    clearMapLine() {
      if (this.pointsArr === [] || this.pointsArr.length === 0) {
      } else {
        /* 移除点位 */
        this.pointsArrMarker.forEach((marker) => {
          this.map.removeLayer(marker);
        });
        /* 移除线段 */
        this.polylineArr.forEach((polyline) => {
          polyline.remove();
        });
        this.endMakeLine(); // 结束画线
        this.polylineArr = [];
        this.pointsArr = [];
      }
    },

    /**
     * @Event 方法
     * @description: 动态改变表格的高度
     * */
    handleResize() {
      const height = document.querySelector(".points-box-table").offsetHeight;
      this.tableHeight = height - 10;
    },

    /**
     * @Event 方法
     * @description: 表格单行选中事件,实现每次点击时都能删除上一次点击的图标
     * */
    handleCurrentChange(row) {
      if (this.chooseMarker) {
        this.map.removeLayer(this.chooseMarker);
      }
      this.chooseMarker = L.marker(
        [row.lat, row.lng],
        this.chooseIconStyle
      ).addTo(this.map); // 添加标记点
    },

    /**
     * @Event 方法
     * @description: 删除表格单行数据并且移除该点位
     * */
    delRow(row) {
      this.loading = true;
      this.$nextTick(() => {
        const target = document.querySelector(".el-dialog__body");
        let options = {
          lock: true,
          text: "重新绘制中...",
          spinner: "el-icon-loading",
          background: "rgba(0, 0, 0, 0.7)",
        };
        this.loadingInstance = this.$loading(options, target);
      });
      setTimeout(() => {
        this.loading = false;
        this.loadingInstance.close();

        /* 删除点位 */
        this.map.removeLayer(this.pointsArrMarker[row.$index]);
        this.pointsArrMarker.splice(row.$index, 1); // 已经绘制的点位
        this.pointsArr.splice(row.$index, 1); // 标记点位列表
        /* 删除点位 */

        /* 删除线段 */
        this.polylineArr.forEach((polyline) => {
          polyline.remove();
        });
        var polyline = L.polyline(this.pointsArr, this.polylineStyle).addTo(
          this.map
        );
        this.polylineArr.push(polyline);
        /* 删除线段 */
      }, 500);
    },
  },
  created() {},
  mounted() {
    window.addEventListener("resize", this.handleResize);
  },
  destroyed() {
    window.removeEventListener("resize", this.handleResize);
  },
};
</script>

<style lang="scss" scoped>
.dialog-footer {
  text-align: center;
}

#map {
  height: 68vh;
}

.points-box {
  width: 426px;
  height: 570px;
  position: absolute;
  top: 100px;
  z-index: 99999 !important;
  background-color: #fff;
  left: 40px;

  &-title {
    height: 40px;
    background-color: #1492ff;
    font-size: 18px;
    color: #ffffff;
    line-height: 40px;
    padding: 0 20px;
  }

  &-table {
    height: 490px;
  }

  &-btn {
    height: 50px;
    position: absolute;
    padding-bottom: 18px;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
    width: 80%;
    display: flex;
    justify-content: space-around;
    align-items: center;
  }
}
</style>
html 复制代码
<el-form-item label="线路轨迹 : " prop="assetSection.point">
              <el-input
                v-model="formData.assetSection.point"
                disabled
                placeholder=""
              >
                <template slot="append">
                  <div class="choose-class" @click="showLeafletMap">
                    <i class="iconfont if-ditudingwei" /> <span>选择</span>
                  </div>
                </template>
              </el-input>
            </el-form-item>






    <leafletMakePointYt ref="leafletMakePointYt" @on-response="getPoints" />





// 打开弹窗 

   showLeafletMap() {
      let passData = {
        title: "选择线路轨迹",
        data: this.formData.assetSection.point,
      };
      this.$refs.leafletMakePointYt.showDialog(passData);
    },



// passData: {
title: "选择线路轨迹",
data: "[{"lat":30.19398904706604,"lng":120.1454230189172},{"lat":30.204226626758985,"lng":120.19285355280543},{"lat":30.22270148713875,"lng":120.13162504542244},{"lat":30.189494160206575,"lng":120.15490912569484}]"
}



// 接收弹窗的点位数据
    getPoints(data) {
      this.$set(this.formData.assetSection, "point", JSON.stringify(data));
      this.$set(this.formData.assetSection, "startLongitude", data[0].lng);
      this.$set(this.formData.assetSection, "startLatitude", data[0].lat);
      this.$set(
        this.formData.assetSection,
        "endLongitude",
        data[data.length - 1].lng
      );
      this.$set(
        this.formData.assetSection,
        "endLatitude",
        data[data.length - 1].lat
      );
    },
相关推荐
小马哥编程7 分钟前
原型链(Prototype Chain)入门
css·vue.js·chrome·node.js·原型模式·chrome devtools
dlnu20152506221 小时前
ssr实现方案
前端·javascript·ssr
轻口味3 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王3 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发3 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀4 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
真滴book理喻6 小时前
Vue(四)
前端·javascript·vue.js
程序员_三木7 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
不是鱼8 小时前
构建React基础及理解与Vue的区别
前端·vue.js·react.js
开心工作室_kaic8 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js