Свёрнутый и развёрнутый вид

В интерфейсах на основе картографической библиотеки Leaflet особое значение имеет управление плотностью элементов управления. Карта редко существует в изоляции: поверх неё размещаются слои, переключатели, фильтры, легенды, формы поиска, информационные панели. При ограниченном пространстве экрана требуется механизм переключения между компактным (свёрнутым) и расширенным (развёрнутым) представлением элементов интерфейса.

Свёрнутый вид в Leaflet обычно реализуется через скрытие или минимизацию панели управления, оставляя на карте только компактный элемент — кнопку, иконку или узкую полоску. Развёрнутый вид, напротив, раскрывает полный интерфейс с множеством контролов, списков слоёв или дополнительных настроек. Оба состояния часто управляются через CSS-классы и события DOM, интегрированные в архитектуру Leaflet Control API.


В Leaflet все элементы управления наследуются от базового класса L.Control. Этот класс определяет механизм добавления контролов на карту и их позиционирования через опции position.

Каждый контрол реализует метод:

  • onAdd(map) — создание DOM-структуры
  • onRemove(map) — очистка при удалении

Именно внутри onAdd формируется логика свёрнутого и развёрнутого состояния.

Базовая структура:

L.Control.Custom = L.Control.extend({
  onAdd: function(map) {
    const container = L.DomUtil.create('div', 'custom-control');
    return container;
  }
});

Понятие свёрнутого состояния

Свёрнутый вид представляет собой компактную версию интерфейса, которая минимизирует занимаемое пространство карты. Основные характеристики:

  • отсутствие списка элементов или опций в видимом DOM
  • отображение одной кнопки или иконки
  • наличие состояния «активен/неактивен»
  • быстрый доступ к разворачиванию

В Leaflet свёрнутое состояние чаще всего реализуется через CSS-класс, например:

.custom-control.collapsed {
  width: 32px;
  height: 32px;
  overflow: hidden;
}

DOM при этом остаётся в дереве, но визуально скрывается содержимое.


Понятие развёрнутого состояния

Развёрнутый вид включает полное отображение функциональности:

  • список слоёв
  • переключатели (checkbox/radio)
  • легенды
  • фильтры данных
  • дополнительные кнопки действий

Пример CSS:

.custom-control.expanded {
  width: 220px;
  height: auto;
  background: white;
  padding: 10px;
}

Развёрнутый вид обычно активируется кликом по кнопке сворачивания/разворачивания.


Базовая реализация переключения состояний

Переключение между состояниями строится на изменении CSS-класса контейнера.

L.Control.TogglePanel = L.Control.extend({
  onAdd: function(map) {
    const container = L.DomUtil.create('div', 'toggle-panel collapsed');

    const button = L.DomUtil.create('button', 'toggle-button', container);
    button.innerHTML = '☰';

    const content = L.DomUtil.create('div', 'panel-content', container);
    content.innerHTML = `
      <div>Слой 1</div>
      <div>Слой 2</div>
      <div>Слой 3</div>
    `;

    L.DomEvent.on(button, 'click', function(e) {
      L.DomEvent.stopPropagation(e);
      L.DomEvent.preventDefault(e);

      if (L.DomUtil.hasClass(container, 'collapsed')) {
        L.DomUtil.removeClass(container, 'collapsed');
        L.DomUtil.addClass(container, 'expanded');
      } else {
        L.DomUtil.removeClass(container, 'expanded');
        L.DomUtil.addClass(container, 'collapsed');
      }
    });

    return container;
  }
});

Использование встроенного Control Layers

Одним из наиболее распространённых примеров является стандартный L.control.layers, который уже содержит механизм свёрнутого/развёрнутого вида.

const baseLayers = {
  "OSM": osmLayer,
  "Satellite": satelliteLayer
};

const overlays = {
  "Дороги": roadsLayer,
  "Здания": buildingsLayer
};

L.control.layers(baseLayers, overlays, {
  collapsed: true
}).addTo(map);

Параметр collapsed управляет состоянием:

  • true — панель свёрнута (иконка раскрытия)
  • false — панель всегда развернута

Внутри Leaflet этот механизм реализован через добавление/удаление CSS-класса leaflet-control-layers-expanded.


CSS-реализация встроенного переключения

Leaflet использует стандартную модель:

.leaflet-control-layers {
  background: #fff;
  padding: 6px;
}

.leaflet-control-layers-expanded {
  width: 200px;
}

Свёрнутый вариант:

  • компактная кнопка с иконкой слоёв
  • отсутствие списка чекбоксов

Развёрнутый вариант:

  • список базовых слоёв
  • список overlay-слоёв
  • переключатели

Управление через события карты

Иногда состояние панели связывается с событиями карты, например масштабированием или изменением режима отображения.

map.on('zoomend', function() {
  const control = document.querySelector('.toggle-panel');

  if (map.getZoom() < 10) {
    control.classList.add('collapsed');
    control.classList.remove('expanded');
  }
});

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


Создание анимированного раскрытия

Для улучшения визуального восприятия используется CSS-анимация:

.toggle-panel {
  transition: all 0.25s ease;
  overflow: hidden;
}

.toggle-panel.collapsed .panel-content {
  max-height: 0;
  opacity: 0;
}

.toggle-panel.expanded .panel-content {
  max-height: 400px;
  opacity: 1;
}

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


Разделение логики и представления

В архитектуре Leaflet-контролов важно разделять:

  • состояние (collapsed/expanded)
  • визуализацию (CSS)
  • поведение (JavaScript)

Пример выделения состояния:

function setPanelState(container, state) {
  container.classList.toggle('collapsed', state === 'collapsed');
  container.classList.toggle('expanded', state === 'expanded');
}

Использование кастомных панелей

Leaflet не ограничивает создание сложных интерфейсов. Свёрнутые и развёрнутые панели часто реализуются как самостоятельные UI-компоненты поверх карты.

Пример структуры:

L.Control.Sidebar = L.Control.extend({
  onAdd: function(map) {
    const container = L.DomUtil.create('div', 'sidebar collapsed');

    const toggle = L.DomUtil.create('div', 'sidebar-toggle', container);
    const body = L.DomUtil.create('div', 'sidebar-body', container);

    toggle.oncl ick = function() {
      container.classList.toggle('collapsed');
      container.classList.toggle('expanded');
    };

    return container;
  }
});

Взаимодействие с слоями в развёрнутом виде

В расширенном состоянии интерфейс часто включает динамическое управление слоями:

  • добавление/удаление маркеров
  • переключение групп объектов
  • фильтрация данных

Пример:

function toggleLayer(layer, enabled) {
  if (enabled) {
    map.addLayer(layer);
  } else {
    map.removeLayer(layer);
  }
}

Эта логика часто привязывается к чекбоксам внутри развёрнутой панели.


Оптимизация при сворачивании

Свёрнутый режим часто используется для оптимизации производительности интерфейса:

  • отключение тяжёлых DOM-элементов
  • уменьшение количества обработчиков событий
  • скрытие списков слоёв

Пример отключения:

function collapsePanel(panel) {
  panel.classList.add('collapsed');

  const items = panel.querySelectorAll('.heavy-item');
  items.forEach(el => el.style.display = 'none');
}

Интеграция с адаптивной версткой

Свёрнутый и развёрнутый виды часто зависят от размера экрана:

@media (max-width: 600px) {
  .toggle-panel {
    width: 32px;
  }

  .toggle-panel.expanded {
    width: 100%;
  }
}

На мобильных устройствах свёрнутый вид становится основным состоянием, а развёрнутый — полноэкранным слоем.


Работа с z-index и перекрытиями

При разворачивании панелей важно учитывать слойность интерфейса Leaflet:

  • карта находится в нижнем слое
  • контролы — поверх карты
  • модальные панели — выше контролов

Пример:

.toggle-panel {
  position: absolute;
  z-index: 1000;
}

Развёрнутые панели часто требуют увеличения z-index для предотвращения перекрытия маркеров или popup-окон.


Управление состоянием через внешний state

В более сложных приложениях состояние свёрнутости выносится из DOM:

const panelState = {
  layers: 'collapsed'
};

function toggleLayersPanel() {
  panelState.layers =
    panelState.layers === 'collapsed' ? 'expanded' : 'collapsed';
}

Такой подход облегчает интеграцию с фреймворками (React, Vue, Svelte), даже при использовании Leaflet как низкоуровневого слоя визуализации.


Связь с пользовательскими сценариями

Свёрнутый и развёрнутый виды в Leaflet применяются для управления плотностью информации:

  • навигационные карты с минимальным интерфейсом
  • аналитические панели с множеством слоёв
  • геоданные с фильтрацией и сегментацией
  • мобильные интерфейсы с ограниченным пространством

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