经纬志
首页 / deck.gl / 教程

数据源与二进制属性

先看结论

同一批点可以用对象数组、GeoJSON 或二进制缓冲三种方式交给图层。 前两种写起来快,第三种省内存和解析时间,选择取决于数据规模与更新频率。

最后验证 2026-11-03 · deck.gl 9.0 · 难度:进阶 · 核验 2026-10-29 · 引用本文
形态写法优点适用
对象数组data: [{lng, lat}]直观,访问器直接读字段几千到几万条
GeoJSONdata: featureCollection带几何与属性,图层自动解析面与线、需要保留属性
CSVloaders.gl 解析后得到对象数组业务数据导出方便表格类点位
二进制属性{length, attributes}无对象开销,上传显存快十万级以上

二进制属性怎么写

二进制数据不是另一种图层,而是给图层换一种 data 结构。 属性名与图层属性同名,size 表示每条数据占几个分量, value 是一个类型化数组。

var N = stations.length;
var positions = new Float32Array(N * 2);
var radii = new Float32Array(N);
var colors = new Uint8Array(N * 4);

for (var i = 0; i < N; i++) {
  positions[i * 2] = stations[i].lng;
  positions[i * 2 + 1] = stations[i].lat;
  radii[i] = stations[i].flow > 800 ? 9 : 5;
  colors[i * 4] = 40;
  colors[i * 4 + 1] = 140;
  colors[i * 4 + 2] = 255;
  colors[i * 4 + 3] = 200;
}

var binaryData = {
  length: N,
  attributes: {
    getPosition: { value: positions, size: 2 },
    getRadius: { value: radii, size: 1 },
    getFillColor: { value: colors, size: 4 }
  }
};

new deck.ScatterplotLayer({
  id: 'stations-binary',
  data: binaryData,
  radiusUnits: 'pixels',
  pickable: true
});

二进制模式下不再需要写 getPosition 这类访问器, 图层直接读取属性缓冲。写错 size 不会报错,只会看到位置错乱或颜色异常。

数组长度必须够。N * size 少了任何一个分量都会读到 undefined, 表现为最后一个要素位置为 0。构造完先打印 positions.length 核对。

CSV 与 GeoJSON 的加载

CSV 不会自动带坐标,需要先解析成对象数组,再在访问器里转成数值。 字符串直接参与位置计算会得到 NaN。

import { load } from '@loaders.gl/core';
import { CSVLoader } from '@loaders.gl/csv';

const rows = await load('/data/stations.csv', CSVLoader);

new deck.ScatterplotLayer({
  id: 'stations-csv',
  data: rows,
  getPosition: function (d) {
    return [Number(d.lng), Number(d.lat)];
  },
  getRadius: 6,
  radiusUnits: 'pixels'
});

// GeoJSON 直接交给复合图层,几何与属性都由它解析
new deck.GeoJsonLayer({
  id: 'districts',
  data: '/data/districts.geojson',
  filled: true,
  getFillColor: [31, 95, 208, 60],
  getLineColor: [31, 95, 208, 220]
});

用扩展做 GPU 过滤

按阈值筛选时,常见做法是过滤数组后重建图层,数据一变就要重新上传缓冲。 DataFilterExtension 把筛选条件传给着色器,滑动阈值时不需要重建数据。

import { DataFilterExtension } from '@deck.gl/extensions';

var filter = new DataFilterExtension({ filterSize: 1 });

var layer = new deck.ScatterplotLayer({
  id: 'stations-filtered',
  data: stations,
  getPosition: function (d) { return [d.lng, d.lat]; },
  getRadius: 6,
  radiusUnits: 'pixels',
  getFilterValue: function (d) { return d.flow; },
  filterRange: [500, 2000],
  extensions: [filter],
  updateTriggers: {
    getFilterValue: flowDomain
  }
});

// 只改阈值,数据与缓冲都不动
layer.setProps({ filterRange: [1200, 2000] });

filterSize 决定每条数据有几个筛选维度。二维筛选(比如同时限制流量与距离)时 把 size 设为 2,访问器返回两个数的数组。

注意事项

  • 二进制属性的 value 必须是类型化数组,普通数组不会走快速路径。
  • 数据对象变化后要更换 data 引用,原地修改类型化数组不会触发更新。
  • GeoJSON 的属性读取要经过 feature.properties,访问器里直接读 d.flow 会得到 undefined。
  • CSV 解析出的数字是字符串还是数值取决于加载器配置,必要时统一 Number() 转换。
  • 过滤扩展只影响显示与拾取,不影响图层内部统计,聚合图层的权重仍需自行处理。

先统一坐标再谈格式。不管来自哪种数据源,进入图层前都应该先转成 [经度, 纬度] 数组。坐标预处理一次,比在每个访问器里转换更省心。

引用本文

经纬志(2026)。《数据源与二进制属性》。https://www.jingweizhi.com/deckgl/tutorial/data-formats.html(访问日期 2026-11-03)。