如何在React Leaflet中绘制随缩放分级的Pluscodes (OLC)网格
实现方案说明
1. 方案选型判断
L.GridLayer完全适合该需求,它的瓦片按需渲染机制正好适配不同缩放层级展示不同粒度Pluscodes网格的要求,不需要更换其他方案。
2. 核心实现逻辑
首先需要建立地图缩放层级与Open Location Code(OLC)精度的对应关系,参考匹配规则如下:
- 缩放等级 < 6:使用4位OLC,网格精度约20km
- 缩放等级 6~8:使用6位OLC,网格精度约2km
- 缩放等级 9~11:使用8位OLC,网格精度约200m
- 缩放等级 ≥12:使用10位OLC,网格精度约14m
然后重写createTile方法,步骤为:
- 根据瓦片坐标计算当前瓦片对应的经纬度边界
- 根据当前地图缩放等级确定要生成的OLC码长度
- 遍历瓦片范围内所有对应精度的OLC网格,计算每个网格在当前瓦片canvas上的像素坐标
- 绘制网格边框,可选择性绘制OLC编码文本
3. 修改后代码示例
Grid.jsx
import { useEffect } from "react"; import L from "leaflet"; import { useLeafletContext } from "@react-leaflet/core"; import { OpenLocationCode } from "open-location-code"; const olc = new OpenLocationCode(); // 缩放等级对应OLC长度 const getOlcLengthByZoom = (zoom) => { if (zoom < 6) return 4; if (zoom < 9) return 6; if (zoom < 12) return 8; return 10; }; const PlusCodeGrid = () => { const { layerContainer, map } = useLeafletContext(); const createLeafletElement = () => { const Grid = L.GridLayer.extend({ createTile: function (coords) { const tile = L.DomUtil.create("canvas", "leaflet-tile"); const tileSize = this.getTileSize(); tile.width = tileSize.x; tile.height = tileSize.y; const ctx = tile.getContext('2d'); ctx.strokeStyle = 'rgba(0,0,0,0.6)'; ctx.lineWidth = 1; ctx.font = '12px Arial'; ctx.fillStyle = 'rgba(0,0,0,0.7)'; // 计算当前瓦片的经纬度范围 const nwPoint = L.point(coords.x * tileSize.x, coords.y * tileSize.y); const sePoint = L.point((coords.x + 1) * tileSize.x, (coords.y + 1) * tileSize.y); const nwLatLng = map.unproject(nwPoint, coords.z); const seLatLng = map.unproject(sePoint, coords.z); const olcLength = getOlcLengthByZoom(coords.z); // 获取瓦片范围四个角的OLC,确定遍历范围 const nwCode = olc.encode(nwLatLng.lat, nwLatLng.lng, olcLength); const seCode = olc.encode(seLatLng.lat, seLatLng.lng, olcLength); const nwDecoded = olc.decode(nwCode); const seDecoded = olc.decode(seCode); // 遍历范围内所有OLC网格 let lat = nwDecoded.latitudeHi; while (lat > seDecoded.latitudeLo) { let lng = nwDecoded.longitudeLo; while (lng < seDecoded.longitudeHi) { const code = olc.encode(lat, lng, olcLength); const decoded = olc.decode(code); // 转换经纬度为瓦片内像素坐标 const cellNw = map.project([decoded.latitudeHi, decoded.longitudeLo], coords.z); const cellSe = map.project([decoded.latitudeLo, decoded.longitudeHi], coords.z); const x = cellNw.x - (coords.x * tileSize.x); const y = cellNw.y - (coords.y * tileSize.y); const w = cellSe.x - cellNw.x; const h = cellSe.y - cellNw.y; // 绘制边框 ctx.strokeRect(x, y, w, h); // 缩放等级足够时绘制OLC编码 if (olcLength >= 8 && w > 30 && h > 15) { ctx.fillText(code.replace('+', ''), x + 2, y + 15); } lng = decoded.longitudeHi; } lat = decoded.latitudeLo; } return tile; } }); return new Grid({ tileSize: 256 }); }; useEffect(() => { const gridLayer = createLeafletElement(); layerContainer.addLayer(gridLayer); // 缩放变化时重绘图层 map.on('zoomend', () => { gridLayer.redraw(); }); return () => { layerContainer.removeLayer(gridLayer); }; }, []); return null; }; export default PlusCodeGrid;
App.jsx 无需大改,保持原有逻辑即可,注意确保已经安装open-location-code依赖。
4. 优化建议
- 可根据需求调整OLC长度与缩放等级的对应规则,平衡显示效果与性能
- 低缩放等级下可降低边框透明度、隐藏文字,避免界面杂乱
- 可添加OLC网格点击交互,点击时获取对应网格的编码与边界信息
内容的提问来源于stack exchange,提问作者Özenç B.
相关产品推荐
相关产品推荐

