Работа со слоями в 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. Он возвращает набор объектов,
которые в данный момент отрисованы на экране и принадлежат указанным
слоям.
const features = map.queryRenderedFeatures({
layers: ['roads-layer']
});
Результат зависит не только от источника данных, но и от текущего состояния карты:
Каждый элемент результата — 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']
});
const features = map.queryRenderedFeatures(
[
[minX, minY],
[maxX, maxY]
],
{
layers: ['parks']
}
);
Это используется для анализа содержимого слоя в конкретной области без перебора всего источника.
В отличие от queryRenderedFeatures, метод
querySourceFeatures работает на уровне данных источника, а
не рендеринга.
const features = map.querySourceFeatures('parks-source', {
sourceLayer: 'parks'
});
Особенности:
Этот метод критичен при работе с vector tile sources, где данные разделены на source layers.
Слой хранит визуальную конфигурацию, которая может быть изменена в runtime:
const layer = map.getLayer('water');
console.log(layer.paint);
console.log(layer.layout);
Примеры свойств paint:
fill-colorline-widthcircle-radiustext-colorПримеры layout:
visibilitytext-fieldsymbol-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']
});
Фильтр влияет только на отображаемые объекты, но не изменяет источник данных.
Один из наиболее частых способов получения информации о слое — обработка событий карты.
map.on('click', 'roads-layer', (e) => {
const features = e.features;
features.forEach(f => {
console.log(f.properties);
});
});
В объекте события:
features — массив объектов слояlngLat — координаты кликаpoint — экранные координатыЭтот механизм оптимизирован и быстрее, чем ручной вызов
queryRenderedFeatures.
map.on('mousemove', 'parks-layer', (e) => {
if (e.features.length > 0) {
const feature = e.features[0];
console.log(feature.properties.name);
}
});
Такой подход используется для подсветки объектов или отображения всплывающих подсказок.
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 часто используется для:
| Метод | Уровень | Учитывает стиль | Учитывает zoom |
|---|---|---|---|
| queryRenderedFeatures | рендеринг | да | да |
| querySourceFeatures | источник | нет | частично |
queryRenderedFeatures показывает то, что реально видно
пользователю. querySourceFeatures показывает данные слоя
без визуальных ограничений.
Методы позволяют получать данные сразу из набора слоёв:
const features = map.queryRenderedFeatures({
layers: ['roads', 'buildings', 'parks']
});
Порядок слоёв влияет на результат при наложении объектов, но не на сам факт их попадания в выборку.
При анализе больших наборов данных важно ограничивать область поиска:
const bboxFeatures = map.queryRenderedFeatures(
[
[10, 10],
[200, 200]
],
{
layers: ['buildings']
}
);
Это снижает нагрузку по сравнению с глобальным запросом.
При использовании кластеров GeoJSON:
map.queryRenderedFeatures({ layers: ['clusters'] });
Кластерные объекты содержат:
cluster: truepoint_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);
Значения:
visiblenoneИзменение:
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Идентификатор слоя часто становится точкой интеграции между:
const INTERACTIVE_LAYERS = [
'roads',
'buildings',
'poi'
];
map.queryRenderedFeatures({
layers: INTERACTIVE_LAYERS
});
Такой подход упрощает масштабирование интерфейса карты без изменения логики запросов к данным.