Настройка цветов и стилей

deck.gl предоставляет многослойную систему визуализации, где стилизация геометрии и цвета строится вокруг концепции слоёв (layers) и функций-аксессоров (accessors). Цвет и внешний вид объектов определяются не декларативными CSS-правилами, а вычисляются на уровне данных и WebGL-пайплайна, что обеспечивает высокую производительность при работе с большими наборами данных.


В большинстве слоёв используется RGBA-представление цвета:

  • формат: [R, G, B, A]
  • диапазон: чаще всего 0–255 для RGB и 0–255 или 0–255 для alpha (в зависимости от слоя и версии)
  • прозрачность управляется альфа-каналом или отдельным параметром opacity

Пример базового цвета:

const color = [30, 144, 255, 200];

Цвет может задаваться:

  • статически (фиксированное значение)
  • динамически (функция от данных)
  • через атрибуты вершин (vertex attributes)
  • через шейдеры (GLSL)

Цветовые пропсы слоёв

Каждый слой имеет набор стандартных свойств, отвечающих за визуальное представление:

getFillColor

Определяет цвет заливки объектов.

new ScatterplotLayer({
  id: 'points',
  data,
  getPosition: d => d.coordinates,
  getFillColor: [255, 0, 0, 180]
});

getLineColor

Используется для линий и контуров.

new PathLayer({
  id: 'paths',
  data,
  getPath: d => d.path,
  getLineColor: [0, 255, 0, 200],
  getWidth: 2
});

getColor (обобщённый вариант)

В некоторых слоях (например, ColumnLayer, HexagonLayer) используется единый accessor:

new ColumnLayer({
  id: 'columns',
  data,
  getPosition: d => d.position,
  getElevation: d => d.value,
  getFillColor: d => d.value > 100 ? [255, 0, 0] : [0, 0, 255]
});

Динамическая стилизация через функции-аксессоры

Ключевая особенность deck.gl — возможность вычислять цвет на основе данных.

getFillColor: d => [
  Math.min(255, d.value * 2),
  100,
  255 - d.value,
  180
]

Такой подход позволяет:

  • визуализировать интенсивность значений
  • кодировать категории цветами
  • строить градиенты без предрасчёта данных

Пример категориального окрашивания

const categoryColor = {
  A: [255, 99, 132, 200],
  B: [54, 162, 235, 200],
  C: [255, 206, 86, 200]
};

getFillColor: d => categoryColor[d.type] || [200, 200, 200, 200]

Условное окрашивание и бизнес-логика

Цвет часто используется как визуальный код состояния данных.

getFillColor: d => {
  if (d.status === 'active') return [0, 200, 0, 180];
  if (d.status === 'warning') return [255, 165, 0, 180];
  return [200, 0, 0, 180];
}

Такой подход применяется в:

  • мониторинге систем
  • геоаналитике
  • финансовых визуализациях

Интерполяция и масштабирование значений

При работе с числовыми данными часто используется нормализация.

const lerpColor = (t) => [
  255 * t,
  100,
  255 * (1 - t),
  200
];

getFillColor: d => lerpColor(d.value / maxValue)

Более сложные варианты включают:

  • логарифмическую шкалу
  • квантильное распределение
  • цветовые палитры (viridis, plasma и др.)

Прозрачность и blending

Альфа-канал определяет прозрачность и влияет на наложение объектов.

getFillColor: [0, 128, 255, 120]

Важно учитывать:

  • порядок отрисовки слоёв
  • включённый blending в WebGL контексте
  • перекрытие геометрий

Некоторые слои используют additive blending для эффектов свечения.


Настройка линий и контуров

Для линий и границ используется отдельная логика стилизации:

new GeoJsonLayer({
  id: 'geojson',
  data,
  stroked: true,
  filled: true,
  getFillColor: [100, 150, 255, 100],
  getLineColor: [0, 0, 0, 255],
  getLineWidth: 2
});

Параметры:

  • stroked — включение обводки
  • getLineWidth — толщина линии
  • getLineColor — цвет контура

Material и освещение

Некоторые слои поддерживают физически корректное освещение.

new ColumnLayer({
  id: 'columns',
  data,
  material: {
    ambient: 0.35,
    diffuse: 0.6,
    shininess: 32
  }
});

Параметры материала:

  • ambient — фоновое освещение
  • diffuse — рассеянный свет
  • specular — зеркальные блики
  • shininess — степень блика

Эта модель особенно важна для 3D-слоёв (ColumnLayer, GridLayer, TerrainLayer).


Шейдерная стилизация (GLSL уровень)

Для максимального контроля используется переопределение шейдеров:

new ScatterplotLayer({
  id: 'custom',
  data,
  getFillColor: d => d.color,
  vs: `
    attribute vec3 positions;
    attribute vec4 colors;
    varying vec4 vColor;
    void main() {
      vColor = colors;
      gl_Position = project_position_to_clipspace(positions);
    }
  `,
  fs: `
    varying vec4 vColor;
    void main() {
      gl_FragColor = vColor;
    }
  `
});

На этом уровне можно реализовать:

  • градиенты по расстоянию
  • пульсации
  • heatmap-эффекты
  • условную дискретизацию цвета

Общие стилистические паттерны

Централизованные палитры

const palette = {
  primary: [0, 120, 255, 200],
  danger: [255, 60, 60, 200],
  neutral: [180, 180, 180, 200]
};

Функции тематизации

const getThemeColor = (theme, value) => {
  return theme === 'dark'
    ? [255 - value, 255 - value, 255, 200]
    : [value, 100, 255, 200];
};

Оптимизация через updateTriggers

При динамических цветах важно контролировать пересчёт атрибутов:

new ScatterplotLayer({
  id: 'optimized',
  data,
  getFillColor: d => colorScale(d.value),
  updateTriggers: {
    getFillColor: [colorScale]
  }
});

Это предотвращает лишние перерасчёты GPU-буферов и повышает производительность.


Цветовые палитры и масштабирование восприятия

Визуализация часто требует согласованных палитр:

  • последовательные (sequential)
  • дивергентные (diverging)
  • категориальные (categorical)

Пример последовательной шкалы:

const sequential = [
  [237, 248, 251, 255],
  [179, 205, 227, 255],
  [140, 150, 198, 255],
  [136, 65, 157, 255]
];

Применение:

getFillColor: d => sequential[Math.floor(d.value * 3)]

Управление стилем на уровне слоёв

В сложных сценах стиль распределяется между слоями:

const layers = [
  new ScatterplotLayer({
    id: 'points',
    getFillColor: [255, 0, 0, 180]
  }),
  new PathLayer({
    id: 'lines',
    getLineColor: [0, 0, 0, 255]
  })
];

Так формируется многослойная визуальная композиция, где каждый слой отвечает за свой визуальный канал: цвет, глубину, прозрачность и структуру данных.