Фильтрация по свойствам

В Mapbox GL JS фильтрация объектов реализуется на уровне слоёв и основана на выражениях (filter expressions), которые вычисляются для каждого фиче-объекта источника данных. Фильтр определяет, будет ли объект отображён в конкретном слое в зависимости от его свойств, геометрии и контекста отображения.

Фильтрация задаётся через свойство filter в описании слоя и поддерживается как в стиле при инициализации карты, так и динамически через метод setFilter.

Базовая структура фильтра:

{
  id: 'cities-layer',
  type: 'circle',
  source: 'cities',
  'source-layer': 'cities-data',
  filter: ['==', ['get', 'type'], 'capital']
}

Здесь выражение означает: отображать только те объекты, у которых свойство type равно capital.


Доступ к свойствам объектов

Для работы с атрибутами feature используется оператор get:

['get', 'property_name']

Пример фильтрации по числовому свойству:

filter: ['>', ['get', 'population'], 1000000]

Такой фильтр пропускает только объекты с населением больше миллиона.

Свойства могут быть строковыми, числовыми, булевыми и использоваться в логических выражениях без предварительного преобразования.


Операторы сравнения

Поддерживается набор базовых операторов сравнения:

Равенство и неравенство

['==', ['get', 'category'], 'park']
['!=', ['get', 'status'], 'closed']

Сравнение чисел

['>', ['get', 'rating'], 4.5]
['>=', ['get', 'area'], 50]
['<', ['get', 'depth'], 100]
['<=', ['get', 'level'], 10]

Эти выражения вычисляются для каждого объекта независимо.


Логические операторы

Фильтрация может включать сложные условия через логические операторы.

AND

filter: [
  'all',
  ['==', ['get', 'type'], 'restaurant'],
  ['>', ['get', 'rating'], 4]
]

Объект проходит фильтр только при выполнении всех условий.

OR

filter: [
  'any',
  ['==', ['get', 'type'], 'cafe'],
  ['==', ['get', 'type'], 'bar']
]

NOT

filter: [
  '!',
  ['==', ['get', 'status'], 'inactive']
]

Проверка наличия значений

Для работы с неполными данными используется оператор has:

filter: ['has', 'name']

Противоположная проверка:

filter: ['!has', 'temporary']

Это важно при работе с источниками, где часть атрибутов может отсутствовать.


Работа с массивами значений

Если свойство содержит массив, используется оператор in:

filter: [
  'in',
  'category',
  'park',
  'forest',
  'reserve'
]

Также можно проверять наличие значения внутри массива:

filter: ['in', 'tag', ['get', 'tags']]

Условные выражения

Для сложной логики используется case:

filter: [
  'case',
  ['>', ['get', 'population'], 1000000],
  true,
  false
]

В фильтрах это используется реже, но позволяет формировать вычисляемые условия.


Фильтрация по типу геометрии

Фильтрация может учитывать тип объекта:

filter: ['==', ['geometry-type'], 'Point']

Поддерживаются значения:

  • Point
  • LineString
  • Polygon

Пример исключения полигонов:

filter: ['!=', ['geometry-type'], 'Polygon']

Комбинированные фильтры

Реальные сценарии часто используют вложенные выражения:

filter: [
  'all',
  ['==', ['get', 'type'], 'restaurant'],
  ['any',
    ['>', ['get', 'rating'], 4.5],
    ['==', ['get', 'featured'], true]
  ],
  ['!', ['==', ['get', 'status'], 'closed']]
]

Такая конструкция реализует многокритериальный отбор объектов.


Динамическое изменение фильтра

Mapbox GL JS позволяет изменять фильтры после инициализации карты без пересоздания слоя.

Метод:

map.setFilter('cities-layer', ['>', ['get', 'population'], 500000]);

Удаление фильтра:

map.setFilter('cities-layer', null);

Это приводит к отображению всех объектов слоя без ограничений.


Сочетание фильтрации и стилей

Фильтрация тесно связана с визуальным представлением данных. Часто фильтр используется вместе с paint и layout свойствами:

{
  id: 'parks',
  type: 'fill',
  source: 'landuse',
  filter: ['==', ['get', 'class'], 'park'],
  paint: {
    'fill-color': '#2ecc71',
    'fill-opacity': 0.6
  }
}

Здесь фильтр выделяет только парки, а стиль определяет их визуализацию.


Производительность фильтрации

Фильтры вычисляются на уровне рендеринга WebGL и оптимизируются движком. Однако сложные вложенные выражения с множеством логических операторов могут влиять на производительность при большом количестве объектов.

Наиболее эффективны:

  • простые сравнения ==, >, <
  • фильтры по индексируемым свойствам
  • минимальное количество вложенных any/all

Менее эффективны:

  • глубокие вложенные case
  • частые изменения фильтра на больших слоях

Использование фильтрации с источниками vector tiles

При работе с vector tiles фильтрация выполняется после загрузки тайлов, но до рендеринга слоя. Это позволяет уменьшить количество отрисовываемых объектов без изменения исходного набора данных.

{
  id: 'buildings',
  type: 'fill-extrusion',
  source: 'composite',
  'source-layer': 'building',
  filter: ['>=', ['get', 'height'], 20]
}

Фильтрация и интерактивность

Фильтры часто изменяются в ответ на действия интерфейса:

map.on('click', (e) => {
  const category = e.features[0].properties.category;

  map.setFilter('highlight-layer', [
    '==',
    ['get', 'category'],
    category
  ]);
});

Таким образом создаются сценарии динамического выделения объектов по их свойствам.


Ограничения выражений фильтрации

Система фильтров в Mapbox GL JS имеет ряд ограничений:

  • нельзя выполнять произвольный JavaScript внутри фильтра
  • отсутствует доступ к внешним данным в момент вычисления
  • выражения должны быть декларативными
  • вычисления происходят на стороне рендера, а не приложения

Эти ограничения обеспечивают предсказуемость и высокую производительность отображения картографических данных.