You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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方法,步骤为:

  1. 根据瓦片坐标计算当前瓦片对应的经纬度边界
  2. 根据当前地图缩放等级确定要生成的OLC码长度
  3. 遍历瓦片范围内所有对应精度的OLC网格,计算每个网格在当前瓦片canvas上的像素坐标
  4. 绘制网格边框,可选择性绘制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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 00:54:01