瓦片地图是 Web 地图的核心技术,通过将地图切分为小块并按需加载,解决了大规模地理数据的传输和渲染问题。本指南将介绍瓦片地图的基本原理、XYZ 坐标系统、瓦片金字塔结构,以及栅格瓦片与矢量瓦片的区别。
瓦片地图是一种将大尺寸地图切分为固定大小小块(瓦片)的技术方案。每块瓦片通常为 256×256 或 512×512 像素,客户端只加载当前视野内的瓦片,而非整张地图。
┌────────────────────────────────────────────────────────────┐
│ 完整地图 │
│ ┌──────┬──────┬──────┬──────┐ │
│ │ │ │ │ │ │
│ │ 瓦片 │ 瓦片 │ 瓦片 │ 瓦片 │ ← 切分为小块 │
│ │ │ │ │ │ │
│ ├──────┼──────┼──────┼──────┤ │
│ │ │██████│██████│ │ │
│ │ │██可██│██视██│ │ ← 只加载可视区域 │
│ │ │██区██│██域██│ │ │
│ ├──────┼──────┼──────┼──────┤ │
│ │ │██████│██████│ │ │
│ │ │██████│██████│ │ │
│ │ │ │ │ │ │
│ └──────┴──────┴──────┴──────┘ │
└────────────────────────────────────────────────────────────┘
如果将整张世界地图作为单张图片加载,会面临两个核心问题:
| 问题 | 说明 |
|---|---|
| 数据量巨大 | 覆盖全球、细节到街道级别的地图需要数百 GB 甚至 TB 级别存储 |
| 资源浪费 | 用户在某一时刻只关注地图的一小块区域,加载全部数据毫无意义 |
瓦片地图的解决思路:
这就像看报纸:你不会一次把整份报纸摊开,而是翻到你想看的那一页。
| 场景 | 说明 |
|---|---|
| Web 地图 | Google Maps、高德地图、百度地图等在线地图服务 |
| 移动端地图 | 手机导航、打车应用中的地图展示 |
| GIS 系统 | 地理信息系统中的底图服务 |
| 数据可视化 | 基于地图的数据可视化(如 L7、Deck.gl) |
瓦片金字塔是瓦片地图的核心数据结构,通过预先渲染多个精度层级的瓦片,支持不同缩放级别的地图展示。
把同一区域的地图,按不同的精细程度,预先渲染成多个层级。每个层级的瓦片数量呈 4 倍递增:
| 层级 | 瓦片数量 | 网格 | 可见细节 |
|---|---|---|---|
| 0 | 1 | 1×1 | 整个世界轮廓 |
| 1 | 4 | 2×2 | 大洲 |
| 2 | 16 | 4×4 | 国家 |
| 3 | 64 | 8×8 | 省/州 |
| … | … | … | … |
| n | 4^n | 2^n × 2^n | 更多细节 |
从侧面看,层级越低,瓦片越少(塔尖);层级越高,瓦片越多(塔底)。形状像金字塔:
┌───┐
│ 0 │ ← Z=0: 1 张瓦片,世界轮廓
└───┘
┌──┬──┐
│ │ │
├──┼──┤ ← Z=1: 4 张瓦片,大洲可见
│ │ │
└──┴──┘
┌──┬──┬──┬──┐
│ │ │ │ │
├──┼──┼──┼──┤ ← Z=2: 16 张瓦片,国家可见
│ │ │ │ │
└──┴──┴──┴──┘
┌──┬──┬──┬──┬──┬──┬──┬──┐
│ │ │ │ │ │ │ │ │
├──┼──┼──┼──┼──┼──┼──┼──┤ ← Z=3: 64 张瓦片,省/州可见
│ │ │ │ │ │ │ │ │
└──┴──┴──┴──┴──┴──┴──┴──┘
...
| 用户操作 | 层级变化 | 加载策略 |
|---|---|---|
| 缩小地图(看全局) | 使用低层级 | 瓦片数量少,细节少 |
| 放大地图(看细节) | 使用高层级 | 瓦片数量多,细节多 |
常见的瓦片服务提供 0-18 或 0-22 级:
| 层级 | 可见细节 |
|---|---|
| 0-3 | 世界、大洲、国家 |
| 4-8 | 省、市、区 |
| 9-14 | 街道、建筑群 |
| 15-18 | 单栋建筑、道路细节 |
| 19-22 | 车道线、地面标记 |
XYZ 坐标系统是定位瓦片的标准方式,通过三个参数唯一标识每一块瓦片。
| 参数 | 含义 | 说明 |
|---|---|---|
| Z (Zoom) | 层级 | 决定精细程度,0 为最粗 |
| X | 横向位置 | 从左到右,从 0 开始 |
| Y | 纵向位置 | 从上到下,从 0 开始(TMS 规范从下到上) |
以 Z=1 为例,整个世界被分为 2×2 共 4 块瓦片:
X=0 X=1
┌────────┬────────┐
│ │ │
│ (0,0) │ (1,0) │ Y=0
│ │ │
├────────┼────────┤
│ │ │
│ (0,1) │ (1,1) │ Y=1
│ │ │
└────────┴────────┘
| 层级 Z | X 范围 | Y 范围 | 瓦片总数 |
|---|---|---|---|
| 0 | 0 | 0 | 1 |
| 1 | 0-1 | 0-1 | 4 |
| 2 | 0-3 | 0-3 | 16 |
| n | 0 到 2^n-1 | 0 到 2^n-1 | 4^n |
瓦片服务通常使用以下 URL 模板:
https://tile.example.com/{z}/{x}/{y}.png
示例:
| URL | 说明 |
|---|---|
/0/0/0.png |
层级 0,唯一的一块瓦片(整个世界) |
/1/0/0.png |
层级 1,左上角瓦片 |
/3/4/2.png |
层级 3,横向第 5 块(X=4),纵向第 3 块(Y=2) |
地图库内部会根据以下步骤将经纬度转换为瓦片坐标:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 经纬度坐标 │ --> │ Web Mercator │ --> │ XYZ 瓦片坐标 │
│ (lon, lat) │ │ 投影计算 │ │ (z, x, y) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
提示:Web Mercator 投影将球面经纬度映射到平面坐标系,这是瓦片地图能够使用规整网格切分的基础。
瓦片坐标有两种常见规范,主要区别在于 Y 轴方向:
| 规范 | Y 轴方向 | 典型使用者 |
|---|---|---|
| XYZ (Google/OSM) | 从上到下(北→南) | Google Maps、OpenStreetMap、Mapbox |
| TMS | 从下到上(南→北) | 部分 GIS 服务器 |
XYZ 规范(Y 从上到下) TMS 规范(Y 从下到上)
Y=0 ┌────┬────┐ Y=1 ┌────┬────┐
│ │ │ │ │ │
Y=1 ├────┼────┤ Y=0 ├────┼────┤
│ │ │ │ │ │
└────┴────┘ └────┴────┘
转换公式:Y_tms = 2^z - 1 - Y_xyz
瓦片地图有两种技术实现路线:栅格瓦片和矢量瓦片。
栅格瓦片的本质是图片。服务端预先将地图渲染成 PNG/JPG/WebP 格式的图片,客户端直接显示。
┌─────────────────────────────────────────────────────────────┐
│ 服务端 客户端 │
│ │
│ 地理数据 ──→ 渲染引擎 ──→ 图片文件 ──→ 传输 ──→ 直接显示 │
│ (预渲染) (PNG/JPG) │
└─────────────────────────────────────────────────────────────┘
特点:
| 维度 | 说明 |
|---|---|
| 传输内容 | 图片文件(PNG/JPG/WebP) |
| 渲染位置 | 服务端预渲染 |
| 样式修改 | 需要服务端重新生成瓦片 |
| 交互能力 | 无法交互查询单个要素 |
| 客户端要求 | 低,只需显示图片 |
典型场景:卫星影像、地形图、传统底图
矢量瓦片的本质是数据。服务端传输压缩后的几何数据(点、线、面)和属性,客户端负责渲染。
┌─────────────────────────────────────────────────────────────┐
│ 服务端 客户端 │
│ │
│ 地理数据 ──→ 切片+压缩 ──→ PBF文件 ──→ 传输 ──→ 解析+渲染 │
│ (预处理) (二进制) (WebGL/Canvas) │
└─────────────────────────────────────────────────────────────┘
特点:
| 维度 | 说明 |
|---|---|
| 传输内容 | 几何数据 + 属性(PBF 格式) |
| 渲染位置 | 客户端实时渲染 |
| 样式修改 | 客户端即时修改,无需重新获取数据 |
| 交互能力 | 支持要素级交互(如点击高亮、属性查询) |
| 客户端要求 | 需要 GPU 渲染能力(WebGL) |
典型场景:可交互的地图、自定义样式底图、数据可视化
| 维度 | 栅格瓦片 | 矢量瓦片 |
|---|---|---|
| 传输内容 | 图片 | 几何数据 + 属性 |
| 渲染位置 | 服务端 | 客户端 |
| 文件格式 | PNG/JPG/WebP | PBF (Protocol Buffer) |
| 样式修改 | 需重新生成瓦片 | 客户端即时修改 |
| 要素交互 | 不支持 | 支持(点击、悬停、查询) |
| 文件大小 | 较大 | 较小(压缩后) |
| 旋转/倾斜 | 文字跟随旋转 | 文字始终正向 |
| 典型代表 | Google Maps(卫星图)、OSM 栅格 | Mapbox、MapLibre、L7 |
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 卫星影像展示 | 栅格瓦片 | 本身就是图片数据 |
| 传统底图、兼容性优先 | 栅格瓦片 | 客户端要求低 |
| 自定义样式底图 | 矢量瓦片 | 可动态修改样式 |
| 需要要素交互 | 矢量瓦片 | 支持点击查询 |
| 数据可视化叠加 | 矢量瓦片 | 便于与业务数据联动 |
理解瓦片地图原理后,在 L7 源码中会遇到以下相关内容:
L7 的 Source 包(packages/source/)支持多种瓦片格式的解析:
| 格式 | 说明 |
|---|---|
| MVT | Mapbox Vector Tile,矢量瓦片格式 |
| Raster | 栅格瓦片(图片) |
| GeoJSON | 非瓦片数据,但可转换为瓦片加载 |
TileLayer 是 L7 中专门处理瓦片的图层类型,实现了:
L7 的 CoordinateSystemService 处理经纬度与瓦片坐标的转换,涉及:
Q1: 瓦片大小为什么通常是 256×256?
256 是 2 的 8 次方,便于二进制计算和内存对齐。同时这个大小在网络传输和渲染性能之间取得了较好的平衡。部分现代服务(如 Mapbox)使用 512×512 的高清瓦片。
Q2: 瓦片地图如何处理跨层级的平滑缩放?
在缩放过渡期间,地图库会同时显示当前层级和目标层级的瓦片,通过淡入淡出或缩放动画实现平滑过渡。目标层级的瓦片加载完成后,移除旧层级的瓦片。
Q3: 矢量瓦片的 PBF 格式是什么?
PBF(Protocol Buffer Binary Format)是 Google Protocol Buffers 的二进制格式。相比 JSON,PBF 体积更小、解析更快,适合传输大量几何数据。Mapbox Vector Tile 规范使用 PBF 作为编码格式。
Q4: 如何选择合适的最大缩放层级?
取决于数据精度和应用场景:
| 场景 | 建议最大层级 |
|---|---|
| 全国/省级概览 | 10-12 |
| 城市级应用 | 14-16 |
| 街道级导航 | 18-20 |
| 室内地图 | 20-22 |
{z}/{x}/{y}| 概念 | 说明 |
|---|---|
| 瓦片大小 | 通常 256×256 或 512×512 像素 |
| 层级范围 | 通常 0-18 或 0-22 |
| 层级 n 瓦片数 | 4^n(横向 2^n × 纵向 2^n) |
| XYZ URL | https://server/{z}/{x}/{y}.png |
| 栅格格式 | PNG、JPG、WebP |
| 矢量格式 | PBF (Mapbox Vector Tile) |
| 坐标系 | Web Mercator (EPSG:3857) |