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
      );
    },
相关推荐
王哲晓38 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
理想不理想v43 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云1 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
aPurpleBerry2 小时前
JS常用数组方法 reduce filter find forEach
javascript
GIS程序媛—椰子2 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x2 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
我血条子呢3 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
半开半落3 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt