1. 绘制需求
1)每层级网格像素大小不变,即每层级,网格经纬度距离加密一次;
2)页面顶部和右侧标注经度、纬度值;
3)经纬度值精度随层级变化;
4)尽量避免显示区域外的多余绘制,同时保证拖动时不会出现没有网格的情况;
2. 代码实现
1)确定网格线间隔,经线范围:-180~180;纬线:-90~90;
间隔值应当为180、90的公约数,这样能保证过0°经线;比如:
1级:-180、-90、0、90、180
2级:-180、-135、-90、-45、0、45、90、135、180
......
let zoom = map.getZoom();
// 经纬度间隔
let d = 90 / Math.pow(2, zoom - 1);
2) 只绘制当前视野内的线
3)在边界上添加标注
let zoom = map.getZoom();
let bounds = map.getBounds();
let north = bounds.getNorth();
let east = bounds.getEast();
// 经纬度间隔
let d = 90 / Math.pow(2, zoom - 1);
// 经线网格
for (let index = -180; index <= 360; index += d) {
// 判断当前视野内
if (bounds.contains([north, index])) {
// 绘制经线
let lonLine = L.polyline(
[
[-90, index],
[90, index],
],
{ weight: 1, color: "blue" }
);
lonLatGridLineLayer.addLayer(lonLine);
// 标注
let text = index.toFixed(1) + "°";
// 动态计算小数位数
if (zoom > 10) {
text = index.toFixed((zoom - 8) / 2) + "°";
}
let divIcon = L.divIcon({
html: `<div style="white-space: nowrap;color:red;">${text}</div>`,
iconAnchor: [0, -5],
});
let textMarker = L.marker([north, index], { icon: divIcon });
lonLatGridLineLayer.addLayer(textMarker);
}
}
4)缩放和拖动事件,重绘网格
map.on("zoomend move", () => {
lonLatGridLineLayer.clearLayers();
addLonLatLine();
});
3.全部代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
/>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<title>leaflet-经纬网格</title>
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.leaflet-div-icon {
background: none;
border: none;
}
</style>
</head>
<body>
<div id="map" style="height: 100%; width: 100%"></div>
<script>
let map = L.map("map", { renderer: L.canvas({ padding: 0.5 }) }).setView(
[25.127879288597576, 118.37905883789064],
4
);
// 添加背景图层
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
// 创建图层
let lonLatGridLineLayer = L.featureGroup().addTo(map);
// 经纬网格生成方法
let addLonLatLine = () => {
let zoom = map.getZoom();
let bounds = map.getBounds();
let north = bounds.getNorth();
let east = bounds.getEast();
// 经纬度间隔
let d = 90 / Math.pow(2, zoom - 1);
// 经线网格
for (let index = -180; index <= 360; index += d) {
// 判断当前视野内
if (bounds.contains([north, index])) {
// 绘制经线
let lonLine = L.polyline(
[
[-90, index],
[90, index],
],
{ weight: 1, color: "blue" }
);
lonLatGridLineLayer.addLayer(lonLine);
// 标注
let text = index.toFixed(1) + "°";
// 动态计算小数位数
if (zoom > 10) {
text = index.toFixed((zoom - 8) / 2) + "°";
}
let divIcon = L.divIcon({
html: `<div style="white-space: nowrap;color:red;">${text}</div>`,
iconAnchor: [0, -5],
});
let textMarker = L.marker([north, index], { icon: divIcon });
lonLatGridLineLayer.addLayer(textMarker);
}
}
if(d>90)d=90;
// 纬线网格
for (let index = -90; index <= 90; index += d) {
if (bounds.contains([index, east])) {
let lonLine = L.polyline(
[
[index, -180],
[index, 360],
],
{ weight: 1, color: "blue" }
);
lonLatGridLineLayer.addLayer(lonLine);
// 标注
let text = index.toFixed(1) + "°";
if (zoom > 10) {
text = index.toFixed((zoom - 8) / 2) + "°";
}
let divIcon = L.divIcon({
html: `<div style="white-space: nowrap;color:red;">${text}</div>`,
iconAnchor: [(text.length + 1) * 6, 0],
});
let textMarker = L.marker([index, east], { icon: divIcon });
lonLatGridLineLayer.addLayer(textMarker);
}
}
};
addLonLatLine();
map.on("zoomend move", () => {
lonLatGridLineLayer.clearLayers();
addLonLatLine();
});
</script>
</body>
</html>