Layer — фундаментальная абстракция, на которой строится
вся система визуализации. Любая графическая сущность в deck.gl, будь то
точки, линии, полигоны или кастомные WebGL-объекты, реализуется через
наследование от этого базового класса.
Ключевая идея:
Layer описывает, как данные превращаются в GPU-геометрию и как она обновляется при изменении входных параметров.
Он не выполняет непосредственный рендер в привычном смысле, а управляет состоянием WebGL-ресурсов, атрибутами и жизненным циклом отрисовки.
Каждый слой можно рассматривать как преобразователь:
data → attributes → shaders → GPU primitives
Где:
data — входной набор данных (GeoJSON, массив координат,
таблицы и т.д.)attributes — буферы вершин и дополнительных данныхshaders — GLSL-программы для вершин и фрагментовКаждый слой создаётся через объект свойств:
new MyLayer({
id: 'custom-layer',
data: [],
opacity: 1,
pickable: true
});
id — уникальный идентификатор слояdata — источник данныхvisible — управляет отображениемopacity — прозрачность слояpickable — включение интерактивности (picking)parameters — WebGL параметры (blending, depth test и
др.)Props в deck.gl иммутабельны на уровне концепции. Любое изменение props приводит к сравнению (diffing) и потенциальному обновлению GPU-ресурсов.
Каждый слой имеет внутреннее состояние, которое не доступно напрямую извне.
Типичный state может содержать:
Пример:
this.state = {
model: null,
attributeManager: null,
lastDataUpdate: null
};
Вызывается один раз при создании слоя.
Назначение:
initializeState() {
const attributeManager = this.getAttributeManager();
attributeManager.addInstanced({
positions: { size: 3, accessor: 'getPosition' }
});
this.setState({ attributeManager });
}
Вызывается при изменении props или состояния контекста.
Основная задача — определить, что изменилось, и обновить только необходимое.
Типичные случаи обновления:
datagetPosition,
getColor)updateState({ props, oldProps, changeFlags }) {
if (changeFlags.dataChanged) {
this._updateGeometry(props.data);
}
if (changeFlags.updateTriggersChanged) {
this.state.attributeManager.invalidateAll();
}
}
Отвечает за фактический рендер в WebGL контекст.
draw({ uniforms }) {
this.state.model.setUniforms(uniforms);
this.state.model.draw();
}
Освобождение ресурсов:
finalizeState() {
this.state.model.delete();
}
Deck.gl использует систему атрибутов для эффективного батчинга данных в GPU.
Каждое поле данных превращается в buffer attribute.
Пример:
attributeManager.add({
positions: {
size: 3,
accessor: 'getPosition'
},
colors: {
size: 4,
accessor: 'getColor',
defaultValue: [255, 0, 0, 255]
}
});
Позволяют контролировать пересчёт атрибутов:
updateTriggers: {
getColor: [this.props.colorRange]
}
Если зависимости изменились — атрибуты пересчитываются.
Перед вызовом updateState deck.gl выполняет сравнение
props:
Категории изменений:
DATA_CHANGEDPROPS_CHANGEDMODEL_CHANGEDSTATE_CHANGEDVIEWPORT_CHANGEDЭто позволяет минимизировать WebGL перерасчёты.
Создание кастомного слоя требует расширения базового класса:
import {Layer} from '@deck.gl/core';
class PointLayer extends Layer {
initializeState() {
this.state = {
positions: []
};
}
updateState({props}) {
if (props.data !== this.state.lastData) {
this._processData(props.data);
}
}
draw({uniforms}) {
// WebGL draw logic
}
}
Каждый слой связан с GLSL программами:
Deck.gl автоматически инжектирует:
Пример структуры:
const vs = `
attribute vec3 positions;
void main() {
gl_Position = project_position_to_clipspace(positions);
}
`;
const fs = `
void main() {
gl_FragColor = vec4(1.0);
}
`;
Layer не рисует напрямую — он использует Model:
this.state.model = new Model(gl, {
vs,
fs,
geometry: new CubeGeometry()
});
Layer поддерживает GPU picking через специальный render pass.
Механизм:
pickable: true
Layer работает в разных системах координат:
Deck.gl автоматически применяет трансформации через
project функции в шейдерах.
Layer может возвращать дочерние слои:
renderLayers() {
return [
new ScatterplotLayer(this.props),
new LineLayer(this.props)
];
}
Это позволяет строить сложные визуализации как композицию простых слоёв.
Ключевые механизмы производительности:
class CustomLayer extends Layer {
initializeState() {
const {gl} = this.context;
this.state.model = new Model(gl, {
vs,
fs,
geometry: new TriangleGeometry()
});
}
updateState({props, changeFlags}) {
if (changeFlags.dataChanged) {
this._updateData(props.data);
}
}
draw({uniforms}) {
this.state.model.setUniforms(uniforms);
this.state.model.draw();
}
finalizeState() {
this.state.model.delete();
}
}
Layer получает доступ к контексту:
this.context.gl
this.context.viewport
this.context.deck
При каждом кадре:
Layer можно формально описать как реактивный GPU-компонент:
Layer = f(props, state, context) → WebGL output
Где: