Видимость слоев

В MapLibre GL JS управление отображением слоёв строится вокруг свойства layout.visibility, которое определяет, участвует ли слой в рендеринге сцены. Это базовый механизм, через который реализуются переключатели карт, тематические режимы отображения, фильтрация визуальных уровней и динамическая настройка интерфейса карты.

Слой в MapLibre GL JS представляет собой декларативное описание того, как геоданные из источника должны быть визуализированы. Видимость слоя — это не удаление данных и не отключение источника, а лишь управление участием слоя в отрисовке кадра.

Базовое свойство visibility

Каждый слой в стиле может содержать блок layout, внутри которого задаётся параметр:

  • visibility: "visible" — слой отображается и участвует в рендеринге
  • visibility: "none" — слой полностью исключается из отрисовки
{
  id: "roads",
  type: "line",
  source: "vector-source",
  "source-layer": "transportation",
  layout: {
    visibility: "visible"
  },
  paint: {
    "line-color": "#888",
    "line-width": 2
  }
}

Отключение слоя:

map.setLayoutProperty("roads", "visibility", "none");

Включение слоя:

map.setLayoutProperty("roads", "visibility", "visible");

Этот механизм работает мгновенно и не требует пересборки источника данных.

Различие между скрытием слоя и фильтрацией данных

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

1. Видимость слоя (visibility)

Полное включение или выключение слоя на уровне рендеринга.

2. Фильтр (filter)

Управляет тем, какие фичи из источника попадают в слой.

map.setFilter("roads", ["==", ["get", "type"], "primary"]);

3. Прозрачность (paint.*-opacity)

Позволяет скрывать визуально, но слой продолжает участвовать в отрисовке.

map.setPaintProperty("roads", "line-opacity", 0);

Различие принципиально: visibility: none отключает слой на уровне pipeline, тогда как opacity и filter продолжают выполнять вычисления.

Производительность и влияние visibility

Отключение слоя через visibility: none имеет прямое влияние на производительность:

  • слой исключается из стадии рендеринга
  • не выполняются вычисления стилей paint/layout
  • уменьшается нагрузка на GPU
  • сокращается количество draw calls

При большом количестве слоёв (десятки и сотни) переключение видимости становится ключевым инструментом оптимизации интерфейса карты.

Особенно заметно это в сценариях:

  • переключение тематических карт (светлая/тёмная)
  • отображение только одного типа объектов (например, транспорт или здания)
  • адаптация карты под уровень зума

Управление видимостью через API

MapLibre GL JS предоставляет несколько методов для управления состоянием слоёв:

setLayoutProperty

Основной способ изменения visibility:

map.setLayoutProperty("buildings", "visibility", "none");

getLayoutProperty

Позволяет получить текущее состояние:

map.getLayoutProperty("buildings", "visibility");

removeLayer vs visibility

Удаление слоя:

map.removeLayer("buildings");

Разница с visibility: none:

  • removeLayer полностью удаляет слой из стиля
  • visibility: none сохраняет слой и его конфигурацию
  • повторное включение при visibility не требует пересоздания слоя

Удаление оправдано только при динамическом изменении структуры стиля, тогда как visibility используется для переключений состояния.

Зависимость видимости от масштаба

Хотя visibility не поддерживает выражения напрямую, его поведение часто комбинируется с параметрами:

  • minzoom
  • maxzoom
{
  id: "city-labels",
  type: "symbol",
  source: "places",
  layout: {
    "text-field": "{name}"
  },
  minzoom: 10,
  maxzoom: 15
}

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

В отличие от visibility, это не переключение состояния, а встроенное условие рендеринга.

Видимость и порядок слоёв

В MapLibre GL JS порядок слоёв строго определяет их наложение. Даже если слой видим, он может быть перекрыт другим слоем выше по стеку.

При изменении видимости важно учитывать:

  • скрытие нижнего слоя может не дать визуального эффекта, если верхний слой перекрывает сцену
  • включение слоя в середине стека может изменить восприятие всей композиции карты

Пример управления порядком:

map.moveLayer("roads", "waterways");

Анимация и переходы видимости

Свойство visibility не поддерживает плавные переходы. Переключение происходит мгновенно.

Для создания визуальной анимации скрытия используются альтернативные подходы:

1. Анимация opacity

map.setPaintProperty("roads", "line-opacity", 1);
map.setPaintProperty("roads", "line-opacity", 0);

2. Комбинирование opacity и visibility

Типичный паттерн:

  1. уменьшение opacity до 0
  2. затем visibility: none
map.setPaintProperty("roads", "line-opacity", 0);

setTimeout(() => {
  map.setLayoutProperty("roads", "visibility", "none");
}, 200);

Это позволяет избежать резкого исчезновения геометрии.

Видимость слоёв символов

Symbol layers (type: "symbol") имеют дополнительную сложность, так как включают:

  • текстовые подписи
  • иконки
  • collision detection (избежание наложений)

При visibility: none полностью отключается:

  • генерация текстовых ран
  • расчёт столкновений
  • загрузка иконок (если они не используются другими слоями)

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

Взаимодействие с источниками данных

Важно понимать, что visibility слоя не влияет на источник (source):

  • vector tile source остаётся загруженным
  • raster tiles продолжают кэшироваться
  • geojson source сохраняет данные в памяти

Поэтому переключение видимости — это операция уровня представления, а не данных.

Условная видимость через выражения стиля

Хотя visibility не является выражаемым параметром, аналогичная логика достигается через фильтры и свойства paint/layout:

map.setFilter("roads", ["==", ["get", "class"], "primary"]);

Или через zoom-based стили:

"line-opacity": [
  "interpolate",
  ["linear"],
  ["zoom"],
  5, 0,
  10, 1
]

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

Видимость и интерактивность слоёв

Слой с visibility: none полностью исключается из:

  • hit detection (обработки кликов)
  • hover-событий
  • queryRenderedFeatures
map.queryRenderedFeatures(point, {
  layers: ["roads"]
});

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

Это важно при реализации:

  • всплывающих подсказок
  • выделения объектов
  • интерактивных фильтров

Типовые архитектурные паттерны

Переключение тематических наборов слоёв

Группы слоёв управляются синхронно:

const layers = ["roads", "buildings", "labels"];

layers.forEach(id => {
  map.setLayoutProperty(id, "visibility", "none");
});

Режимные карты

Например:

  • транспортная карта
  • туристическая карта
  • карта рельефа

Каждый режим активирует свой набор слоёв, остальные скрываются через visibility: none.

Ленивое отображение

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

map.setLayoutProperty("3d-buildings", "visibility", "visible");

Это уменьшает задержки при переключении режимов.

Ограничения механизма visibility

Несмотря на простоту, модель имеет ограничения:

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

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