В системе рендеринга Mapbox GL JS каждый слой управляется через
объект описания слоя, где ключевую роль в управлении отображением играет
поле layout.visibility. Оно определяет, будет ли слой
участвовать в отрисовке карты или временно исключён из визуализации без
удаления из стиля.
Основные допустимые значения:
visible — слой отображаетсяnone — слой скрытmap.addLayer({
id: 'roads-layer',
type: 'line',
source: 'composite',
'source-layer': 'road',
layout: {
visibility: 'visible'
},
paint: {
'line-color': '#ff0000',
'line-width': 2
}
});
Скрытие слоя без удаления из стиля:
map.setLayoutProperty('roads-layer', 'visibility', 'none');
Возврат отображения:
map.setLayoutProperty('roads-layer', 'visibility', 'visible');
Изменение visibility не влияет на загрузку данных слоя.
Источник продолжает запрашиваться, тайлы продолжают кешироваться, а
фильтры и вычисления остаются активными. Различие заключается
исключительно в финальной стадии рендеринга.
Mapbox GL JS использует декларативную модель стиля, где каждый слой
участвует в графе рендеринга. При этом visibility — это не
просто CSS-подобное свойство, а часть layout-стадии, определяющей
участие слоя в композиции кадра.
Рендеринг проходит несколько этапов:
visibilityЕсли visibility = none, слой исключается на шаге
композиции, что делает его невидимым без удаления вычислительного
контекста.
Основной способ динамического управления слоями — метод
setLayoutProperty.
map.setLayoutProperty('buildings-layer', 'visibility', 'none');
map.setLayoutProperty('buildings-layer', 'visibility', 'visible');
Перед изменением свойства важно убедиться, что слой уже добавлен в стиль:
if (map.getLayer('buildings-layer')) {
map.setLayoutProperty('buildings-layer', 'visibility', 'none');
}
Для получения текущего состояния используется
getLayoutProperty:
const state = map.getLayoutProperty('buildings-layer', 'visibility');
Удаление слоя через removeLayer полностью исключает его
из графа стиля:
map.removeLayer('roads-layer');
В отличие от этого:
visibility: none сохраняет слой в памятиУдаление слоя оправдано только при полной очистке конфигурации, тогда
как visibility используется для переключения режимов
отображения.
Скрытие слоя через visibility: none снижает нагрузку на
GPU только на стадии отрисовки. Однако:
Поэтому большое количество скрытых слоёв может незначительно влиять
на производительность, особенно при сложных выражениях
paint и filter.
Порядок слоёв в стиле влияет на итоговое отображение. Даже если слой видим, он может быть перекрыт другим слоем.
map.addLayer({
id: 'water',
type: 'fill',
source: 'composite',
'source-layer': 'water',
paint: {
'fill-color': '#00bfff'
}
});
map.addLayer({
id: 'labels',
type: 'symbol',
source: 'composite',
'source-layer': 'place_label'
});
В данном случае labels будет отрисован поверх
water, если не изменить порядок добавления или использовать
beforeId.
map.addLayer(layerConfig, 'labels');
Таким образом, визуальная «видимость» слоя складывается из двух факторов:
layout.visibilityХотя visibility управляется напрямую, часто используется
косвенное управление через масштаб:
minzoommaxzoommap.addLayer({
id: 'poi-layer',
type: 'symbol',
source: 'composite',
'source-layer': 'poi',
minzoom: 12,
maxzoom: 18,
layout: {
visibility: 'visible'
}
});
Такой слой не исчезает через visibility, но перестаёт
отображаться вне диапазона масштабов.
Комбинация этих механизмов позволяет создавать сложные стратегии отображения:
visibility — ручное переключениеТипичная архитектура картографических приложений использует слои как взаимно исключающие режимы:
function setTheme(theme) {
map.setLayoutProperty('light-map', 'visibility', theme === 'light' ? 'visible' : 'none');
map.setLayoutProperty('dark-map', 'visibility', theme === 'dark' ? 'visible' : 'none');
}
Такой подход позволяет:
Хотя visibility принимает только строковые значения,
более гибкая логика реализуется через фильтры и выражения
case внутри paint/layout свойств.
Пример имитации скрытия по условию:
map.setPaintProperty('roads-layer', 'line-opacity', [
'case',
['==', ['get', 'class'], 'secondary'],
0,
1
]);
Хотя слой остаётся visible, визуально часть данных
скрывается.
Это позволяет обходить ограничение бинарности
visibility.
При наличии нескольких слоёв, использующих один источник, управление видимостью одного слоя не влияет на другие:
map.setLayoutProperty('roads-line', 'visibility', 'none');
При этом:
roads-label остаётся активнымroads-halo может продолжать отображатьсяЭто важно при построении слоёв-композиций, где геометрия и подписи разделены.
Часто переключение слоёв привязывается к событиям карты:
map.on('zoom', () => {
const zoom = map.getZoom();
if (zoom < 10) {
map.setLayoutProperty('detail-layer', 'visibility', 'none');
} else {
map.setLayoutProperty('detail-layer', 'visibility', 'visible');
}
});
Такой подход позволяет реализовать адаптивные карты, где детализация изменяется в зависимости от масштаба.
Однако частое изменение visibility в обработчиках
событий может приводить к лишним пересчётам стиля, поэтому
предпочтительнее использовать minzoom и
maxzoom, если логика линейна.
Фильтры слоя могут создавать эффект «пустого слоя», который технически остаётся видимым:
map.setFilter('cities-layer', ['==', 'name', 'NonExistingCity']);
В этом случае:
visibility = visibleТакой слой визуально эквивалентен скрытому, но сохраняет вычислительный контекст фильтрации.
В сложных приложениях состояние visibility часто
синхронизируется с UI:
function toggleLayer(id, state) {
map.setLayoutProperty(id, 'visibility', state ? 'visible' : 'none');
}
При этом важно учитывать:
При первом рендере карты слои с visibility: none:
Изменение visibility до события load может
не дать эффекта, если слой ещё не добавлен:
map.on('load', () => {
map.setLayoutProperty('roads-layer', 'visibility', 'none');
});
Хотя Mapbox GL JS не имеет встроенных групп слоёв, логика группировки реализуется через соглашения об именовании:
roads-*buildings-*labels-*Пример массового переключения:
const layers = ['roads-main', 'roads-secondary', 'roads-minor'];
layers.forEach(id => {
map.setLayoutProperty(id, 'visibility', 'none');
});
Такой подход используется для тематических переключений и режимов отображения.
При вызове setStyle все изменения
visibility, сделанные динамически, сбрасываются:
map.setStyle('mapbox://styles/mapbox/streets-v11');
После этого:
Поэтому состояние видимости часто хранится вне Mapbox и
восстанавливается после загрузки стиля через
style.load.