Data-driven styling

Визуальное оформление слоёв в Mapbox GL JS строится на модели декларативных стилей, где внешний вид объектов карты описывается через свойства слоя. Ключевым механизмом выступает data-driven styling — привязка визуальных параметров к данным источника и масштабу карты, что позволяет формировать динамическую картографическую визуализацию без ручного обновления стилей.

Стили слоя делятся на две фундаментальные группы:

  • layout properties — отвечают за геометрию и размещение (например, видимость слоя, тип символов, порядок отрисовки);
  • paint properties — определяют визуальное оформление (цвет, прозрачность, толщину линий, заливки, градиенты).

Data-driven подход применяется преимущественно к paint-свойствам, а также частично к layout-параметрам, когда требуется динамическое управление отображением.

map.addLayer({
  id: 'cities',
  type: 'circle',
  source: 'cities-source',
  paint: {
    'circle-radius': 6,
    'circle-color': '#3b82f6'
  }
});

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

Типы выражений (expressions)

Основой data-driven styling выступают выражения Mapbox Style Specification. Они позволяют вычислять значения свойств на основе входных данных.

Основные типы выражений:

  • interpolate — плавная интерполяция значений
  • step — ступенчатое изменение
  • match — сопоставление значений
  • case — условная логика
  • get — извлечение свойства фичи
  • zoom — использование масштаба карты
  • feature-state — динамическое состояние объекта

Извлечение данных через get

Данные из GeoJSON или векторных тайлов доступны через свойства feature:

'circle-color': ['get', 'category']

В данном случае цвет круга зависит от значения свойства category в каждом объекте.

Интерполяция значений

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

'circle-radius': [
  'interpolate',
  ['linear'],
  ['get', 'population'],
  1000, 4,
  100000, 10,
  1000000, 20
]

Функция задаёт зависимость радиуса круга от численности населения, обеспечивая непрерывное масштабирование символов.

Ступенчатая визуализация

step позволяет разделять диапазон значений на интервалы:

'circle-color': [
  'step',
  ['get', 'density'],
  '#fee5d9',
  50, '#fcae91',
  100, '#fb6a4a',
  200, '#cb181d'
]

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

Категориальное сопоставление

match используется для дискретных значений, когда атрибут принимает ограниченное число категорий.

'circle-color': [
  'match',
  ['get', 'type'],
  'capital', '#e11d48',
  'city', '#2563eb',
  'town', '#10b981',
  '#9ca3af'
]

Последнее значение выступает значением по умолчанию.

Условная логика

case позволяет задавать последовательность условий:

'circle-opacity': [
  'case',
  ['>', ['get', 'importance'], 80],
  1,
  ['>', ['get', 'importance'], 50],
  0.6,
  0.3
]

Каждое условие проверяется последовательно, пока не будет найдено истинное.

Зависимость от масштаба карты

Zoom-aware styling позволяет изменять внешний вид в зависимости от уровня приближения.

'circle-radius': [
  'interpolate',
  ['linear'],
  ['zoom'],
  5, 2,
  10, 6,
  15, 18
]

Такой подход применяется для регулировки читаемости объектов при разных масштабах.

Использование feature-state

feature-state обеспечивает динамическое обновление стилей без изменения исходных данных источника. Это критично для интерактивных сценариев.

map.setFeatureState(
  { source: 'cities', id: 123 },
  { selected: true }
);

Стиль слоя может реагировать на состояние:

'circle-color': [
  'case',
  ['boolean', ['feature-state', 'selected'], false],
  '#f59e0b',
  '#3b82f6'
]

Такой механизм отделяет данные от UI-состояния, снижая необходимость перерендера источника.

Комбинирование выражений

Выражения могут вкладываться друг в друга, формируя сложную логику визуализации:

'circle-radius': [
  'interpolate',
  ['linear'],
  ['zoom'],
  5,
  ['+', 2, ['/', ['get', 'value'], 50]],
  10,
  ['+', 6, ['/', ['get', 'value'], 20]]
]

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

Привязка нескольких атрибутов

Data-driven styling поддерживает использование нескольких полей одновременно:

'circle-color': [
  'rgb',
  ['get', 'r'],
  ['get', 'g'],
  ['get', 'b']
]

Цвет формируется непосредственно из данных, что исключает необходимость предрасчёта значений.

Работа с типами данных источников

Источники данных в Mapbox GL JS могут быть:

  • GeoJSON
  • vector tiles
  • raster tiles (ограниченно для стилизации)
  • image sources

Data-driven styling наиболее полно раскрывается на векторных источниках, где каждый feature содержит набор атрибутов, доступных через expressions.

map.addSource('places', {
  type: 'geojson',
  data: '/data/places.geojson'
});

Производительность выражений

Вычисление выражений происходит на уровне рендеринга, поэтому важно учитывать:

  • минимизацию вложенности выражений
  • отказ от избыточных вычислений
  • использование предрасчитанных атрибутов в источнике
  • предпочтение step над сложной интерполяцией при больших наборах данных

Каждое выражение пересчитывается при изменении состояния карты (zoom, pan, feature-state), что влияет на частоту перерисовки слоя.

Динамическая генерация стилей

Стили могут формироваться программно на основе внешних данных:

const maxValue = Math.max(...values);

const style = [
  'interpolate',
  ['linear'],
  ['get', 'value'],
  0, '#f0f9ff',
  maxValue, '#075985'
];

map.setPaintProperty('layer-id', 'fill-color', style);

Такой подход позволяет связывать визуализацию с аналитическими вычислениями вне карты.

Многоуровневая визуализация

Data-driven styling часто применяется для построения тематических карт с несколькими слоями:

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

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