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

拾取与交互

先看结论

deck.gl 的拾取不是命中测试,而是把每个图元编码成颜色再读回来。 因此默认所有图层都不可拾取,要显式打开,并且每帧的拾取都有成本。

最后验证 2026-11-03 · deck.gl 9.0 · 难度:入门 · 核验 2026-10-29 · 引用本文

打开拾取并绑定回调

图层默认 pickable: false。打开后,onClick、 onHover、onDrag 这些回调才会收到该图层的信息。 回调参数是一个 info 对象,info.object 是命中的那条数据。

var stationsLayer = new deck.ScatterplotLayer({
  id: 'stations',
  data: stations,
  getPosition: function (d) { return [d.lng, d.lat]; },
  getRadius: function (d) { return d.flow > 800 ? 10 : 6; },
  getFillColor: [40, 140, 255, 200],
  pickable: true,
  autoHighlight: true,
  highlightColor: [255, 200, 0, 220],
  onClick: function (info) {
    console.log('点击', info.object.name, '索引', info.index);
  },
  onHover: function (info) {
    document.body.style.cursor = info.object ? 'pointer' : 'default';
  }
});

new deck.Deck({
  container: 'map',
  initialViewState: {
    longitude: 116.397,
    latitude: 39.908,
    zoom: 11,
    pitch: 0
  },
  controller: true,
  pickingRadius: 6,
  layers: [stationsLayer]
});

autoHighlight 是 deck.gl 内置的悬停高亮,按图层 id 记录当前命中对象, 不需要自己维护状态。highlightColor 的 alpha 决定覆盖强度。

字段含义备注
info.object命中的数据项未命中时为 null
info.index数据在数组中的下标聚合图层为 -1
info.layer命中的图层实例可用于判断来自哪一层
info.coordinate地理坐标[经度, 纬度, 高度]
info.x / info.y画布像素坐标用于放置提示框
info.picked是否命中部分图层会返回额外信息

多层叠加时的拾取顺序

拾取按图层绘制顺序从后往前查,最上层的命中优先返回。 如果上层图层完全透明或 pickable: false,会继续往下找。 这也是「底图盖住了业务图层就点不到」的最常见原因。

var layers = [
  new deck.GeoJsonLayer({
    id: 'parcels',
    data: parcels,
    filled: true,
    pickable: true,
    onClick: function (info) { console.log('地块', info.object.properties.id); }
  }),
  new deck.ScatterplotLayer({
    id: 'stations',
    data: stations,
    getPosition: function (d) { return [d.lng, d.lat]; },
    getRadius: 7,
    pickable: true
  })
];

// Deck 级回调只在所有图层都未命中时触发
var deckgl = new deck.Deck({
  container: 'map',
  initialViewState: { longitude: 116.397, latitude: 39.908, zoom: 11 },
  controller: true,
  layers: layers,
  onClick: function (info, event) {
    if (!info.object) console.log('空白处', info.coordinate);
  }
});

图层回调先于 Deck 回调执行。同一次点击,两层都命中时只会调用最上层图层的 onClick,Deck 级回调拿到的仍是这次命中的 info。

拾取半径影响容差。pickingRadius: 6 让指针周围 6 像素内都算命中, 适合细线和小点。数值过大会让相邻要素互相抢命中,悬停高亮来回跳。

悬停的代价

每次指针移动都会触发一次离屏拾取渲染。十万级散点图开着 onHover 时,帧率下降非常明显。常见做法是只在需要提示的图层打开拾取, 其余图层保持 pickable: false,并用 autoHighlight 代替手写悬停逻辑。

注意事项

  • 图层的 id 必须稳定。每次渲染都换 id 会让 deck.gl 重建图层,拾取状态随之丢失。
  • 聚合图层的 info.object 是聚合结果对象,不是原始数据项;原始点存放在 info.object.points 里。
  • 给 onClick 传箭头函数时,若依赖外部变量,要确认每次渲染都能拿到最新值。
  • 画布尺寸为 0(容器未挂载或隐藏)时拾取全部失效,控制台不会有提示。
  • 移动端触摸事件的坐标是 CSS 像素,info.x / info.y 与之一致,可直接用于定位提示框。
引用本文

经纬志(2026)。《拾取与交互》。https://www.jingweizhi.com/deckgl/tutorial/picking.html(访问日期 2026-11-03)。