效果:点击表格可实现选中地图点位,删除按钮点击可删除对应点位并且重新绘制线段,点击确定按钮 保存已经绘制的点位信息传给父组件 并且该组件已实现回显
完整的组件代码如下 文件名称为:
leafletMakePointYt
<!--
* @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,
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.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() {},
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>
<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
);
},