本节摘要:地图瓦片让大规模地图加载又快又流畅。本节讲瓦片金字塔、层级行列索引、矢量瓦片——地图服务加速的核心技术。
阅读完本节,你应当能够:
整张地图太大,一次加载慢且浪费。瓦片把地图按层级切成小方块(如 256x256),前端只加载视野内的瓦片,按需加载,快且省流量。

地图按缩放层级分层,每级瓦片数 2^z × 2^z:
每块瓦片用 z/x/y 索引,URL 形如 `「相关地址请参见官方文档」 x/y 范围,只加载这些瓦片。
| 维度 | 栅格瓦片 | 矢量瓦片(MVT) |
|---|---|---|
| 内容 | 渲染好的图片 | 矢量数据 |
| 样式 | 服务端固定 | 前端动态控制 |
| 大小 | 较大 | 较小 |
| 分析 | 不能 | 可提取要素 |
| 缓存 | 简单 | 按需渲染 |
栅格瓦片(如 WMTS、XYZ 瓦片)是图片,快但样式固定。矢量瓦片(MVT)传数据,前端渲染,样式动态可控,是现代趋势。
常见瓦片方案:
前端库通常支持多种方案,注意 y 方向差异。
⚠️ 常见坑:栅格瓦片样式想动态改——栅格瓦片是图片样式固定,要动态样式用矢量瓦片。
💡 关键直觉:瓦片按 z/x/y 索引,前端按视野加载。栅格瓦片是图片快但样式固定,矢量瓦片传数据样式前端控。预渲染快占空间,按需渲染省空间首次慢。
前端要"按视野加载瓦片",就得把屏幕范围换算成 z/x/y 瓦片号。以 Web 墨卡托(3857)的 XYZ 方案为例,核心是两次投影:经纬度转墨卡托平面坐标,再按 2 的 z 次方分块取整:
function lonLatToTile(lon, lat, z) { const n = Math.pow(2, z); const x = Math.floor((lon + 180) / 360 * n); const latRad = lat * Math.PI / 180; const y = Math.floor((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n); return { x, y, z }; } console.log(lonLatToTile(116.4, 39.9, 12)); // 输出该点在 12 级下的瓦片号
反过来,给定瓦片号可以算出它覆盖的经纬度范围。理解这个换算,才能处理"瓦片偏移""白边"这类问题——通常是 y 轴方向(XYZ 向下、TMS 向上)或原点(左上 vs 左下)搞反了。
| 方案 | 原理 | 优势 | 局限 |
|---|---|---|---|
| WMTS | 标准瓦片服务 | 标准互通、可缓存 | 配置略重 |
| XYZ | 直接文件路径 | 简单、CDN 友好 | 非 OGC 标准 |
| TMS | 类似 XYZ 但 y 反向 | 老工具兼容 | 客户端要处理 y |
| MVT | 矢量瓦片 | 样式动态、体积小 | 前端渲染负担 |
实践中:前端直接用 XYZ 最省事(OpenLayers、Leaflet 都原生支持);对第三方系统开放用 WMTS 更规范;自己搭渲染管线追求灵活用 MVT。
预渲染瓦片常用这些工具,选型看数据量和更新频率:
# GDAL 生成金字塔和瓦片(栅格) gdal2tiles.py -z 0-12 -p raster input.tif tiles/ # 矢量瓦片:用 tippecanoe 把 GeoJSON 切 MVT tippecanoe -zg -o roads.mbtiles roads.geojson # 从 mbtiles 发布瓦片服务(工具很多,原理一致)
增量更新场景别整库重渲:只对变化区域重新生成对应层级瓦片,再覆盖到瓦片目录,配合 CDN 刷新缓存,成本低很多。
选瓦片方案要同时看数据性质、访问模式和团队能力:
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 全球底图展示 | XYZ 栅格瓦片 | 简单,CDN 友好,数据现成 |
| 业务矢量展示 | MVT 矢量瓦片 | 样式可调、体积小 |
| 对接第三方系统 | WMTS | 标准协议,互通 |
| 离线移动端 | MBTiles | 单文件,App 好读 |
| 海量影像 | COG 加金字塔 | 按需读块,云端友好 |
一个常见误区是把"瓦片"等同于"地图图片"。矢量瓦片、COG、3D Tiles 都是瓦片思想在不同数据上的延伸——把大对象切成小块按需加载。理解了这个本质,选型就有了主线:按数据是什么、在哪个端消费、要不要动态样式来判断。
上线后跟踪这些指标判断瓦片服务是否健康:
2^z × 2^z 块,z 越大越细节。z/x/y,前端按视野算需要的瓦片。第 3 章结束。下一章讲前端怎么消费这些服务。