Фильтрация слоев в MapLibre GL JS представляет собой механизм
управления видимостью и отображением географических объектов на основе
их свойств. Она реализуется через filter слоя и позволяет
динамически ограничивать набор отображаемых фич без необходимости
пересоздания источника данных или слоя.
Фильтрация выполняется на уровне слоя и применяется к каждому объекту (feature) источника данных перед рендерингом.
Каждый слой в стиле MapLibre может содержать свойство:
filter: ["==", "property_name", "value"]
Фильтр задаётся в виде выражения (expression), представляющего дерево логических и сравнительных операций.
Пример слоя с фильтром:
map.addLayer({
id: "cities",
type: "circle",
source: "places",
"source-layer": "city_points",
filter: ["==", ["get", "type"], "city"],
paint: {
"circle-radius": 6,
"circle-color": "#ff5722"
}
});
В данном случае будут отображены только те объекты, у которых
свойство type равно "city".
Основной способ динамической фильтрации — метод:
map.setFilter(layerId, filterExpression);
map.setFilter("cities", ["==", ["get", "country"], "Kazakhstan"]);
Фильтр применяется мгновенно, без перезагрузки источника данных.
Сброс фильтра:
map.setFilter("cities", null);
Фильтры в MapLibre GL JS основаны на JSON-выражениях. Это стековая система операторов.
["==", ["get", "population"], 100000]
["!=", ["get", "status"], "inactive"]
[">", ["get", "population"], 500000]
["<=", ["get", "rank"], 10]
["all",
["==", ["get", "type"], "city"],
[">", ["get", "population"], 100000]
]
["any",
["==", ["get", "type"], "city"],
["==", ["get", "type"], "town"]
]
["!", ["==", ["get", "status"], "inactive"]]
Проверяет наличие свойства:
["has", "name"]
["!has", "population"]
Позволяет проверять вхождение значения в список:
["in", ["get", "type"], "city", "town", "village"]
Этот вариант часто используется вместо длинных цепочек
any.
Фильтрация по диапазону значений:
["all",
[">=", ["get", "population"], 100000],
["<", ["get", "population"], 1000000]
]
Такой подход применяется для сегментации данных по классам величин.
Если источник содержит разные типы геометрии, можно использовать
фильтрацию по geometry-type:
["==", ["geometry-type"], "Point"]
Допустимые значения:
Реальные задачи требуют сочетания условий.
Отображение крупных городов определённого типа:
["all",
["==", ["get", "type"], "city"],
[">", ["get", "population"], 500000],
["in", ["get", "region"], "south", "east"]
]
Фильтры часто изменяются в ответ на пользовательский интерфейс.
function filterByCategory(category) {
if (category === "all") {
map.setFilter("places", null);
return;
}
map.setFilter("places", ["==", ["get", "category"], category]);
}
В некоторых случаях данные уже представлены массивами:
["in", "landuse", ["get", "tags"]]
Однако MapLibre не всегда поддерживает глубокие операции с массивами в фильтрах напрямую, поэтому часто используется нормализация данных на этапе подготовки GeoJSON или vector tiles.
Фильтрация выполняется на этапе рендеринга слоя. Основные особенности:
Оптимизация достигается за счёт:
Хотя это не часть filter, часто используется
совместно:
map.addLayer({
id: "labels",
type: "symbol",
source: "places",
minzoom: 10,
maxzoom: 16,
filter: ["==", ["get", "type"], "city"]
});
minzoom и maxzoom ограничивают видимость
слоя по масштабу, тогда как filter ограничивает по
данным.
MapLibre автоматически пересчитывает отображение при вызове
setFilter.
Внутренне происходит:
Важно, что источник данных остаётся неизменным.
MapLibre позволяет использовать арифметические и строковые операции.
["<", ["length", ["get", "name"]], 10]
["==", ["slice", ["get", "name"], 0, 3], "Alm"]
Часто данные содержат числовые коды категорий:
["in", ["get", "class"], 1, 2, 3]
Такой подход используется в тайловых наборах типа OpenStreetMap-derived vector tiles.
Один источник может иметь несколько слоёв с разными фильтрами:
map.addLayer({
id: "cities-large",
type: "circle",
source: "places",
filter: [">", ["get", "population"], 1000000]
});
map.addLayer({
id: "cities-small",
type: "circle",
source: "places",
filter: ["<=", ["get", "population"], 1000000]
});
Это позволяет разделять визуальные стили без дублирования данных.
map.setFilter("cities", null);
После этого слой начинает отображать все объекты источника без ограничений.
["==", ["get", "population"], "100000"] // строка вместо числа
Фильтр не сработает корректно, если типы не совпадают.
["==", ["get", "populaton"], 1000]
Ошибки в названии свойства приводят к пустому результату.
Глубокая вложенность:
["all",
["any",
["all", ...],
["all", ...]
]
]
Такие конструкции снижают читаемость и усложняют отладку.
Фильтры рекомендуется строить по принципу:
Пример структурированного фильтра:
["all",
["==", ["get", "type"], "poi"],
[">=", ["get", "rating"], 4],
["in", ["get", "category"], "restaurant", "cafe"]
]
Фильтры часто обновляются в ответ на:
Пример объединения условий:
function updateFilter(type, minPop) {
map.setFilter("cities", [
"all",
["==", ["get", "type"], type],
[">=", ["get", "population"], minPop]
]);
}
Фильтры в MapLibre GL JS часто становятся основой архитектуры:
Такой подход уменьшает количество источников данных и упрощает управление картой.