В Mapbox GL JS концепция viewport querying строится вокруг текущего состояния камеры карты: центра, масштаба, наклона и границ видимой области. Все операции выборки геоданных выполняются относительно того, что уже отрисовано в кадре или находится в пределах текущего отображаемого экстента.
Viewport querying делится на два основных направления:
Разница между ними принципиальна: первый тип работает с тем, что реально попало в текущий рендеринг, второй — с геометрией в источнике, независимо от визуального состояния.
Основной механизм viewport querying — метод
queryRenderedFeatures. Он позволяет получать объекты,
которые уже прошли стадию рендеринга и находятся в текущем кадре.
map.queryRenderedFeatures(point?, options?)
Метод поддерживает несколько режимов вызова:
Наиболее распространённый сценарий — выбор объектов по координатам пикселя:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point);
console.log(features);
});
e.point — экранные координаты события, которые
автоматически преобразуются в пространство canvas.
Особенности поведения:
filter) влияют на результатViewport querying может быть ограничен конкретными слоями:
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer', 'roads-layer']
});
Такой подход используется для:
При наличии большого количества слоёв фильтрация по
layers критична для предотвращения избыточных
вычислений.
Viewport querying поддерживает прямоугольные области:
const bounds = [
[left, top],
[right, bottom]
];
const features = map.queryRenderedFeatures(bounds);
Применения:
Bounding box работает в пиксельных координатах текущего canvas, а не в географических координатах.
В Mapbox GL JS существует отдельный метод:
map.querySourceFeatures(sourceId, options)
Он возвращает данные напрямую из источника, минуя рендеринг.
Rendered features:
Source features:
Viewport querying тесно связан с системой координат карты:
При выполнении queryRenderedFeatures происходит
промежуточное преобразование:
Эта цепочка объясняет, почему результаты зависят от zoom уровня и угла наклона.
При использовании pitch и bearing viewport перестаёт быть строго прямоугольным в географическом смысле.
Особенности:
Это критично для:
Viewport querying часто используется для определения попадания курсора в объект.
Пример:
map.on('mousemove', (e) => {
const features = map.queryRenderedFeatures(e.point);
map.getCanvas().style.cursor =
features.length ? 'pointer' : '';
});
Алгоритм hit detection включает:
При пересечении нескольких объектов результат
queryRenderedFeatures не гарантирует единственный
элемент.
Типичные сценарии:
Решения:
layer и
sourcefilter для уточненияlayers в запросеfeature.propertiesViewport querying напрямую зависит от:
Оптимизационные техники:
map.queryRenderedFeatures(point, {
layers: ['interactive-layer']
});
let timeout;
map.on('mousemove', (e) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
map.queryRenderedFeatures(e.point);
}, 50);
});
Для point-данных кластеризация существенно снижает количество объектов в viewport.
Viewport querying учитывает выражения фильтрации слоя:
'filter': ['==', ['get', 'type'], 'park']
Это означает:
Viewport querying тесно связан с событийной моделью Mapbox GL JS.
Основные события:
Пример комбинированного сценария:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['buildings']
});
if (features.length) {
const feature = features[0];
console.log(feature.properties);
}
});
Symbol layers имеют специфическое поведение:
Viewport querying в symbol layers часто требует дополнительной логики:
symbol-sort-keytext-field над icongeometry.typeНа разных zoom уровнях viewport querying возвращает разные наборы данных:
Это связано с тем, что тайлы пересобираются динамически.
Несмотря на гибкость, существуют ограничения:
В реальных системах viewport querying часто комбинируется с source querying:
const rendered = map.queryRenderedFeatures(point, {
layers: ['places']
});
const source = map.querySourceFeatures('places-source');
Такой подход позволяет:
Mapbox GL JS использует WebGL, что означает:
Viewport querying всегда зависит от состояния камеры:
Любое изменение камеры мгновенно изменяет набор доступных результатов, поскольку пересчитывается:
Во время flyTo или easeTo:
Viewport querying может возвращать пустой массив в случаях:
visibility: none)Это состояние используется как нормальное в асинхронной модели загрузки данных Mapbox GL JS.