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

Стилизация в Deck.gl определяет визуальное представление геоданных на карте. Цвета, размеры, прозрачность, форма объектов, контуры, высота экструзии и анимация формируют восприятие пространственной информации и позволяют акцентировать внимание на наиболее важных характеристиках набора данных.

Архитектура библиотеки построена таким образом, что практически любой визуальный параметр слоя может быть настроен через специальные свойства (accessors), вычисляемые для каждого объекта данных отдельно. Благодаря этому карта может динамически менять внешний вид в зависимости от атрибутов данных, масштаба карты, состояния взаимодействия пользователя и внешних событий.


Основные принципы стилизации

Каждый слой Deck.gl содержит набор параметров отображения. Часть параметров задаётся фиксированными значениями:

new ScatterplotLayer({
  id: 'points',
  data,
  getFillColor: [255, 0, 0],
  getRadius: 100
})

В этом случае все объекты получают одинаковый цвет и размер.

Другой подход предполагает вычисление стиля для каждого элемента:

new ScatterplotLayer({
  id: 'points',
  data,
  getFillColor: d => d.color,
  getRadius: d => d.population
})

Здесь визуальные характеристики определяются содержимым объекта данных.

Такой механизм называется data-driven styling — стилизация на основе данных.


Цветовые модели в Deck.gl

Большинство слоёв используют цвет в формате массива:

[r, g, b]

или

[r, g, b, a]

где:

Компонент Диапазон
Red 0–255
Green 0–255
Blue 0–255
Alpha 0–255

Пример:

[255, 100, 50]

Оранжевый цвет.

Полупрозрачный вариант:

[255, 100, 50, 120]

Чем меньше значение Alpha, тем прозрачнее объект.


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

Во многих слоях применяется свойство:

getFillColor

Например:

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

Все точки будут окрашены в синий цвет.

Динамическое вычисление:

getFillColor: d => {
  if (d.population > 1000000) {
    return [255, 0, 0];
  }

  return [0, 180, 0];
}

Крупные города отображаются красным цветом, остальные — зелёным.


Градиентная раскраска данных

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

Пример:

getFillColor: d => {
  const value = d.temperature;

  return [
    value * 2,
    50,
    255 - value * 2
  ];
}

Рост температуры изменяет цвет объекта от синего к красному.

Для более качественного отображения часто используются шкалы из библиотек D3:

import {scaleSequential} from 'd3-scale';
import {interpolateTurbo} from 'd3-scale-chromatic';

const colorScale = scaleSequential(interpolateTurbo)
  .domain([0, 100]);

Использование:

getFillColor: d => {
  const color = colorScale(d.value);

  return [
    color.r,
    color.g,
    color.b
  ];
}

Такой подход позволяет создавать профессиональные картографические палитры.


Настройка цвета границы

Для объектов с контурами применяется свойство:

getLineColor

Пример:

new PolygonLayer({
  id: 'regions',
  data,
  stroked: true,
  filled: true,
  getLineColor: [0, 0, 0]
})

Контур полигона будет чёрным.

Динамическая настройка:

getLineColor: d =>
  d.selected
    ? [255, 0, 0]
    : [80, 80, 80]

Выбранные объекты выделяются красным цветом.


Толщина линий

Для линий и контуров используется:

getLineWidth

Пример:

new PathLayer({
  id: 'roads',
  data,
  getPath: d => d.path,
  getLineWidth: 5
})

Динамическая толщина:

getLineWidth: d => d.trafficLevel

Ширина дороги зависит от интенсивности движения.

Чтобы толщина не зависела от масштаба карты:

widthUnits: 'meters'

или

widthUnits: 'pixels'

Основные единицы измерения

Значение Описание
pixels Экранные пиксели
meters Реальные метры
common Внутренние координаты Deck.gl

Настройка размеров объектов

Для точечных слоёв используется:

getRadius

Пример:

new ScatterplotLayer({
  data,
  getRadius: 500
})

Размер определяется в метрах.

Динамическая настройка:

getRadius: d => d.population / 100

Большие города получают более крупные маркеры.

Для ограничения размеров применяются:

radiusMinPixels

и

radiusMaxPixels

Пример:

radiusMinPixels: 2,
radiusMaxPixels: 50

Даже при сильном изменении масштаба объекты остаются читаемыми.


Использование прозрачности

Прозрачность помогает отображать плотные наборы данных без визуальной перегрузки.

Пример:

getFillColor: [0, 128, 255, 80]

Или динамически:

getFillColor: d => [
  0,
  128,
  255,
  d.opacity
]

Прозрачность особенно полезна для:

  • тепловых карт;
  • кластеров;
  • плотных наборов точек;
  • визуализации пересечений объектов.

Стилизация PolygonLayer

PolygonLayer предоставляет большое количество параметров оформления.

Базовый пример:

new PolygonLayer({
  id: 'districts',
  data,
  getPolygon: d => d.geometry,
  filled: true,
  stroked: true,
  getFillColor: [50, 150, 255],
  getLineColor: [0, 0, 0],
  getLineWidth: 2
})

Основные свойства:

Свойство Назначение
filled Отрисовка заливки
stroked Отрисовка контура
extruded Включение 3D-экструзии
wireframe Каркасное отображение
getElevation Высота объекта

Трёхмерная стилизация

Одним из преимуществ Deck.gl является работа с WebGL и поддержка объёмных объектов.

Пример:

new PolygonLayer({
  data,
  extruded: true,
  getElevation: d => d.population
})

Высота полигона определяется населением.

Одновременно можно использовать цветовую кодировку:

getFillColor: d => {
  const value = d.population;

  return [
    value / 1000,
    100,
    255 - value / 1000
  ];
}

Высота и цвет начинают отражать один и тот же показатель разными визуальными средствами.


Освещение трёхмерных объектов

Для экструзии важную роль играет освещение.

Deck.gl поддерживает:

  • направленный свет;
  • точечный свет;
  • солнечный свет;
  • систему теней.

Пример создания набора источников света:

import {
  AmbientLight,
  DirectionalLight,
  LightingEffect
} from '@deck.gl/core';

const ambientLight = new AmbientLight({
  intensity: 1.0
});

const directionalLight = new DirectionalLight({
  direction: [-1, -3, -1],
  intensity: 1.5
});

const lightingEffect = new LightingEffect({
  ambientLight,
  directionalLight
});

Подключение:

new Deck({
  effects: [lightingEffect]
});

Грамотно настроенное освещение значительно улучшает читаемость объёмных карт.


Подсветка объектов при наведении

Deck.gl поддерживает интерактивное изменение стиля.

Активация:

pickable: true

Обработчик:

onHover: info => {
  console.log(info.object);
}

Изменение цвета:

getFillColor: d =>
  d.id === hoveredId
    ? [255, 0, 0]
    : [0, 128, 255]

Такой подход используется для:

  • отображения выбранного объекта;
  • подсветки районов;
  • интерактивных аналитических панелей;
  • картографических дашбордов.

Автоматическое обновление стилей

Deck.gl оптимизирует рендеринг и не пересчитывает стили без необходимости.

Если стиль зависит от внешней переменной:

let selectedCategory;

Следует использовать:

updateTriggers: {
  getFillColor: [selectedCategory]
}

Пример:

new ScatterplotLayer({
  data,
  getFillColor: d =>
    d.category === selectedCategory
      ? [255, 0, 0]
      : [0, 128, 255],

  updateTriggers: {
    getFillColor: [selectedCategory]
  }
})

Без updateTriggers слой может не обновить отображение.


Цветовые схемы для тематических карт

Наиболее распространённые подходы:

Категориальная раскраска

const colors = {
  city: [0, 120, 255],
  village: [0, 180, 0],
  industrial: [255, 120, 0]
};

Использование:

getFillColor: d => colors[d.type]

Подходит для дискретных значений.


Последовательная шкала

0 → светлый цвет
100 → тёмный цвет

Используется для:

  • температуры;
  • населения;
  • плотности;
  • уровня загрязнения.

Дивергентная шкала

Пример:

Синий ← 0 → Красный

Подходит для отображения отклонений от среднего значения.

Примеры:

  • изменение температуры;
  • экономический рост и падение;
  • разница между планом и фактом.

Стилизация ArcLayer

ArcLayer применяется для отображения связей между точками.

Пример:

new ArcLayer({
  id: 'flights',
  data,

  getSourcePosition: d => d.from,
  getTargetPosition: d => d.to,

  getSourceColor: [0, 128, 255],
  getTargetColor: [255, 0, 0]
})

Динамический стиль:

getWidth: d => d.passengers / 1000

Толщина дуги отражает объём перевозок.


Стилизация PathLayer

Для отображения маршрутов используются свойства:

getColor

и

getWidth

Пример:

new PathLayer({
  data,
  getPath: d => d.path,
  getColor: [255, 0, 0],
  getWidth: 5
})

Цвет может зависеть от типа маршрута:

getColor: d => {
  switch (d.type) {
    case 'highway':
      return [255, 0, 0];

    case 'street':
      return [255, 255, 0];

    default:
      return [180, 180, 180];
  }
}

Использование анимации в стилях

Некоторые визуальные параметры можно изменять во времени.

Пример:

getRadius: d =>
  d.baseRadius + animationValue

Где:

animationValue = Math.sin(time) * 100;

Создаётся эффект пульсации маркеров.

Анимация применяется для:

  • отслеживания событий в реальном времени;
  • отображения перемещения объектов;
  • выделения важных элементов интерфейса;
  • демонстрации потоков данных.

Практические рекомендации по оформлению карт

Ограничение количества цветов

На одной карте рекомендуется использовать не более 5–7 основных цветов. Избыточное количество оттенков затрудняет восприятие данных.

Использование прозрачности вместо яркости

Для отображения плотности объектов часто эффективнее снижать непрозрачность, чем увеличивать насыщенность цвета.

Согласованность цветовых схем

Если красный цвет обозначает высокий риск, такое значение должно сохраняться во всех слоях карты.

Контрастность

Светлые данные лучше отображаются на тёмной подложке, а тёмные — на светлой. Недостаточный контраст существенно ухудшает читаемость.

Масштабируемость

Размеры объектов должны оставаться различимыми на разных уровнях приближения. Для этого используются ограничения через radiusMinPixels, radiusMaxPixels, widthMinPixels и widthMaxPixels.

Минимизация визуального шума

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