需求
需要实现实时测距的功能,之前使用leaflet-Geoman的编辑功能,开启编辑之后会把展示的内容转换为点与线段的形式
解决
(注:使用的社区版,很多功能使用不了)
-
初次尝试
最开始是在查找这个组件处于编辑状态时的标记点是否有点击事件,找了很久没有发现这个的点击事件
-
自己动手
没找到点击事件只能自己想办法了,既然插件的没有那我自己写一套
-
实现展示效果
具体思路就是把真是的图层暂时隐藏,生成一个用于测量的图层
// 用来存储自己创建的线与标记点
const testData = L.layerGroup();
const ranging = () => {
map.removeLayer(layerContainer); // 移除地图上的 layerContainer 图层,这是移除展示的真实数据
map.removeLayer(testData); // 移除之前的测试数据图层
// 这是后端传递过来用于渲染的数据
const codes = JSON.parse(riverInfo.value.vector);
const coordinates = codes.geometry.coordinates[0]; // 提取坐标数组
// 创建一个 Polyline 来连接所有标记点
const polyline = L.polyline(coordinates.map(coord => [coord[1], coord[0]]), {
color: '#5079ea', // 线的颜色
weight: 2, // 线的宽度
opacity: 0.7, // 线的透明度
}).addTo(map);
// 创建标记点并绑定点击事件
coordinates.forEach(coords => {
const marker = L.marker([coords[1], coords[0]], {
icon: L.divIcon({
className: 'custom-marker',
iconSize: [20, 20],
html: `<div style="background-color: #fff; width: 10px; height: 10px; border-radius: 50%;"></div>`,
}),
pmIgnore: true, // 忽略 Leaflet-Geoman 的编辑功能
}).addTo(testData);
// 为每个 Marker 绑定点击事件
marker.on('click', (e) => {
const { lat, lng } = e.target.getLatLng();
// 触发点击事件
toggleHighlightMarker(e.target, lat, lng);
});
});
testData.addTo(map); // 将标记点添加到地图
};
2.点击事件处理
这里主要的逻辑是,创建一个容器存储点击的标记点数据,只存储两个标记点,当已经有两个标记点时再次点击,把后面加入的标记点替换掉第二个标记点,当点击已经存储的标记点则把这个标记点移除
// 存储高亮的标记点(最多两个)
const highlightedMarkers = ref([]);
// 切换标记点的高亮状态
function toggleHighlightMarker(marker, lat, lng) {
const index = highlightedMarkers.value.indexOf(marker);
if (index !== -1) {
// 如果已经高亮,取消高亮并移除标记点
highlightedMarkers.value.splice(index, 1);
marker.setIcon(L.divIcon({
className: 'custom-marker',
iconSize: [20, 20],
html: `<div style="background-color: #fff; width: 10px; height: 10px; border-radius: 50%;"></div>`,
}));
removeSelectedPoint(lat, lng); // 移除坐标点
} else {
// 如果未高亮,处理高亮逻辑
if (highlightedMarkers.value.length >= 2) {
// 如果已经有两个高亮的标记点,移除最后一个高亮的标记点
const lastHighlightedMarker = highlightedMarkers.value.pop();
const { lat: lastLat, lng: lastLng } = lastHighlightedMarker.getLatLng();
lastHighlightedMarker.setIcon(L.divIcon({
className: 'custom-marker',
iconSize: [20, 20],
html: `<div style="background-color:#fff; width: 10px; height: 10px; border-radius: 50%;"></div>`,
}));
removeSelectedPoint(lastLat, lastLng); // 移除最后一个高亮标记点的坐标
}
// 添加新点击的标记点
highlightedMarkers.value.push(marker);
marker.setIcon(L.divIcon({
className: 'highlighted-marker',
iconSize: [25, 25],
html: `<div style="background-color: #ff7043; width: 15px; height: 15px; border-radius: 50%; border: 2px solid white;"></div>`,
}));
addSelectedPoint(lat, lng); // 添加新标记点的坐标
}
}
// 添加选中的点
function addSelectedPoint(lat, lng) {
const point = { lat, lng };
if (!selectedPoints.value.some((p) => p.lat === lat && p.lng === lng)) {
selectedPoints.value.push(point); // 避免重复添加
getPointsBetweenMarkers(JSON.parse(riverInfo.value.vector).geometry.coordinates[0])
}
}
// 移除选中的坐标点
function removeSelectedPoint(lat, lng) {
const index = selectedPoints.value.findIndex(p => p.lat === lat && p.lng === lng);
if (index !== -1) {
selectedPoints.value.splice(index, 1);
}
}
-
获取这两个点之间的其他点(因为不是直线是弯曲点,这里使用的turf的计算api来实现这个功能)
这应该是是这个功能实现的最大难题,需要获取其他的点
function getPointsBetweenMarkers(coordinates) {
if (highlightedMarkers.value.length < 2) {
console.log("需要至少两个高亮标记点来获取中间的点");
return [];
}
// 获取两个高亮标记点的坐标
const firstMarker = highlightedMarkers.value[0];
const secondMarker = highlightedMarkers.value[1];
const firstPoint = firstMarker.getLatLng();
const secondPoint = secondMarker.getLatLng();
// 找到这两个点在原始坐标数组中的索引
let firstIndex = coordinates.findIndex(([lng, lat]) =>
Math.abs(lng - firstPoint.lng) < 0.0001 && Math.abs(lat - firstPoint.lat) < 0.0001
);
let secondIndex = coordinates.findIndex(([lng, lat]) =>
Math.abs(lng - secondPoint.lng) < 0.0001 && Math.abs(lat - secondPoint.lat) < 0.0001
);
if (firstIndex === -1 || secondIndex === -1) {
console.error("未找到高亮标记点的坐标");
return [];
}
// 确保 firstIndex < secondIndex
if (firstIndex > secondIndex) {
[firstIndex, secondIndex] = [secondIndex, firstIndex];
}
// 提取两个标记点之间的所有点
const pointsBetween = coordinates.slice(firstIndex, secondIndex + 1);
const result = turf.lineString([...pointsBetween])
const Length = turf.length(result).toFixed(2);
return Length;
}
至此为止,这个功能大部分实现,剩下的逻辑需要根据实际情况进行修改