Векторные слои в Leaflet основаны на системе событий, унаследованной
от ядра библиотеки и тесно связанной с DOM-подобной моделью обработки
взаимодействий. Любой объект, наследующийся от L.Layer и
реализующий интерактивность (например, L.Path,
L.Polygon, L.Polyline, L.Circle,
L.Rectangle, L.GeoJSON), поддерживает единый
набор событий и механизм подписки через on,
off и once.
Векторные объекты в Leaflet состоят из двух уровней:
Интерактивность активируется через свойство:
interactive: true
Без него события мыши для слоя не генерируются.
Базовый механизм работы с событиями реализуется через методы:
on(type, handler)off(type, handler)once(type, handler)const polygon = L.polygon([
[51.5, -0.09],
[51.51, -0.1],
[51.52, -0.12]
]).addTo(map);
polygon.on('click', function (e) {
console.log('Клик по полигону');
});
polygon.once('click', function () {
console.log('Сработает только один раз');
});
Все интерактивные векторные слои поддерживают единый набор событий:
clickdblclickmousedownmouseupmouseovermouseoutmousemovecontextmenuСрабатывает при клике по геометрии:
polygon.on('click', (e) => {
console.log(e.latlng);
});
Используются для визуальной реакции при наведении:
polygon.on('mouseover', () => {
polygon.setStyle({ color: 'red' });
});
polygon.on('mouseout', () => {
polygon.setStyle({ color: 'blue' });
});
Генерируется при перемещении курсора внутри слоя:
polygon.on('mousemove', (e) => {
console.log(e.latlng);
});
Каждое событие содержит унифицированный объект event,
включающий координаты и ссылки на слои.
latlng — географические координатыlayerPoint — координаты в пикселях относительно
слояcontainerPoint — координаты относительно контейнера
картыtarget — слой, вызвавший событиеsourceTarget — исходный источник событияoriginalEvent — нативное DOM-событиеpolygon.on('click', function (e) {
console.log(e.latlng.lat, e.latlng.lng);
console.log(e.containerPoint.x, e.containerPoint.y);
});
Векторные слои генерируют системные события жизненного цикла:
add — слой добавлен на картуremove — слой удалён с картыpolygon.on('add', () => {
console.log('Слой добавлен');
});
polygon.on('remove', () => {
console.log('Слой удалён');
});
Эти события полезны для инициализации ресурсов и очистки состояния.
Если к векторному слою привязаны popup или tooltip, доступны дополнительные события:
popupopenpopupclosetooltipopentooltipclosepolygon.bindPopup('Информация');
polygon.on('popupopen', () => {
console.log('Popup открыт');
});
polygon.on('popupclose', () => {
console.log('Popup закрыт');
});
L.GeoJSON расширяет систему событий, добавляя обработку
на уровне каждой геометрической сущности.
L.geoJSON(data, {
onEachFeature: function (feature, layer) {
layer.on('click', function () {
console.log(feature.properties);
});
}
}).addTo(map);
Каждая feature становится независимым источником событий.
При работе с большим количеством объектов применяется паттерн делегирования:
const geoLayer = L.geoJSON(data, {
onEachFeature: (feature, layer) => {
layer.on('click', (e) => {
console.log(feature.id);
});
}
});
Это снижает нагрузку по сравнению с массовой подпиской на уровне карты.
Leaflet поддерживает механизм всплытия событий от слоя к карте.
map.on('click', (e) => {
console.log('Клик по карте');
});
Если клик происходит по векторному слою, событие может всплыть на карту, если не остановлено.
Остановка всплытия:
polygon.on('click', function (e) {
L.DomEvent.stopPropagation(e);
});
Позволяет управлять передачей событий вверх:
const circle = L.circle([51.5, -0.09], {
bubblingMouseEvents: false
});
При false события не поднимаются к карте.
Ключевые условия генерации событий:
interactive: trueСобытия часто используются для динамического изменения отображения:
const polyline = L.polyline([[51.5, -0.1], [51.51, -0.12]]).addTo(map);
polyline.on('mouseover', () => {
polyline.setStyle({ weight: 8 });
});
polyline.on('mouseout', () => {
polyline.setStyle({ weight: 3 });
});
Позволяет обрабатывать правый клик:
polygon.on('contextmenu', (e) => {
console.log('Контекстное меню', e.latlng);
});
События работают аналогично полигонам, но геометрия упрощена до радиуса:
L.circle([51.5, -0.09], { radius: 500 })
.on('click', (e) => {
console.log('Клик по кругу');
})
.addTo(map);
Эти слои генерируют события на всей длине/площади. При этом hit
detection зависит от параметров weight и
lineCap.
function handler(e) {
console.log('click');
}
polygon.on('click', handler);
polygon.off('click', handler);
Удаление критично при динамическом управлении слоями.
Можно отключить все события одного типа:
polygon.off('click');
Или все события слоя:
polygon.off();
События часто используются как триггеры для изменения состояния приложения:
let selected = null;
function selectLayer(layer) {
if (selected) {
selected.setStyle({ color: 'blue' });
}
selected = layer;
selected.setStyle({ color: 'green' });
}
geoLayer.eachLayer(layer => {
layer.on('click', () => selectLayer(layer));
});
При большом количестве векторных объектов важно учитывать:
GeoJSON + onEachFeaturemousemoveПри включённой опции draggable (через плагины или
расширения) возможны события:
dragstartdragdragendПример:
marker.on('dragend', (e) => {
console.log(e.target.getLatLng());
});