Visibility

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

В Mapbox GL JS значение свойства задаётся через параметр:

layout: {
    visibility: 'visible'
}

или изменяется после создания слоя с помощью метода:

map.setLayoutProperty(layerId, 'visibility', 'none');

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

Значение Описание
visible Слой отображается
none Слой скрыт

Принцип работы visibility

Каждый слой карты проходит этапы:

  1. Получение данных.
  2. Обработка данных.
  3. Рендеринг объектов.

Когда свойство принимает значение:

visibility: 'visible'

слой участвует в процессе отрисовки.

Когда используется:

visibility: 'none'

слой остаётся зарегистрированным в стиле карты, но его объекты не отображаются.

Важно понимать различие между скрытием слоя и его удалением:

map.removeLayer('roads');

Удаление уничтожает слой полностью.

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

Скрытие лишь отключает отображение.

Данные при этом продолжают существовать внутри карты.


Задание видимости при создании слоя

Отображаемый слой

По умолчанию большинство слоёв являются видимыми.

map.addLayer({
    id: 'cities',
    type: 'circle',
    source: 'cities-source',
    paint: {
        'circle-radius': 6,
        'circle-color': '#ff0000'
    },
    layout: {
        visibility: 'visible'
    }
});

Скрытый слой

Слой может быть добавлен в скрытом состоянии.

map.addLayer({
    id: 'cities',
    type: 'circle',
    source: 'cities-source',
    paint: {
        'circle-radius': 6,
        'circle-color': '#ff0000'
    },
    layout: {
        visibility: 'none'
    }
});

После загрузки карты такой слой не будет отображаться до изменения свойства.


Изменение видимости после создания слоя

Наиболее распространённый сценарий — переключение отображения во время работы приложения.

Скрытие слоя

map.setLayoutProperty(
    'cities',
    'visibility',
    'none'
);

Показ слоя

map.setLayoutProperty(
    'cities',
    'visibility',
    'visible'
);

Получение текущего состояния

Для определения текущей видимости используется метод:

map.getLayoutProperty(
    'cities',
    'visibility'
);

Результат:

'visible'

или

'none'

Пример:

const visibility =
    map.getLayoutProperty(
        'cities',
        'visibility'
    );

console.log(visibility);

Реализация переключателя слоя

Один из наиболее популярных сценариев — кнопка включения и отключения слоя.

button.addEventListener('click', () => {

    const visibility =
        map.getLayoutProperty(
            'cities',
            'visibility'
        );

    if (visibility === 'visible') {

        map.setLayoutProperty(
            'cities',
            'visibility',
            'none'
        );

    } else {

        map.setLayoutProperty(
            'cities',
            'visibility',
            'visible'
        );

    }

});

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


Создание панели слоёв

Часто карта содержит множество тематических слоёв:

  • дороги;
  • здания;
  • парковки;
  • остановки;
  • водоёмы;
  • административные границы.

Каждый слой может включаться и выключаться независимо.

const layers = [
    'roads',
    'buildings',
    'water'
];

layers.forEach(layerId => {

    const checkbox =
        document.createElement('input');

    checkbox.type = 'checkbox';
    checkbox.checked = true;

    checkbox.addEventListener('change', () => {

        map.setLayoutProperty(
            layerId,
            'visibility',
            checkbox.checked
                ? 'visible'
                : 'none'
        );

    });

});

Подобная структура лежит в основе большинства GIS-интерфейсов.


Visibility и производительность

Скрытие слоя значительно эффективнее его постоянного удаления и повторного создания.

Нежелательный вариант:

map.removeLayer('roads');

map.addLayer({
    id: 'roads',
    ...
});

Предпочтительный вариант:

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

Причины:

  • не требуется заново создавать слой;
  • не пересоздаются настройки стиля;
  • не выполняется повторная инициализация;
  • уменьшается нагрузка на браузер.

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


Visibility и источник данных

Скрытие слоя не влияет на источник данных.

Например:

map.addSource('cities', {
    type: 'geojson',
    data: citiesData
});

Если затем скрыть слой:

map.setLayoutProperty(
    'cities-layer',
    'visibility',
    'none'
);

источник cities продолжит существовать.

Его данные остаются доступными:

map.getSource('cities');

Это особенно важно для приложений, где несколько слоёв используют один и тот же source.


Visibility и фильтры

Скрытие слоя отличается от фильтрации объектов.

Visibility

map.setLayoutProperty(
    'cities',
    'visibility',
    'none'
);

На карте не отображается ничего.


Filter

map.setFilter('cities', [
    '==',
    'country',
    'France'
]);

Слой остаётся активным, но отображает только подходящие объекты.

Сравнение:

Механизм Результат
visibility Скрывается весь слой
filter Скрываются отдельные объекты
removeLayer Слой удаляется полностью

Visibility и масштаб карты

Видимость слоя можно комбинировать с ограничениями масштаба.

map.addLayer({
    id: 'buildings',
    type: 'fill',
    source: 'buildings',
    minzoom: 15,
    layout: {
        visibility: 'visible'
    }
});

Слой будет отображаться:

  • только начиная с масштаба 15;
  • только если свойство visibility равно visible.

Если установить:

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

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


Массовое переключение слоёв

Иногда необходимо скрыть сразу несколько слоёв.

const thematicLayers = [
    'roads',
    'bridges',
    'tunnels',
    'railways'
];

thematicLayers.forEach(layerId => {

    map.setLayoutProperty(
        layerId,
        'visibility',
        'none'
    );

});

Включение выполняется аналогично:

thematicLayers.forEach(layerId => {

    map.setLayoutProperty(
        layerId,
        'visibility',
        'visible'
    );

});

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

Часто карта поддерживает несколько режимов отображения.

Например:

  • транспортный;
  • туристический;
  • спутниковый;
  • инженерный.

Для транспортного режима:

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

map.setLayoutProperty(
    'railways',
    'visibility',
    'visible'
);

map.setLayoutProperty(
    'tourist-routes',
    'visibility',
    'none'
);

Для туристического режима:

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

map.setLayoutProperty(
    'railways',
    'visibility',
    'none'
);

map.setLayoutProperty(
    'tourist-routes',
    'visibility',
    'visible'
);

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


Проверка существования слоя перед изменением

Попытка изменить несуществующий слой вызывает ошибку.

Надёжный вариант:

if (map.getLayer('cities')) {

    map.setLayoutProperty(
        'cities',
        'visibility',
        'none'
    );

}

Подобная проверка особенно полезна при работе с динамически создаваемыми слоями.


Visibility в обработчиках событий

Свойство часто используется совместно с пользовательскими событиями.

Реакция на изменение масштаба

map.on('zoom', () => {

    if (map.getZoom() > 12) {

        map.setLayoutProperty(
            'cities',
            'visibility',
            'visible'
        );

    } else {

        map.setLayoutProperty(
            'cities',
            'visibility',
            'none'
        );

    }

});

Реакция на выбор режима

select.addEventListener(
    'change',
    event => {

        map.setLayoutProperty(
            'roads',
            'visibility',
            event.target.value === 'roads'
                ? 'visible'
                : 'none'
        );

    }
);

Visibility и группы слоёв

В Mapbox GL JS отсутствует понятие группы слоёв на уровне API. Обычно группировка реализуется программно.

const weatherLayers = [
    'temperature',
    'wind',
    'precipitation'
];

Скрытие всей группы:

weatherLayers.forEach(layer => {

    map.setLayoutProperty(
        layer,
        'visibility',
        'none'
    );

});

Показ группы:

weatherLayers.forEach(layer => {

    map.setLayoutProperty(
        layer,
        'visibility',
        'visible'
    );

});

Типичные ошибки

Использование свойства в paint

Неверно:

paint: {
    visibility: 'none'
}

Свойство не относится к секции paint.

Правильно:

layout: {
    visibility: 'none'
}

Использование логических значений

Неверно:

visibility: false

или

visibility: true

Mapbox GL JS ожидает строковые значения:

visibility: 'none'

или

visibility: 'visible'

Работа с несуществующим слоем

Неверно:

map.setLayoutProperty(
    'unknown-layer',
    'visibility',
    'none'
);

Следует предварительно проверить наличие слоя:

if (map.getLayer('unknown-layer')) {
    // изменение свойства
}

Практические сценарии применения

Свойство visibility активно используется для решения следующих задач:

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

Благодаря простоте и высокой производительности свойство visibility является основным механизмом управления отображением слоёв в Mapbox GL JS и используется практически в каждом сложном картографическом приложении.