Группировка слоев

В Leaflet работа с визуальными элементами карты строится вокруг концепции слоёв. Каждый объект — тайлы, маркеры, векторные фигуры, GeoJSON-данные — представляет собой отдельный слой, который может быть добавлен на карту, удалён или изменён.

При усложнении интерфейса возникает необходимость объединять слои в логические группы. Это позволяет управлять множеством объектов как единым целым: включать/выключать наборы данных, изменять порядок отображения, применять операции к группе сразу, а не к каждому элементу отдельно.

Основные механизмы группировки:

  • LayerGroup — базовая группа слоёв
  • FeatureGroup — расширенная группа с событийной моделью
  • Control.Layers — UI-компонент управления группами слоёв
  • вложенные группы слоёв

LayerGroup как фундамент объединения слоёв

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

Создание группы

const markers = L.layerGroup();

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

markers.addLayer(marker1);
markers.addLayer(marker2);
markers.addLayer(marker3);

markers.addTo(map);

LayerGroup не накладывает ограничений на типы слоёв. В одной группе могут находиться:

  • маркеры (L.marker)
  • поли линии (L.polyline)
  • полигоны (L.polygon)
  • круги (L.circle)
  • GeoJSON-слои

Основные методы LayerGroup

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

group.addLayer(layer);
group.removeLayer(layer);

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

group.clearLayers();

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

Перебор слоёв

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

Каждый слой передаётся в callback-функцию, что позволяет выполнять массовые операции:

  • изменение стиля
  • обновление координат
  • навешивание событий

Практическая роль LayerGroup

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

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

Пример логической группировки:

const restaurants = L.layerGroup();
const parks = L.layerGroup();
const transport = L.layerGroup();

FeatureGroup: расширенная модель группировки

L.FeatureGroup расширяет LayerGroup, добавляя поддержку событий и взаимодействия.

Ключевая особенность — группа становится единым интерактивным объектом.

Создание FeatureGroup

const editableItems = L.featureGroup();

Отличие от LayerGroup

FeatureGroup:

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

События группы

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

editableItems.on('click', function (e) {
    console.log('Клик по любому элементу группы', e.layer);
});

Это позволяет избегать навешивания обработчиков на каждый объект отдельно.


Работа с границами

FeatureGroup умеет вычислять bounding box всех вложенных элементов:

const bounds = editableItems.getBounds();
map.fitBounds(bounds);

Это особенно полезно при:

  • отображении набора объектов
  • автоматическом масштабировании карты
  • переключении между слоями данных

Управление группами через Control.Layers

L.control.layers предоставляет интерфейс переключения между группами слоёв.

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

const baseMaps = {
    "Карта": osm,
    "Спутник": satellite
};

const overlayMaps = {
    "Рестораны": restaurants,
    "Парки": parks
};

L.control.layers(baseMaps, overlayMaps).addTo(map);

Логика overlay-групп

Overlay-группы позволяют:

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

Пример поведения:

  • включены «Рестораны» и «Парки» → отображаются обе группы
  • выключены все overlay → остаётся только базовый слой

Вложенные группы слоёв

Хотя Leaflet не предоставляет формальной древовидной структуры групп, LayerGroup может содержать другие LayerGroup или FeatureGroup.

const cities = L.layerGroup();
const moscowMarkers = L.layerGroup();
const parisMarkers = L.layerGroup();

cities.addLayer(moscowMarkers);
cities.addLayer(parisMarkers);

Такой подход создаёт многоуровневую структуру логики:

  • страны

    • города

      • объекты

Управление порядком отображения (Z-index)

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

Для маркеров

marker.setZIndexOffset(1000);

Для групп

Группа наследует поведение вложенных слоёв, но не имеет собственного z-index как контейнер. Порядок определяется:

  • порядком добавления на карту
  • z-index отдельных элементов

Динамическое управление группами

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

if (type === 'restaurant') {
    restaurants.addLayer(marker);
}

Перемещение слоя между группами

oldGroup.removeLayer(marker);
newGroup.addLayer(marker);

Это позволяет реализовать:

  • фильтрацию
  • переклассификацию объектов
  • интерактивные переключатели категорий

Очистка и пересборка групп

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

function rebuildGroup(data) {
    group.clearLayers();

    data.forEach(item => {
        const marker = L.marker(item.coords);
        group.addLayer(marker);
    });
}

Такой подход упрощает синхронизацию с сервером.


Геоданные и группировка GeoJSON

GeoJSON-слои особенно часто группируются.

const geoLayer = L.geoJSON(data);
const group = L.layerGroup([geoLayer]);

Или динамически:

const group = L.featureGroup();

L.geoJSON(data, {
    onEachFeature: function (feature, layer) {
        group.addLayer(layer);
    }
});

Событийная модель внутри групп

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

  • click
  • mouseover
  • mouseout
  • dragstart
  • dragend

FeatureGroup агрегирует эти события:

group.on('mouseover', function (e) {
    e.layer.setStyle({ color: 'red' });
});

Оптимизация производительности при группировке

При большом количестве объектов группировка влияет на производительность:

Рекомендации:

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

Пример оптимизированной загрузки:

map.off();

group.clearLayers();

batch.forEach(item => {
    group.addLayer(L.marker(item.coords));
});

map.on();

Контроль видимости групп

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

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

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


Интерактивные сценарии группировки

Фильтрация по категориям

function filter(category) {
    group.clearLayers();

    data
        .filter(item => item.category === category)
        .forEach(item => {
            group.addLayer(L.marker(item.coords));
        });
}

Переключение слоёв по состоянию интерфейса

checkbox.oncha nge = function () {
    if (this.checked) {
        map.addLayer(restaurants);
    } else {
        map.removeLayer(restaurants);
    }
};

Использование групп в архитектуре приложения

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

  • слой данных (Data Layer)
  • слой визуализации (View Layer)
  • слой управления (Control Layer)

Типичная структура:

const layers = {
    traffic: L.layerGroup(),
    infrastructure: L.layerGroup(),
    analytics: L.featureGroup()
};

Связь групп и масштабируемости проекта

Чем больше объём данных, тем важнее структурирование:

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

Группы становятся аналогом контейнеров состояния для карты, упрощая управление сложными сценами и многослойными визуализациями.