Получение информации о слое

Работа со слоями в Mapbox GL JS начинается с обращения к стилю карты, где слой существует как часть style specification. Любой слой имеет уникальный идентификатор, по которому он извлекается из текущего стиля:

const layer = map.getLayer('roads-layer');

Метод getLayer возвращает объект слоя, содержащий его тип, источник данных, фильтры, параметры отрисовки (paint) и размещения (layout). Структура соответствует спецификации Style Specification, используемой платформой Mapbox.

Слой в этом контексте не содержит геометрии напрямую — он лишь описывает способ отображения данных, поступающих из источника (source).

Ключевые свойства объекта слоя:

  • id — уникальный идентификатор
  • type — тип слоя (fill, line, symbol, circle, raster, fill-extrusion)
  • source — идентификатор источника данных
  • filter — выражение фильтрации объектов
  • layout — параметры размещения
  • paint — визуальные стили
const layer = map.getLayer('parks-layer');

console.log(layer.type);    // "fill"
console.log(layer.source);  // "parks-source"

Проверка наличия слоя в стиле

Перед выполнением операций над слоем часто требуется убедиться в его существовании:

if (map.getLayer('buildings')) {
  // слой существует
}

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


Получение данных, отображаемых слоем

Основной механизм: queryRenderedFeatures

Наиболее важный метод для получения информации о слое — queryRenderedFeatures. Он возвращает набор объектов, которые в данный момент отрисованы на экране и принадлежат указанным слоям.

const features = map.queryRenderedFeatures({
  layers: ['roads-layer']
});

Результат зависит не только от источника данных, но и от текущего состояния карты:

  • масштаб (zoom)
  • область экрана
  • фильтры слоя
  • стиль отображения
  • перекрытие другими слоями

Каждый элемент результата — GeoJSON Feature:

features.forEach(f => {
  console.log(f.id);
  console.log(f.geometry);
  console.log(f.properties);
});

Фильтрация по координате или области

Метод поддерживает пространственные ограничения.

По точке

const features = map.queryRenderedFeatures([x, y], {
  layers: ['buildings']
});

По bounding box

const features = map.queryRenderedFeatures(
  [
    [minX, minY],
    [maxX, maxY]
  ],
  {
    layers: ['parks']
  }
);

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


Получение объектов источника: querySourceFeatures

В отличие от queryRenderedFeatures, метод querySourceFeatures работает на уровне данных источника, а не рендеринга.

const features = map.querySourceFeatures('parks-source', {
  sourceLayer: 'parks'
});

Особенности:

  • возвращает данные до применения стилей
  • не учитывает текущий zoom как ограничение отображения
  • полезен для анализа полного набора данных в векторных тайлах

Этот метод критичен при работе с vector tile sources, где данные разделены на source layers.


Получение слоя и его визуальных параметров

Извлечение layout и paint

Слой хранит визуальную конфигурацию, которая может быть изменена в runtime:

const layer = map.getLayer('water');

console.log(layer.paint);
console.log(layer.layout);

Примеры свойств paint:

  • fill-color
  • line-width
  • circle-radius
  • text-color

Примеры layout:

  • visibility
  • text-field
  • symbol-placement

Динамическое изменение и последующее чтение

После изменения свойств слоя можно повторно получить обновлённый объект:

map.setPaintProperty('roads', 'line-color', '#ff0000');

const updated = map.getLayer('roads');
console.log(updated.paint['line-color']);

Важно учитывать, что getLayer возвращает текущее состояние style, а не копию исходного описания.


Работа с фильтрами слоя

Фильтр слоя определяет, какие объекты источника будут отображены.

const layer = map.getLayer('cities');
console.log(layer.filter);

Пример фильтра:

map.setFilter('cities', ['==', ['get', 'type'], 'capital']);

После изменения фильтра можно анализировать результат через повторный запрос:

const visible = map.queryRenderedFeatures({
  layers: ['cities']
});

Фильтр влияет только на отображаемые объекты, но не изменяет источник данных.


Получение информации при взаимодействии с картой

Обработка события click

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

map.on('click', 'roads-layer', (e) => {
  const features = e.features;

  features.forEach(f => {
    console.log(f.properties);
  });
});

В объекте события:

  • features — массив объектов слоя
  • lngLat — координаты клика
  • point — экранные координаты

Этот механизм оптимизирован и быстрее, чем ручной вызов queryRenderedFeatures.


Hover-интерактивность

map.on('mousemove', 'parks-layer', (e) => {
  if (e.features.length > 0) {
    const feature = e.features[0];
    console.log(feature.properties.name);
  }
});

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


Работа с состоянием объекта (feature state)

Feature State позволяет хранить динамическую информацию, связанную с объектом слоя, не изменяя сам источник данных.

Установка состояния

map.setFeatureState(
  {
    source: 'parks-source',
    id: 123
  },
  {
    hover: true
  }
);

Получение состояния

const state = map.getFeatureState({
  source: 'parks-source',
  id: 123
});

console.log(state.hover);

Применение в слоях

map.setPaintProperty('parks', 'fill-opacity', [
  'case',
  ['boolean', ['feature-state', 'hover'], false],
  0.8,
  0.3
]);

Feature state часто используется для:

  • hover-эффектов
  • выделения выбранных объектов
  • динамического обновления визуализации

Различие между rendered и source данными

Метод Уровень Учитывает стиль Учитывает zoom
queryRenderedFeatures рендеринг да да
querySourceFeatures источник нет частично

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


Работа с несколькими слоями одновременно

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

const features = map.queryRenderedFeatures({
  layers: ['roads', 'buildings', 'parks']
});

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


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

При анализе больших наборов данных важно ограничивать область поиска:

const bboxFeatures = map.queryRenderedFeatures(
  [
    [10, 10],
    [200, 200]
  ],
  {
    layers: ['buildings']
  }
);

Это снижает нагрузку по сравнению с глобальным запросом.


Особенности работы с кластеризованными источниками

При использовании кластеров GeoJSON:

map.queryRenderedFeatures({ layers: ['clusters'] });

Кластерные объекты содержат:

  • cluster: true
  • point_count

Для получения дочерних элементов используется:

map.getSource('points').getClusterLeaves(clusterId, limit, offset, callback);

Или:

map.getSource('points').getClusterExpansionZoom(clusterId, callback);

Получение информации о видимости слоя

const layer = map.getLayer('roads');

console.log(layer.layout.visibility);

Значения:

  • visible
  • none

Изменение:

map.setLayoutProperty('roads', 'visibility', 'none');

Это влияет на результат queryRenderedFeatures, так как скрытые слои не участвуют в рендере.


Комбинация запросов для анализа слоя

Комплексный анализ слоя часто включает несколько шагов:

const layerId = 'buildings';

const layer = map.getLayer(layerId);
const rendered = map.queryRenderedFeatures({
  layers: [layerId]
});
const source = map.querySourceFeatures(layer.source);

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

  • стиль слоя
  • отрисованные данные
  • исходные данные источника

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

При работе с большим количеством слоёв и частыми запросами важно учитывать:

  • queryRenderedFeatures дорог в вычислении при больших viewport
  • фильтрация по layers значительно ускоряет запрос
  • избегание глобальных запросов без bbox повышает производительность
  • кэширование результатов снижает нагрузку на UI

Использование ID слоёв как контрактной модели данных

Идентификатор слоя часто становится точкой интеграции между:

  • UI логикой
  • источниками данных
  • интерактивностью карты
const INTERACTIVE_LAYERS = [
  'roads',
  'buildings',
  'poi'
];

map.queryRenderedFeatures({
  layers: INTERACTIVE_LAYERS
});

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