queryRenderedFeatures — ключевой метод в Mapbox GL JS, предназначенный для извлечения объектов, уже отрисованных на карте в текущем viewport. Он работает не с исходными данными источников, а с тем, что фактически попало в сцену рендеринга WebGL, что делает его основным инструментом для интерактивных сценариев: клики по карте, подсветка объектов, выбор геометрии, анализ видимой области и построение пользовательских взаимодействий поверх слоёв.
Метод map.queryRenderedFeatures() возвращает массив
GeoJSON-подобных объектов, которые соответствуют визуально отображённым
элементам карты в момент вызова. Это означает:
Ключевое отличие от querySourceFeatures заключается в
том, что последний работает с исходными данными источника, а
queryRenderedFeatures — с результатом рендеринга.
Это делает метод особенно полезным для задач, где важна визуальная реальность, а не полный набор данных.
map.queryRenderedFeatures(geometry?, options?)
geometry (optional) Ограничивает область поиска:
{ x, y }[[x1, y1], [x2, y2]]Если не указан, поиск выполняется по всему viewport.
options (object)
Основные поля:
layers — массив ID слоёв, в которых искатьfilter — выражение фильтрации по свойствам featureПример:
map.queryRenderedFeatures(point, {
layers: ['cities-layer'],
filter: ['==', ['get', 'type'], 'capital']
});
Используется при клике или наведении:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point);
console.log(features);
});
e.point содержит координаты пикселя относительно
canvas.
Позволяет выделять объекты в прямоугольной зоне:
const features = map.queryRenderedFeatures([
[100, 100],
[300, 300]
]);
Этот режим часто используется для drag-selection интерфейсов.
Фильтрация по слоям критически важна для производительности и предсказуемости результата.
map.queryRenderedFeatures(point, {
layers: ['roads', 'buildings']
});
Если слои не указаны:
Фильтры используют expression-синтаксис Mapbox GL JS:
map.queryRenderedFeatures(point, {
filter: ['>=', ['get', 'population'], 1000000]
});
Поддерживаются:
==, !=,
>, <, all,
any)['get', 'property']Фильтрация выполняется после рендеринга, но до возврата результата API.
Каждый feature имеет структуру GeoJSON:
{
type: "Feature",
geometry: { ... },
properties: { ... },
layer: {
id: "layer-name",
type: "fill"
},
source: "source-id",
sourceLayer: "source-layer-name"
}
Особое внимание:
layer — информация о визуальном слое, где объект
отрисованsourceLayer — актуально для vector tilesproperties — свойства из исходных данныхПри пересечении нескольких слоёв результат может содержать несколько features из одной точки.
Порядок зависит от:
Для контроля можно ограничить список layers:
map.queryRenderedFeatures(point, {
layers: ['top-layer']
});
Наиболее частый сценарий — обработка кликов:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['parcels']
});
if (features.length) {
const feature = features[0];
console.log(feature.properties);
}
});
Также применяется в:
mousemove (hover эффекты)touchstart (мобильные интерфейсы)Для подсветки объектов при наведении:
map.on('mousemove', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['buildings']
});
map.getCanvas().style.cursor = features.length ? 'pointer' : '';
});
Расширенный вариант — динамическое изменение стиля:
map.setFilter('highlight-layer', [
'in',
'id',
...features.map(f => f.id)
]);
queryRenderedFeatures может быть дорогим при частых вызовах.
1. Ограничение layers
layers: ['relevant-layer']
2. Минимизация частоты вызова
3. Уменьшение области поиска
4. Избегать сложных filter expressions
| Метод | Работает с | Учитывает стиль | Видимость |
|---|---|---|---|
| queryRenderedFeatures | отрисованные объекты | да | только видимые |
| querySourceFeatures | исходные данные | нет | все |
queryRenderedFeatures используется для UI-интеракций, querySourceFeatures — для анализа данных.
Для слоёв типа symbol запрос может возвращать:
Однако важно учитывать, что:
Если несколько features пересекаются:
1. Отсутствие layers Приводит к шумным результатам.
2. Использование вне события Без контекста координат результат бессмысленен.
3. Ожидание source данных Метод возвращает только рендер, а не полный dataset.
4. Игнорирование zoom На разных zoom уровни видимость объектов различается.
const selected = map.queryRenderedFeatures(e.point, {
layers: ['zones']
});
map.on('click', (e) => {
const f = map.queryRenderedFeatures(e.point)[0];
showPopup(f.properties);
});
const features = map.queryRenderedFeatures();
const total = features.length;
map.queryRenderedFeatures(bbox, {
layers: ['parcels']
});
Во время:
результаты могут меняться между кадрами, так как рендер обновляется непрерывно.
Поскольку Mapbox GL JS использует WebGL:
Это объясняет высокую скорость операции при малых областях и деградацию при больших выборках.
При работе с cluster layers результат может содержать:
map.queryRenderedFeatures(point, {
layers: ['clusters']
});
Дальнейшая логика часто требует:
map.getSource('points').getClusterExpansionZoom(clusterId);
Типичный паттерн:
map.on('click', (e) => {
const f = map.queryRenderedFeatures(e.point, {
layers: ['regions']
})[0];
if (!f) return;
map.setFeatureState(
{ source: 'regions', id: f.id },
{ selected: true }
);
});
Эти ограничения определяют его позицию как UI-метода, а не аналитического API.