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

73 阅读3分钟

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

image.png

image.png

  • 文件名 LeafletMakePointYt.vue
<!--

* @Description: leaflet 地图选择点位 实现画线 页面

* @Author: xxx

-->

<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: true,

title: "",

map: null,

iconStyle: {

icon: L.icon({

iconUrl: require("/public/img/point.png"),

iconSize: [12, 12],

// iconAnchor: [19, 19],

// popupAnchor: [0, -10]

}),

}, // 点位图标样式

chooseIconStyle: {

icon: L.icon({

iconUrl: require("/public/img/marker.png"),

iconSize: [30, 30],

iconAnchor: [18, 22],

}),

}, // 表格中选中的点位图标样式

startIconStyle: {

icon: L.icon({

iconUrl: require("/public/img/startPoint.png"),

iconSize: [30, 30],

iconAnchor: [18, 22],

}),

}, // 起点点位图标样式

endIconStyle: {

icon: L.icon({

iconUrl: require("/public/img/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,

oldPointObj: {}, // 记录上一个点位(判断是否是连续点击造成重复添加)

};

},

methods: {

hideDialog() {

this.dialogVisible = false;

this.map.remove();

this.map = null;

this.pointsArr = [];

this.pointsArrMarker = [];

this.polylineArr = [];

},

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);

});

this.map.fitBounds(

this.polylineArr[this.polylineArr.length - 1].getBounds()

); // 缩放地图以适应标记和线条

}

});

},

/**

* @Event 方法

* @description: 初始化 leaflet 地图

* */

initMap() {

this.map = L.map("map", {

center: [30.760408, 120.767573],

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(

"http://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", //在线地图

// "/cesiumTerrainApi/mapLayer/{z}/{x}/{y}.jpg",

// "@/../public/mapabc/satellite/{z}/{x}/{y}.jpg", //离线地图地址(全能电子地图下载器下载瓦片)

{

// 此图层将显示的最大缩放级别(包括最大)

maxZoom: 14,

minZoom: 10,

// 手机等高分辨率设备,图层显示可能会模糊,设置为true,可以改善。

detectRetina: false,

zoom: 10, //默认缩放层级

zoomControl: false, //去掉左上角缩放图标

attributionControl: false

}

).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) => {

if (

e.latlng.lat !== this.oldPointObj.lat &&

e.latlng.lng !== this.oldPointObj.lng

) {

// 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);

}

this.oldPointObj = e.latlng;

});

},

/**

* @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 = [];

this.pointsArrMarker = [];

}

},

/**

* @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);

/* 删除线段 */

}, 300);

},

},

created() {

const data={

data:[],

title:"标题"

}

this.showDialog(data);

},

mounted() {

window.addEventListener("resize", this.handleResize);

},

destroyed() {

window.removeEventListener("resize", this.handleResize);

},

};

</script>

<style 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;

}

  


.points-box-title {

height: 40px;

background-color: #1492ff;

font-size: 18px;

color: #ffffff;

line-height: 40px;

padding: 0 20px;

}

.points-box-table {

height: 490px;

}

  


.points-box-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>

参考博客:blog.csdn.net/m0_74149462… 亲测可用