瓦片图层:TileLayer 与 MVTLayer
数据超过几十万条时,一次性下载和建模都不可行。瓦片图层把请求拆到不同缩放级别, 只加载当前视野需要的切片,渲染再交给子图层完成。
TileLayer 负责调度,不负责画
TileLayer 本身不渲染任何内容。它按 Web 墨卡托切分视野,
为每个瓦片请求数据,然后调用 renderSubLayers,
由你返回一个真正的绘制图层。props.tile 里带着瓦片边界与索引。
var parcelsTile = new deck.TileLayer({
id: 'parcels-tiles',
data: 'https://tiles.example.com/parcels/{z}/{x}/{y}.geojson',
minZoom: 8,
maxZoom: 16,
tileSize: 256,
maxRequests: 8,
refinementStrategy: 'best-available',
renderSubLayers: function (props) {
var west = props.tile.bbox.west;
var south = props.tile.bbox.south;
var east = props.tile.bbox.east;
var north = props.tile.bbox.north;
return new deck.GeoJsonLayer({
id: props.id,
data: props.data,
filled: true,
stroked: true,
getFillColor: [31, 95, 208, 90],
getLineColor: [255, 255, 255, 200],
getLineWidth: 1,
lineWidthUnits: 'pixels',
pickable: true
});
}
});
子图层的 id 必须带上瓦片编号,直接复用 props.id
最省事。子图层数据已经由 TileLayer 解析好,GeoJsonLayer 直接接收对象即可。
瓦片边界不需要手动裁剪。服务端按瓦片切好的数据只包含该瓦片内的几何,
bbox 主要用于定位标注或计算密度,不是用来裁剪的。
MVTLayer:少一层封装
MVTLayer 继承自 TileLayer,内置了 MVT 解析和子图层生成。
一个 MVT 图层内部会自动按几何类型拆成面、线、点三类子图层,
样式通过同名访问器传给它们。
var mvt = new deck.MVTLayer({
id: 'base-mvt',
data: 'https://tiles.example.com/base/{z}/{x}/{y}.pbf',
minZoom: 0,
maxZoom: 14,
binary: true,
getFillColor: function (f) {
var kind = f.properties.kind;
if (kind === 'water') return [20, 80, 160, 200];
if (kind === 'park') return [60, 160, 90, 180];
return [230, 230, 230, 120];
},
getLineColor: [255, 255, 255, 180],
getLineWidth: 1,
lineWidthMinPixels: 1,
pickable: true
});
binary: true 让 MVT 以二进制属性表加载,内存占用和解析时间都更低,
代价是访问属性要通过 f.properties 的代理对象,不能直接改原始 JSON。
| 方案 | 数据格式 | 样式控制 | 适用 |
|---|---|---|---|
| 直接 GeoJsonLayer | 整份 GeoJSON | 完整 | 几千个要素,一次加载 |
| TileLayer + GeoJsonLayer | 按瓦片切的 GeoJSON | 完整 | 十万级,服务端已切片 |
| TileLayer + 任意子图层 | 自定义 JSON | 完整 | 聚合结果、格网等非矢量数据 |
| MVTLayer | MVT | 按几何类型统一 | 底图、大规模行政区划 |
请求调度与失败处理
TileLayer 按视口计算需要哪些瓦片,并限制同时进行的请求数。 内网服务可以适当调高并发,公网服务则要保守,避免浏览器队列拖慢交互。
var tuned = new deck.TileLayer({
id: 'parcels-tuned',
data: 'https://tiles.example.com/parcels/{z}/{x}/{y}.geojson',
tileSize: 256,
minZoom: 8,
maxZoom: 16,
maxRequests: 12,
renderSubLayers: function (props) {
return new deck.GeoJsonLayer({
id: props.id,
data: props.data,
filled: true,
getFillColor: [31, 95, 208, 90]
});
},
onTileError: function (tile, error) {
console.warn('瓦片加载失败', tile.id, error.message);
}
});
单个瓦片失败不会中断整个图层,画面上只会留下一块空白。
onTileError 是把这类问题暴露出来的最直接方式。
注意事项
- 瓦片地址模板里的
{z}/{x}/{y}由 TileLayer 自动替换,服务端若是 TMS 方案需要自行翻转 y。 tileSize要与切片服务一致,256 的服务按 512 请求会拿到错位内容。refinementStrategy决定低级别瓦片何时被替换,best-available视觉最稳,never最省流量。- 瓦片缓存默认按视口保留,快速平移再返回时会重新请求,可调大
maxCacheSize。 - 子图层数量随瓦片数增长,每帧都会遍历,图层多时把不必要的高级别瓦片限制掉。
- MVTLayer 读取的源图层名由切片决定,属性名消失通常意味着服务端换了切片方案。
先看请求数再看帧率。瓦片类问题大多出在请求过多或层级过深。 用浏览器网络面板确认同一时刻的并发请求数,比盯着 fps 更容易定位。
经纬志(2026)。《瓦片图层:TileLayer 与 MVTLayer》。https://www.jingweizhi.com/deckgl/tutorial/tile-layers.html(访问日期 2026-11-03)。