В архитектуре MapLibre GL JS работа с результатами запросов основана на взаимодействии с отрисованными в данный момент векторными тайлами, источниками данных и серверными API. Запросы могут возвращать как уже загруженные на клиент данные, так и результаты внешних сервисов, интегрированных в приложение. Основные механизмы включают выбор объектов на карте, фильтрацию геометрий, обращение к источникам данных и обработку асинхронных ответов.
Одним из ключевых инструментов является метод получения объектов, попадающих в заданную область экрана. Это позволяет работать с интерактивностью без обращения к серверу.
Основной метод:
map.queryRenderedFeatures(bbox, options);
const features = map.queryRenderedFeatures(
[
[xMin, yMin],
[xMax, yMax]
],
{
layers: ['cities-layer']
}
);
Каждый элемент результата содержит:
geometry — геометрия объекта;properties — атрибуты из исходного источника;layer — слой, на котором объект отрисован;source — идентификатор источника данных;state — динамическое состояние фичи (если используется
feature-state).В отличие от queryRenderedFeatures, метод
querySourceFeatures работает напрямую с данными источника,
независимо от того, отрисованы они или нет.
map.querySourceFeatures('earthquakes', {
sourceLayer: 'points',
filter: ['>', ['get', 'mag'], 5]
});
Система выражений позволяет ограничивать набор возвращаемых данных с использованием декларативных правил.
const features = map.queryRenderedFeatures({
layers: ['restaurants'],
filter: ['==', ['get', 'type'], 'fastfood']
});
Фильтры поддерживают:
all, any,
none);==, !=, >,
<, >=, <=);Частый сценарий работы с результатами запросов связан с обработкой событий интерфейса. При клике на карту выполняется запрос к отрисованным объектам в точке события.
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['buildings']
});
if (features.length) {
const feature = features[0];
console.log(feature.properties);
}
});
layer или
дополнительным атрибутам.При запросах к нескольким слоям результат формируется как единый массив, в котором объекты могут принадлежать разным источникам.
map.queryRenderedFeatures(e.point, {
layers: ['parks', 'water', 'roads']
});
Для повышения точности интерактивности часто используется расширение области запроса вокруг точки события.
const buffer = 5;
const features = map.queryRenderedFeatures([
[e.point.x - buffer, e.point.y - buffer],
[e.point.x + buffer, e.point.y + buffer]
]);
При использовании кластеризации результаты запросов требуют дополнительной обработки, так как возвращаемые объекты могут представлять собой агрегаты.
map.queryRenderedFeatures(e.point, {
layers: ['clusters']
});
cluster: true — признак кластера;point_count — количество объектов внутри;cluster_id — идентификатор для раскрытия;map.getSource('points').getClusterExpansionZoom(clusterId, (err, zoom) => {
map.easeTo({
center: cluster.geometry.coordinates,
zoom
});
});
Помимо локальных данных, результаты запросов часто приходят из внешних API, например геокодеров или сервисов поиска.
fetch('https://api.example.com/geocode?q=Berlin')
.then(response => response.json())
.then(data => {
console.log(data.features);
});
setData;map.getSource('search-results').setData(geojson);
При динамическом обновлении данных важно учитывать жизненный цикл источников.
Изменения данных не всегда мгновенно отражаются в
queryRenderedFeatures, так как обновление зависит от
рендера WebGL-контекста.
При обработке пересекающихся объектов важно учитывать порядок их определения.
Факторы приоритета:
Состояние объекта позволяет динамически изменять его отображение и учитывать это при запросах.
map.setFeatureState(
{
source: 'cities',
id: 123
},
{
selected: true
}
);
Запрос:
map.queryRenderedFeatures({
layers: ['cities'],
filter: ['==', ['feature-state', 'selected'], true]
});
Запросы к результатам напрямую зависят от объёма данных и сложности сцены.
Факторы влияния:
Оптимизация достигается через:
В реальных сценариях часто комбинируются разные источники результатов:
queryRenderedFeatures для интерактивности;querySourceFeatures для аналитики;Объединённые данные приводятся к единому формату GeoJSON FeatureCollection:
const combined = {
type: 'FeatureCollection',
features: [
...renderedFeatures,
...sourceFeatures,
...apiFeatures
]
};
Пустые выборки являются нормальным состоянием при работе с динамическими данными.
Причины:
Корректная обработка включает проверку длины массива и учёт асинхронных состояний источников.
if (!features.length) {
return;
}
Полученные данные часто требуют преобразования перед повторным отображением.
Типичные операции:
const geojson = {
type: 'FeatureCollection',
features: features.map(f => ({
type: 'Feature',
geometry: f.geometry,
properties: {
name: f.properties.name,
category: f.properties.type
}
}))
};
Результаты запросов могут становиться источником для динамически создаваемых слоёв.
map.addSource('dynamic', {
type: 'geojson',
data: geojson
});
map.addLayer({
id: 'dynamic-layer',
type: 'circle',
source: 'dynamic'
});
Такой подход позволяет строить интерактивные интерфейсы, основанные на выборе и фильтрации данных в реальном времени.