Layer базовый класс

Роль Layer в архитектуре deck.gl

Layer — фундаментальная абстракция, на которой строится вся система визуализации. Любая графическая сущность в deck.gl, будь то точки, линии, полигоны или кастомные WebGL-объекты, реализуется через наследование от этого базового класса.

Ключевая идея:

Layer описывает, как данные превращаются в GPU-геометрию и как она обновляется при изменении входных параметров.

Он не выполняет непосредственный рендер в привычном смысле, а управляет состоянием WebGL-ресурсов, атрибутами и жизненным циклом отрисовки.


Основная модель Layer

Каждый слой можно рассматривать как преобразователь:

data → attributes → shaders → GPU primitives

Где:

  • data — входной набор данных (GeoJSON, массив координат, таблицы и т.д.)
  • attributes — буферы вершин и дополнительных данных
  • shaders — GLSL-программы для вершин и фрагментов
  • GPU primitives — итоговая отрисовка

Конструктор Layer и props

Каждый слой создаётся через объект свойств:

new MyLayer({
  id: 'custom-layer',
  data: [],
  opacity: 1,
  pickable: true
});

Базовые свойства (props)

  • id — уникальный идентификатор слоя
  • data — источник данных
  • visible — управляет отображением
  • opacity — прозрачность слоя
  • pickable — включение интерактивности (picking)
  • parameters — WebGL параметры (blending, depth test и др.)

Важная особенность

Props в deck.gl иммутабельны на уровне концепции. Любое изменение props приводит к сравнению (diffing) и потенциальному обновлению GPU-ресурсов.


Состояние слоя (state)

Каждый слой имеет внутреннее состояние, которое не доступно напрямую извне.

Типичный state может содержать:

  • WebGL buffers
  • compiled shaders
  • attribute managers
  • cached geometries
  • uniform values

Пример:

this.state = {
  model: null,
  attributeManager: null,
  lastDataUpdate: null
};

Жизненный цикл Layer

1. initializeState

Вызывается один раз при создании слоя.

Назначение:

  • инициализация WebGL ресурсов
  • создание AttributeManager
  • подготовка моделей
initializeState() {
  const attributeManager = this.getAttributeManager();

  attributeManager.addInstanced({
    positions: { size: 3, accessor: 'getPosition' }
  });

  this.setState({ attributeManager });
}

2. updateState

Вызывается при изменении props или состояния контекста.

Основная задача — определить, что изменилось, и обновить только необходимое.

Типичные случаи обновления:

  • изменение data
  • изменение атрибутов (getPosition, getColor)
  • изменение стиля (opacity, sizeScale)
  • изменение viewport
updateState({ props, oldProps, changeFlags }) {
  if (changeFlags.dataChanged) {
    this._updateGeometry(props.data);
  }

  if (changeFlags.updateTriggersChanged) {
    this.state.attributeManager.invalidateAll();
  }
}

3. draw

Отвечает за фактический рендер в WebGL контекст.

draw({ uniforms }) {
  this.state.model.setUniforms(uniforms);
  this.state.model.draw();
}

4. finalizeState

Освобождение ресурсов:

  • удаление буферов
  • удаление шейдеров
  • cleanup GPU памяти
finalizeState() {
  this.state.model.delete();
}

AttributeManager и работа с данными

Deck.gl использует систему атрибутов для эффективного батчинга данных в GPU.

Принцип:

Каждое поле данных превращается в buffer attribute.

Пример:

attributeManager.add({
  positions: {
    size: 3,
    accessor: 'getPosition'
  },
  colors: {
    size: 4,
    accessor: 'getColor',
    defaultValue: [255, 0, 0, 255]
  }
});

Update triggers

Позволяют контролировать пересчёт атрибутов:

updateTriggers: {
  getColor: [this.props.colorRange]
}

Если зависимости изменились — атрибуты пересчитываются.


Система diffing props

Перед вызовом updateState deck.gl выполняет сравнение props:

Категории изменений:

  • DATA_CHANGED
  • PROPS_CHANGED
  • MODEL_CHANGED
  • STATE_CHANGED
  • VIEWPORT_CHANGED

Это позволяет минимизировать WebGL перерасчёты.


Наследование Layer

Создание кастомного слоя требует расширения базового класса:

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
  }
}

Шейдерная модель Layer

Каждый слой связан с GLSL программами:

  • vertex shader
  • fragment shader

Deck.gl автоматически инжектирует:

  • projection matrix
  • model matrix
  • picking color
  • lighting uniforms

Пример структуры:

const vs = `
  attribute vec3 positions;
  void main() {
    gl_Position = project_position_to_clipspace(positions);
  }
`;

const fs = `
  void main() {
    gl_FragColor = vec4(1.0);
  }
`;

Model как связующее звено

Layer не рисует напрямую — он использует Model:

  • объединяет геометрию
  • хранит шейдеры
  • управляет draw calls
this.state.model = new Model(gl, {
  vs,
  fs,
  geometry: new CubeGeometry()
});

Picking и интерактивность

Layer поддерживает GPU picking через специальный render pass.

Механизм:

  • каждому объекту назначается picking color
  • при клике читается пиксель из framebuffer
  • color → object mapping
pickable: true

Transform и координатные системы

Layer работает в разных системах координат:

  • latitude/longitude
  • Web Mercator
  • Cartesian

Deck.gl автоматически применяет трансформации через project функции в шейдерах.


Композиция слоёв

Layer может возвращать дочерние слои:

renderLayers() {
  return [
    new ScatterplotLayer(this.props),
    new LineLayer(this.props)
  ];
}

Это позволяет строить сложные визуализации как композицию простых слоёв.


Оптимизация работы Layer

Ключевые механизмы производительности:

  • минимизация updateState
  • использование attributeManager
  • кеширование моделей
  • инвалидация по updateTriggers
  • батчинг draw calls

Типичная структура пользовательского слоя

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

Layer получает доступ к контексту:

  • WebGLRenderingContext
  • viewport (камера)
  • deck instance
  • coordinate system
  • animation loop state
this.context.gl
this.context.viewport
this.context.deck

Обновление и жизненный цикл кадра

При каждом кадре:

  1. сравнение props
  2. updateState (если нужно)
  3. пересборка атрибутов
  4. подготовка uniforms
  5. draw всех слоёв
  6. composite result

Итоговая модель поведения Layer

Layer можно формально описать как реактивный GPU-компонент:

Layer = f(props, state, context) → WebGL output

Где:

  • props определяют входные данные
  • state хранит GPU-ресурсы
  • context задаёт окружение рендера