Класс LayerGroup

Назначение и концепция LayerGroup

LayerGroup представляет собой контейнер для объединения нескольких слоёв в единую логическую структуру. Он не является визуальным слоем сам по себе, но управляет набором вложенных объектов, реализующих интерфейс ILayer.

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

LayerGroup используется для:

  • группировки маркеров (Marker)
  • объединения векторных объектов (Polyline, Polygon, Circle)
  • логической сегментации карты
  • управления наборами объектов как единым состоянием

Создание LayerGroup

Базовая инициализация выполняется через конструктор:

const group = L.layerGroup();

Также допускается передача массива слоёв:

const marker1 = L.marker([51.5, -0.09]);
const marker2 = L.marker([51.51, -0.1]);

const group = L.layerGroup([marker1, marker2]);

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


Добавление LayerGroup на карту

Группа слоёв ведёт себя как обычный слой:

group.addTo(map);

Эквивалентная форма:

map.addLayer(group);

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


Добавление и удаление слоёв

Добавление слоя

group.addLayer(L.marker([51.5, -0.09]));

Метод возвращает сам объект LayerGroup, что позволяет строить цепочки вызовов:

group
  .addLayer(L.marker([51.5, -0.09]))
  .addLayer(L.circle([51.51, -0.1], { radius: 200 }));

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

group.removeLayer(marker);

Удаление происходит по ссылке на объект слоя. Если слой не найден, операция игнорируется.


Очистка группы

Для удаления всех вложенных слоёв используется:

group.clearLayers();

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


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

group.hasLayer(marker);

Возвращает true, если слой присутствует в группе, иначе false.


Обход слоёв внутри группы

LayerGroup предоставляет возможность итерации:

group.eachLayer(function (layer) {
  console.log(layer);
});

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


Получение всех слоёв

const layers = group.getLayers();

Возвращается массив ссылок на слои. Изменение массива не влияет на саму группу.


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

LayerGroup наследует поведение от базового слоя, поэтому поддерживает стандартные операции:

map.addLayer(group);
map.removeLayer(group);

При удалении группы с карты автоматически скрываются все вложенные элементы.


Вложенные группы (Nested LayerGroup)

LayerGroup может содержать другие группы:

const subgroup = L.layerGroup([
  L.marker([51.49, -0.08]),
  L.marker([51.5, -0.1])
]);

const mainGroup = L.layerGroup([subgroup]);
mainGroup.addTo(map);

Такая структура позволяет строить древовидную организацию слоёв. При этом операции addLayer и removeLayer работают рекурсивно.


Поведение при событиях

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

Пример:

const marker = L.marker([51.5, -0.09])
  .on('click', () => console.log('click'));

group.addLayer(marker);
group.addTo(map);

Событие клика обрабатывается на уровне маркера, а не группы.


Отличие LayerGroup от FeatureGroup

Хотя LayerGroup и FeatureGroup внешне похожи, различие принципиальное:

  • LayerGroup — простая агрегация слоёв без дополнительной логики
  • FeatureGroup — расширение с поддержкой событий, геометрических операций и интерактивности

LayerGroup не предоставляет методов типа getBounds() или setStyle().


Использование с динамическими данными

LayerGroup часто применяется для управления динамическими наборами объектов:

const group = L.layerGroup().addTo(map);

fetch('/api/points')
  .then(res => res.json())
  .then(data => {
    data.forEach(item => {
      group.addLayer(L.marker([item.lat, item.lng]));
    });
  });

Обновление данных:

group.clearLayers();

newData.forEach(item => {
  group.addLayer(L.marker([item.lat, item.lng]));
});

Комбинирование с управлением слоёв (Layer Control)

LayerGroup удобно подключать к контролю слоёв:

const cities = L.layerGroup([marker1, marker2]);
const rivers = L.layerGroup([line1, line2]);

L.control.layers(null, {
  "Города": cities,
  "Реки": rivers
}).addTo(map);

Каждая группа выступает как единый переключаемый слой.


Производительность и особенности работы

При большом количестве объектов LayerGroup не создаёт дополнительной визуальной нагрузки, так как не добавляет собственных DOM-элементов или canvas-слоёв. Однако:

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

Взаимодействие с GeoJSON

LayerGroup часто используется как контейнер для результатов L.geoJSON:

const group = L.layerGroup();

const geoLayer = L.geoJSON(geoData);
group.addLayer(geoLayer);

group.addTo(map);

Такой подход позволяет комбинировать GeoJSON-слои с другими типами объектов в одной структуре.


Управление порядком слоёв

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

group.addLayer(markerA);
group.addLayer(markerB);

markerB будет выше в стекe отображения, если используется DOM-рендеринг (например, маркеры).


Ограничения LayerGroup

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

LayerGroup остаётся низкоуровневым инструментом композиции, а не анализа или визуализации.


Типичные сценарии архитектуры

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

  • группа маркеров пользователей
  • группа объектов инфраструктуры
  • группа временных данных (heat / live updates)
  • группа выбранных объектов

Пример многослойной структуры:

const usersLayer = L.layerGroup();
const poiLayer = L.layerGroup();
const tempLayer = L.layerGroup();

const overlays = {
  "Пользователи": usersLayer,
  "Точки интереса": poiLayer,
  "Временные данные": tempLayer
};

L.control.layers(null, overlays).addTo(map);