-
Notifications
You must be signed in to change notification settings - Fork 29
Open
Description
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Leaflet Point Constrained to Line Movement</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin="" />
<style>
#map {
height: 500px;
}
</style>
</head>
<body>
<div style="height: 500px;"></div>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
<script>
var map = L.map(mapEl.value, {
maxZoom: 25,
zoom: 14, //缩放比列
minZoom: 3,
zoomControl: false, //禁用 + - 按钮
doubleClickZoom: false, // 禁用双击放大
attributionControl: false, // 移除右下角leaflet标识
zoomSnap: 1,
rotate: true,
}).setView([23.1799, 113.4103], 15);
map?.setBearing(30);
// 添加底图
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// 定义点列表
var pointList = [
{ lat: 23.17964623275198, lng: 113.41035915466436, alt: 40 },
{ lat: 23.1802030290629, lng: 113.41031035532006, alt: 41 },
{ lat: 23.180202162848065, lng: 113.41028334317612, alt: 42 },
{ lat: 23.179646826779138, lng: 113.41033201465262, alt: 43 },
{ lat: 23.179647420806287, lng: 113.41030487464066, alt: 44 },
{ lat: 23.180201296633236, lng: 113.41025633103251, alt: 45 },
{ lat: 23.1802004304184, lng: 113.41022931888928, alt: 46 },
{ lat: 23.17964801483344, lng: 113.41027773462844, alt: 47 },
{ lat: 23.179648311847014, lng: 113.41026416462223, alt: 48 },
{ lat: 23.180199997310982, lng: 113.4102158128178, alt: 49 },
];
// 绘制点
var markers = [];
pointList.forEach(point => {
var marker = L.marker([point.lat, point.lng])
.addTo(map)
.bindPopup(`Latitude: ${point.lat}, Longitude: ${point.lng}, Altitude: ${point.alt}`);
markers.push(marker);
});
// 绘制线
var polyline = L.polyline(pointList.map(point => [point.lat, point.lng]), { color: 'blue' }).addTo(map);
// 监听线段的点击事件
polyline.on('click', function (e) {
var latlng = e.latlng;
var closestSegment = getClosestSegment(latlng, pointList);
if (closestSegment !== null) {
var prevPoint = pointList[closestSegment.index];
var nextPoint = pointList[closestSegment.index + 1];
// 在相邻两个点之间添加新点
var newPoint = getMidPoint(prevPoint, nextPoint);
var newMarker = L.marker(newPoint)
.addTo(map)
.bindPopup(`New Point: Latitude: ${newPoint.lat}, Longitude: ${newPoint.lng}`)
.on('drag', function (e) {
var latlng = e.target.getLatLng();
// The latitude and longitude are incorrect, and the drawing is offset
console.log(latlng);
e.target.setLatLng(latlng);
})
.on('dragend', function (e) {
var latlng = e.target.getLatLng();
// The latitude and longitude are incorrect, and the drawing is offset
console.log(latlng);
})
.dragging.enable();
markers.splice(closestSegment.index + 1, 0, newMarker);
pointList.splice(closestSegment.index + 1, 0, newPoint);
updatePolyline();
}
});
// 更新折线
function updatePolyline() {
polyline.setLatLngs(pointList.map(point => [point.lat, point.lng]));
}
// 获取最近线段及其索引
function getClosestSegment(latlng, points) {
var minDistance = Infinity;
var closestSegment = null;
for (var i = 0; i < points.length - 1; i++) {
var segmentDistance = getSegmentDistance(latlng, points[i], points[i + 1]);
if (segmentDistance < minDistance) {
minDistance = segmentDistance;
closestSegment = { index: i, distance: segmentDistance };
}
}
// 如果没有找到任何线段,返回 null
return closestSegment || null;
}
// 计算点到线段的距离
function getSegmentDistance(point, start, end) {
var dx = end.lng - start.lng;
var dy = end.lat - start.lat;
var t = ((point.lng - start.lng) * dx + (point.lat - start.lat) * dy) / (dx * dx + dy * dy);
// 限制 t 的范围在 0 到 1 之间
t = Math.max(0, Math.min(1, t));
// 计算最近点
var closestLat = start.lat + t * dy;
var closestLng = start.lng + t * dx;
// 计算点到最近点的距离
var dlat = point.lat - closestLat;
var dlng = point.lng - closestLng;
return Math.sqrt(dlat * dlat + dlng * dlng);
}
// 计算两点之间的中点
function getMidPoint(point1, point2) {
return L.latLng((point1.lat + point2.lat) / 2, (point1.lng + point2.lng) / 2);
}
// 计算直线上的最近点
function getClosestPointOnLine(point, start, end) {
var dx = end.lng - start.lng;
var dy = end.lat - start.lat;
var t = ((point.lng - start.lng) * dx + (point.lat - start.lat) * dy) / (dx * dx + dy * dy);
// 限制 t 的范围在 0 到 1 之间
t = Math.max(0, Math.min(1, t));
// 计算最近点
var closestLat = start.lat + t * dy;
var closestLng = start.lng + t * dx;
return L.latLng(closestLat, closestLng);
}
</script>
</body>
</html>Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels