经纬志
首页 / 实战手册 / 瓦片

瓦片目录从 1 级开始,地图整体放大了一倍

先看结论

离线包只有 1~19 级目录,前端按 0 级起算,画面始终比实际大一号,19 级还缺图。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

用 MOBAC 导出的离线瓦片,目录结构是 1/0/0.png 到 19/...png, 没有 0 级。 前端配置 minZoom: 0, maxZoom: 18 后:

  • 地图初始级别显示的是 1 级的画面,但控件显示 zoom 0。
  • 缩放到最大时出现灰块,网络面板请求 18/x/y.png 实际全部命中 19 级目录之外的空白。
  • 叠加的矢量数据比底图小一半。

原因

瓦片层级只是一个目录名,切图工具默认从 1 级开始(1 级全球 2×2 张瓦片), 而 Leaflet 的 zoom 从 0 开始,0 级全球 1×1 张。

两者差 1,导致请求的 {z} 比目录小 1: Leaflet 的 0 级去请求 0/ 目录,不存在; 实际能显示的是 Leaflet 1 级对应的 1/ 目录,于是一直错位。

排查过程

  1. 列出瓦片根目录,看最小的层级目录号是 0 还是 1。
  2. 在 tileload 事件里打印 e.coords,与目录号对比。
  3. 看最大层级目录号,与 maxZoom 配置比较。
  4. 检查 minNativeZoom / maxNativeZoom 是否设置,它们不影响请求层级但影响放大行为。
map.on('tileload', e => console.log(e.coords, e.tile.src));
// { x: 0, y: 0, z: 1 }  -> 实际请求 /tiles/1/0/0.png

// 目录结构
// tiles/1/0/0.png
// tiles/2/0/0.png ... tiles/2/3/3.png   (2 级 4×4)
// tiles/19/...

解决方案

用 zoomOffset 把前端层级平移到目录层级。 zoomOffset: -1 表示请求时 z = 前端 zoom + (-1), 但更直观的做法是让 minZoom 从 1 开始并设 zoomOffset: 0,两者择一。

// 目录从 1 级起,前端也从 1 级起:直接对齐
L.tileLayer('/tiles/{z}/{x}/{y}.png', {
  minZoom: 1,
  maxZoom: 19,
  tileSize: 256
}).addTo(map);

// 或者保持前端 0 级起,用 zoomOffset 补偿
L.tileLayer('/tiles/{z}/{x}/{y}.png', {
  minZoom: 0,
  maxZoom: 18,
  zoomOffset: 1,        // 请求 z = zoom + 1
  tileSize: 256
}).addTo(map);

maxNativeZoom 与 maxZoom 不是一回事。 目录只到 19 级时,把 maxNativeZoom 设为 19、maxZoom 设为 21, Leaflet 会把 19 级瓦片放大复用,不会请求不存在的层级。

验证

tileload 打印的 z 与请求目录号一致; 缩放到最大级别仍能出图(复用 19 级瓦片),不再出现灰块; 叠加矢量数据与底图对齐。

console.assert(e.coords.z === Number(e.tile.src.match(/\/(\d+)\//)[1]), '层级仍未对齐');
map.setZoom(21);   // 不应出现 404

适用版本

库 / 工具版本说明
Leaflet1.7 ~ 1.9zoomOffset 与 maxNativeZoom 均可用
OpenLayers9.x用 createXYZ({ minZoom, maxZoom }) 显式对齐
MOBAC2.x默认最小层级为 1
引用本文

经纬志(2026)。《瓦片目录从 1 级开始,地图整体放大了一倍》。https://www.jingweizhi.com/cookbook/tile-z-offset.html(访问日期 2026-11-03)。