События групп слоев

Архитектура групп слоёв

В библиотеке Leaflet слои не существуют изолированно: они объединяются в коллекции, позволяющие управлять множеством объектов как единым целым. Базовыми структурами выступают LayerGroup и его расширение FeatureGroup. Эти классы наследуют поведение Evented, что делает их полноценными источниками событий.

Ключевая особенность — группа слоёв не только агрегирует объекты, но и транслирует изменения состава через событийную систему. Это позволяет синхронизировать состояние карты, UI и бизнес-логики без ручного обхода каждого слоя.


Базовые типы групп

LayerGroup

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

Основные задачи:

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

FeatureGroup

FeatureGroup расширяет LayerGroup, добавляя:

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

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

Группы слоёв являются источниками событий (Evented), что означает наличие стандартного набора методов:

  • on(type, fn) — подписка на событие
  • off(type, fn) — удаление обработчика
  • fire(type, data) — ручной вызов события

Основные события LayerGroup

layeradd

Событие layeradd возникает при добавлении нового слоя в группу.

Срабатывает:

  • при вызове addLayer(layer)
  • при добавлении группы на карту, если внутри есть слои

Передаваемый объект события:

  • layer — добавленный слой
const group = L.layerGroup();

group.on('layeradd', (e) => {
  console.log('Добавлен слой:', e.layer);
});

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

layerremove

Событие layerremove возникает при удалении слоя из группы.

Срабатывает:

  • при removeLayer(layer)
  • при удалении группы с карты
group.on('layerremove', (e) => {
  console.log('Удалён слой:', e.layer);
});

group.removeLayer(marker);

add

Событие add связано с добавлением всей группы на карту. Оно отличается от layeradd тем, что относится к самой группе как объекту, а не к внутренним слоям.

group.on('add', (e) => {
  console.log('Группа добавлена на карту');
});

remove

Событие remove возникает при удалении группы с карты.

group.on('remove', () => {
  console.log('Группа удалена с карты');
});

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

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

Событие Источник Смысл
layeradd LayerGroup Добавление слоя в группу
layerremove LayerGroup Удаление слоя из группы
add LayerGroup Добавление группы на карту
remove LayerGroup Удаление группы с карты
layeradd (Map) Map Добавление любого слоя на карту

FeatureGroup и расширенные события

FeatureGroup усиливает событийную модель за счёт поддержки интерактивных слоёв.

click, mouseover, mouseout

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

const features = L.featureGroup();

features.on('click', (e) => {
  console.log('Клик по одному из объектов группы:', e.layer);
});

Особенность заключается в том, что событие содержит:

  • layer — конкретный слой, вызвавший событие
  • latlng — координаты (если применимо)
  • target — группа как объект-источник

popupopen и popupclose

Если слои внутри группы используют popup, события также всплывают:

features.on('popupopen', (e) => {
  console.log('Открыт popup слоя:', e.popup);
});

Проксификация событий

Группы в Leaflet реализуют механизм проксирования событий от дочерних слоёв.

Это означает:

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

Внутренний механизм layeradd/layerremove

При добавлении слоя в группу происходит следующая цепочка:

  1. Вызов group.addLayer(layer)
  2. Проверка наличия слоя в коллекции
  3. Добавление слоя в внутренний индекс
  4. Подписка группы на события слоя (если применимо)
  5. Генерация события layeradd
  6. Если группа уже на карте — добавление слоя на карту

Аналогично при удалении:

  1. group.removeLayer(layer)
  2. Удаление из внутреннего хранилища
  3. Отписка от событий
  4. Генерация layerremove
  5. Удаление с карты (если группа добавлена)

Управление событиями через методы группы

onEachFeature и связка с GeoJSON

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

const geoGroup = L.featureGroup();

L.geoJSON(data, {
  onEachFeature: (feature, layer) => {
    layer.on('click', () => {
      console.log(feature.properties);
    });

    geoGroup.addLayer(layer);
  }
});

eachLayer и контроль событий

Метод eachLayer позволяет массово навесить обработчики:

group.eachLayer((layer) => {
  layer.on('click', () => {
    console.log('Клик по слою');
  });
});

Всплытие событий (event bubbling)

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

Иерархия:

  • слой
  • группа
  • карта

Пример цепочки:

  • пользователь кликает по маркеру
  • маркер генерирует click
  • FeatureGroup получает событие
  • Map получает агрегированное событие

Контекст события

Каждое событие группы содержит стандартные поля:

  • type — тип события
  • target — объект, который инициировал событие
  • layer — конкретный слой (если применимо)
  • latlng — координаты (для геометрических слоёв)
  • sourceTarget — исходный объект события

Практика управления динамическими группами

Добавление слоёв с отслеживанием состояния

const group = L.layerGroup();

group.on('layeradd', (e) => {
  e.layer._addedAt = Date.now();
});

group.addLayer(L.marker([55.75, 37.61]));

Удаление слоёв с логированием

group.on('layerremove', (e) => {
  console.log('Слой удалён:', e.layer);
});

Синхронизация UI с состоянием группы

group.on('layeradd layerremove', () => {
  console.log('Состав группы изменён:', group.getLayers().length);
});

Динамическая пересборка групп

При интенсивной работе с данными группы часто пересобираются:

group.clearLayers();

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

События:

  • множественные layerremove
  • множественные layeradd

Это позволяет отслеживать полное обновление состояния.


Особенности обработки большого количества событий

При работе с десятками тысяч слоёв:

  • события layeradd могут генерироваться массово;
  • обработчики должны быть максимально лёгкими;
  • рекомендуется агрегировать изменения через debounce-логику вне Leaflet.
let timer;

group.on('layeradd layerremove', () => {
  clearTimeout(timer);
  timer = setTimeout(() => {
    console.log('Группа стабилизировалась');
  }, 50);
});

Взаимодействие с другими системами событий

Группы слоёв часто выступают мостом между:

  • геоданными (GeoJSON, WKT);
  • UI-компонентами;
  • серверными потоками данных (WebSocket, polling).

События layeradd и layerremove становятся точкой синхронизации состояния приложения с картой.