leaflet 实现 测距、测面、清除测量的功能
参考文档:https://my.oschina.net/u/4321106/blog/3528070/print
1、先定义需要用到的全局变量
var DRAWING = false; //是否正在绘制
var DRAWLAYERS = [];
var BarDRAWLAYERS = [];
var ISMEASURE = false; //是否是量距
var MEASURETOOLTIP; //量距提示
var MEASUREAREATOOLTIP; //量面提示
var MEASURERESULT = 0; //测量结果
var DRAWPOLYLINE; //绘制的折线
var DRAWMOVEPOLYLINE; //绘制过程中的折线
var DRAWPOLYLINEPOINTS = []; //绘制的折线的节点集
var DRAWPOLYGON; //绘制的面
var DRAWMOVEPOLYGON; //绘制过程中的面
var DRAWPOLYGONPOINTS = []; //绘制的面的节点集
2、测距
<button type="button" class="btn btn-sm btn-default" id="juliMeasure">测距</button>
$('#juliMeasure').click(function() {
ISMEASURE = true;
init.startDrawLine();
}),
startDrawLine(func) {
MEASURERESULT = 0; //测量结果
map.getContainer().style.cursor = 'crosshair';
var shapeOptions = {
color: '#F54124',
weight: 3,
opacity: 0.8,
fill: false,
clickable: true
},
DRAWPOLYLINE = new L.Polyline([], shapeOptions); //绘制的折线
map.addLayer(DRAWPOLYLINE);
if (ISMEASURE) { //是否是量距
MEASURETOOLTIP = new L.Tooltip(map); //量距提示
}
map.on('mousedown', onClick);
map.on('dblclick', onDoubleClick);
function onClick(e) {
DRAWING = true; //是否正在绘制
DRAWPOLYLINEPOINTS.push(e.latlng); //绘制的折线的节点集
if (DRAWPOLYLINEPOINTS.length > 1 && ISMEASURE) { //是否是量距
MEASURERESULT += e.latlng.distanceTo(DRAWPOLYLINEPOINTS[DRAWPOLYLINEPOINTS.length - 2]);
}
DRAWPOLYLINE.addLatLng(e.latlng); //绘制的折线
map.on('mousemove', onMove);
}
function onMove(e) {
if (DRAWING) { //是否正在绘制
if (DRAWMOVEPOLYLINE != undefined && DRAWMOVEPOLYLINE != null) { //绘制过程中的折线
map.removeLayer(DRAWMOVEPOLYLINE);
}
var prevPoint = DRAWPOLYLINEPOINTS[DRAWPOLYLINEPOINTS.length - 1];
DRAWMOVEPOLYLINE = new L.Polyline([prevPoint, e.latlng], shapeOptions);
map.addLayer(DRAWMOVEPOLYLINE);
if (ISMEASURE) {
var distance = MEASURERESULT + e.latlng.distanceTo(DRAWPOLYLINEPOINTS[DRAWPOLYLINEPOINTS.length - 1]);
/* MEASURETOOLTIP.updatePosition(e.latlng); //量距提示
MEASURETOOLTIP.updateContent({
text: '单击确定点,双击结束!',
subtext: "总长:" + (distance / 1000).toFixed(2) + "公里"
});*/
}
}
}
function onDoubleClick(e) {
map.getContainer().style.cursor = '';
/*显示两点距离*/
var distance = MEASURERESULT + e.latlng.distanceTo(DRAWPOLYLINEPOINTS[DRAWPOLYLINEPOINTS.length - 1]);
marker = new L.Marker(e.latlng, { draggable: false });
map.addLayer(marker);
marker.bindPopup((distance / 1000).toFixed(2) + "公里").openPopup();
if (DRAWING) {
if (DRAWMOVEPOLYLINE != undefined && DRAWMOVEPOLYLINE != null) {
map.removeLayer(DRAWMOVEPOLYLINE);
DRAWMOVEPOLYLINE = null;
}
BarDRAWLAYERS.push(DRAWPOLYLINE);
DRAWPOLYLINEPOINTS = [];
DRAWING = false;
ISMEASURE = false;
map.off('mousedown');
map.off('mousemove');
map.off('dblclick');
}
}
},
3、测面
<button type="button" class="btn btn-sm btn-default" id="mianjiMeasure">测面</button>
/*面积量算*/ $('#mianjiMeasure').click(function() { ISMEASURE = true; init.startDrawPolygon() }) /*多边形*/ startDrawPolygon(func) { MEASURERESULT = 0; map.getContainer().style.cursor = 'crosshair'; map.on('mousedown', function(e) { DRAWING = true; DRAWPOLYGONPOINTS.push(e.latlng); DRAWPOLYGON.addLatLng(e.latlng); }); map.on('mousemove', function(e) { if (DRAWING) { if (DRAWMOVEPOLYGON != undefined && DRAWMOVEPOLYGON != null) { map.removeLayer(DRAWMOVEPOLYGON); } var prevPoint = DRAWPOLYGONPOINTS[DRAWPOLYGONPOINTS.length - 1]; var firstPoint = DRAWPOLYGONPOINTS[0]; DRAWMOVEPOLYGON = new L.Polygon([firstPoint, prevPoint, e.latlng], shapeOptions); map.addLayer(DRAWMOVEPOLYGON); } }); map.on('dblclick', function(e) { map.getContainer().style.cursor = ''; var tempPoints = []; for (var i = 0; i < DRAWPOLYGONPOINTS.length; i++) { tempPoints.push(DRAWPOLYGONPOINTS[i]); } tempPoints.push(e.latlng); var distance = CalArea(tempPoints); marker = new L.Marker(e.latlng, { draggable: false }); map.addLayer(marker); marker.bindPopup("总面积:" + (distance / 1000000).toFixed(3) + '平方公里').openPopup(); if (DRAWING) { if (DRAWMOVEPOLYGON != undefined && DRAWMOVEPOLYGON != null) { map.removeLayer(DRAWMOVEPOLYGON); DRAWMOVEPOLYGON = null; } BarDRAWLAYERS.push(DRAWPOLYGON); if (func) { func(DRAWPOLYGONPOINTS); } DRAWPOLYGONPOINTS = []; DRAWING = false; ISMEASURE = false; map.off('mousedown'); map.off('mousemove'); map.off('dblclick'); } }); var shapeOptions = { color: '#F54124', weight: 3, opacity: 0.8, fill: true, fillColor: null, fillOpacity: 0.2, clickable: true }, DRAWPOLYGON = new L.Polygon([], shapeOptions); map.addLayer(DRAWPOLYGON); if (ISMEASURE) { MEASUREAREATOOLTIP = new L.Tooltip(map); } function CalArea(latLngs) { var pointsCount = latLngs.length, area = 0.0, d2r = Math.PI / 180, p1, p2; if (pointsCount > 2) { for (var i = 0; i < pointsCount; i++) { p1 = latLngs[i]; p2 = latLngs[(i + 1) % pointsCount]; area += ((p2.lng - p1.lng) * d2r) * (2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r)); } area = area * 6378137.0 * 6378137.0 / 2.0; } return Math.abs(area); } },
4、清除测量
<button type="button" class="btn btn-sm btn-default" id="clearMeasure">清除</button>
/*清除量算*/ $('#clearMeasure').click(function() { init.qingchu() }) qingchu(func) { for (var i = 0; i < BarDRAWLAYERS.length; i++) { map.removeLayer(BarDRAWLAYERS[i]); } BarDRAWLAYERS = []; if (marker) { map.removeLayer(marker) } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构