Custom layers
Quick answer
This tutorial separates two extension paths in deck.gl: CompositeLayer, which returns built-in layers from renderLayers, and Layer, which owns a Model, shaders and buffers. It builds a station composite of ScatterplotLayer and TextLayer using getSubLayerProps, then outlines initializeState, updateState, draw and getPickingInfo. Readers can package repeated layer stacks or write a GPU layer of their own.
Key points
- Wrap sublayers with this.getSubLayerProps and give each a stable, unique id.
- Create the Model in initializeState, recompute buffers in updateState, draw every frame.
- Map picked indices back to data in getPickingInfo and forward pickable to sublayers.
Example
class StationLayer extends deck.CompositeLayer {
static layerName = 'StationLayer';
renderLayers() {
const data = this.props.data;
const selectedId = this.props.selectedId;
return [
new deck.ScatterplotLayer(this.getSubLayerProps({
id: 'halo',
data: data,
getPosition: function (d) { return [d.lng, d.lat]; },
getRadius: function (d) { return d.id === selectedId ? 18 : 12; },
getFillColor: [40, 140, 255, 60],
radiusUnits: 'pixels'
})),
new deck.ScatterplotLayer(this.getSubLayerProps({
id: 'core',
data: data,
getPosition: function (d) { return [d.lng, d.lat]; },
getRadius: 5,
getFillColor: [40, 140, 255, 230],
radiusUnits: 'pixels'
})),
new deck.TextLayer(this.getSubLayerProps({
id: 'label',
data: data,
getPosition: function (d) { return [d.lng, d.lat]; },
getText: function (d) { return d.name; },
getSize: 12,
getColor: [22, 24, 29, 255],
getTextAnchor: 'middle',
getAlignmentBaseline: 'bottom',
getPixelOffset: [0, -14],
sizeUnits: 'pixels'
}))
];
}
}
var layer = new StationLayer({
id: 'stations',
data: stations,
selectedId: 'BJ-001',
pickable: true
});class HeatGridLayer extends deck.Layer {
static layerName = 'HeatGridLayer';
static defaultProps = { cellSize: 200 };
initializeState() {
this.state.model = this.createModel();
}
updateState(params) {
super.updateState(params);
const { props, oldProps, changeFlags } = params;
if (changeFlags.dataChanged || props.cellSize !== oldProps.cellSize) {
this.state.model.setAttributes({
aGrid: this.buildGrid(props.data, props.cellSize)
});
}
}
draw({ uniforms }) {
this.state.model.setUniforms(uniforms).draw();
}
getPickingInfo({ info }) {
info.object = info.index >= 0 ? this.props.data[info.index] : null;
return info;
}
createModel() { /* 返回 new Model(...) */ }
buildGrid(data, size) { /* 返回计算好的缓冲数据 */ }
}
Notes
- Two sublayers with the same id are merged, so the second one never draws.
- Skipping finalizeState leaks GPU buffers when the layer or page is torn down.
English edition written for Atlaslog. Code is taken from the original Chinese page and runs unchanged.
Atlaslog (2026). Custom layers. https://www.jingweizhi.com/en/deckgl/tutorials/custom-layer.html (accessed 2026-11-03).