首页 / 实战手册 / 瓦片
缩小到 3 级时地图重复了三次,noWrap 没开
先看结论
缩到最小级别,屏幕上并排出现三个中国,左右两边还是镜像拼接的。
现象
地图容器宽 1600 像素,缩放到 3 级时, 屏幕上同时出现三份中国地图,横向排列; 左右两份与中间的不连续,接缝处是海岸线直接拼内陆。
拖动地图时,重复的图案会跟着滚动,缩小到 2 级时变成五份。
原因
Leaflet 默认开启世界环绕(wrap):当 2^z × tileSize 小于视口宽度时,
会横向重复平铺瓦片,让地图看起来「无限宽」。
3 级时全球宽度为 8 × 256 = 2048 像素,不足以填满 1600 以上的容器多次,
于是出现重复。
只在中国范围使用的瓦片服务,没有全球数据, 重复出来的部分要么是同一张图,要么是 404,视觉上很怪。
排查过程
- 算当前级别的世界宽度
2^z × tileSize,与容器宽度比较。 - 看是否有
noWrap配置,默认是false。 - 检查
bounds是否设置,设置了 bounds 会自动限制到该范围。 - 看
minZoom是否太小,很多国内底图最小只支持 3 或 4 级。
const worldWidth = Math.pow(2, map.getZoom()) * 256;
console.log(worldWidth, map.getSize().x);
// 3 级: 2048 vs 1600 -> 世界比视口宽,不应重复
// 2 级: 1024 vs 1600 -> 世界比视口窄,必然重复
解决方案
国内范围底图关闭环绕,并限制最小缩放级别。
L.tileLayer('https://tile.example.com/{z}/{x}/{y}.png', {
minZoom: 4,
maxZoom: 18,
noWrap: true,
bounds: [[3.5, 73.0], [53.6, 135.1]] // 中国范围
}).addTo(map);
// 同时限制地图本身的最小级别
const map = L.map('map', {
minZoom: 4,
maxBounds: [[3.5, 73.0], [53.6, 135.1]],
maxBoundsViscosity: 0.8
});
// OpenLayers:在 tileGrid extent 上限制
new TileLayer({
source: new XYZ({
url: 'https://tile.example.com/{z}/{x}/{y}.png',
wrapX: false,
tileGrid: createXYZ({
extent: getProjection('EPSG:3857').getExtent(),
minZoom: 4,
maxZoom: 18,
tileSize: 256
})
})
});
验证
缩放到 4 级时画面只有一份中国,左右边缘是空白而不是重复图案;
继续缩小被 minZoom 拦住,不会出现 2 级。
console.assert(map.getZoom() >= 4, '仍可缩到 4 级以下');
console.assert(layer.options.noWrap === true, 'noWrap 未开');
// 各级世界宽度与视口宽度的关系
console.assert(Math.pow(2, 4) * 256 >= map.getSize().x, '4 级世界仍窄于视口');
适用版本
| 库 | 版本 | 说明 |
|---|---|---|
| Leaflet | 1.9.x | noWrap 默认 false,bounds 单独设也可限制 |
| OpenLayers | 9.x | XYZ 的 wrapX 默认 true |
| Mapbox GL JS | 2.x / 3.x | 同样默认横向重复 |
经纬志(2026)。《缩小到 3 级时地图重复了三次,noWrap 没开》。https://www.jingweizhi.com/cookbook/tile-nowrap-out-of-range.html(访问日期 2026-11-03)。