Маркеры в Leaflet являются интерактивными слоями, которые тесно связаны с системой событий карты и DOM-событий. Каждый маркер представляет собой объект, способный реагировать на пользовательские действия, изменять своё состояние и передавать информацию о происходящих взаимодействиях через единый механизм событий.
Маркер в Leaflet наследует поведение от Evented, что
обеспечивает стандартный набор методов для работы с событиями:
on(type, handler, context?) — подписка на событиеoff(type, handler?) — удаление обработчикаonce(type, handler) — одноразовая подпискаfire(type, data?) — вызов события вручнуюКаждый маркер может одновременно обрабатывать несколько типов событий, а также иметь несколько обработчиков на одно событие.
Наиболее часто используемые события маркеров связаны с взаимодействием пользователя.
Срабатывает при клике по маркеру. Является базовым событием для интерактивных карт.
marker.on('click', function (e) {
console.log(e.latlng);
});
Объект события содержит координаты точки клика:
e.latlng — географические координатыe.target — сам маркерe.type — строка событияДвойной клик по маркеру. Часто используется для альтернативных действий, например, масштабирования или открытия расширенной информации.
marker.on('dblclick', function (e) {
map.setView(e.latlng, 14);
});
Используются для визуальной обратной связи при наведении курсора.
marker.on('mouseover', function () {
this.setOpacity(0.7);
});
marker.on('mouseout', function () {
this.setOpacity(1);
});
Эти события важны для UI-поведения: подсветка, отображение подсказок, изменение иконки.
Срабатывает при правом клике. Позволяет реализовать контекстные меню.
marker.on('contextmenu', function (e) {
console.log('Контекстное меню', e.latlng);
});
При включении опции draggable: true маркер становится
перемещаемым и начинает генерировать дополнительные события.
const marker = L.marker([51.5, -0.09], {
draggable: true
}).addTo(map);
Срабатывает в момент начала перетаскивания.
marker.on('dragstart', function () {
console.log('Перетаскивание началось');
});
Срабатывает во время движения маркера.
marker.on('drag', function (e) {
console.log(e.target.getLatLng());
});
Это событие может вызываться десятки раз в секунду, поэтому тяжёлые вычисления внутри него нежелательны.
Срабатывает после завершения перемещения.
marker.on('dragend', function (e) {
const position = e.target.getLatLng();
console.log('Новая позиция:', position);
});
Маркер также может реагировать на изменения координат, даже если они происходят программно.
Срабатывает при любом изменении положения маркера.
marker.on('move', function (e) {
console.log('Маркер перемещён');
});
Срабатывает после завершения перемещения (аналогично dragend, но включает программные изменения).
marker.on('moveend', function () {
console.log('Перемещение завершено');
});
Маркер может автоматически управлять всплывающими элементами, которые также генерируют события.
Срабатывает при открытии всплывающего окна.
marker.on('popupopen', function () {
console.log('Popup открыт');
});
Срабатывает при закрытии всплывающего окна.
marker.on('popupclose', function () {
console.log('Popup закрыт');
});
Аналогичные события для подсказок:
marker.on('tooltipopen', function () {
console.log('Tooltip открыт');
});
Все события маркера имеют единый формат объекта события, расширенный в зависимости от типа действия.
Общие поля:
type — тип событияtarget — объект маркераlatlng — географические координаты (для событий
мыши)layerPoint — координаты относительно слояcontainerPoint — координаты относительно контейнера
картыЭта унификация позволяет использовать единые обработчики для разных типов взаимодействий.
В Leaflet значение this внутри обработчика события
обычно указывает на объект, к которому привязано событие. Для маркера
это сам экземпляр L.Marker.
marker.on('click', function () {
this.openPopup();
});
Также можно явно задать контекст:
marker.on('click', function () {
console.log(this.id);
}, customContext);
Корректное управление подписками критично для предотвращения утечек памяти.
function onClick(e) {
console.log(e.latlng);
}
marker.on('click', onClick);
marker.off('click', onClick);
marker.off('click');
marker.off();
Метод once позволяет обработать событие только один
раз.
marker.once('click', function () {
console.log('Сработает только один раз');
});
После первого вызова обработчик автоматически удаляется.
События маркера могут взаимодействовать с событиями карты. Например, клик по маркеру может также вызывать клик по карте, если не остановить распространение события.
marker.on('click', function (e) {
L.DomEvent.stopPropagation(e);
});
Механизм распространения событий позволяет строить сложные иерархии взаимодействий между слоями.
Маркер может генерировать собственные события через
fire.
marker.fire('customEvent', {
data: 'value'
});
И обработка:
marker.on('customEvent', function (e) {
console.log(e.data);
});
Это используется для интеграции маркеров с внешними системами состояния.
События mousemove, drag и move
могут генерироваться с высокой частотой. При большом количестве маркеров
это становится критическим фактором производительности.
Типичные подходы оптимизации:
offМаркер в Leaflet представлен DOM-элементом, поэтому часть событий фактически является обёрткой над DOM-событиями. Это объясняет поведение hover, click и contextmenu.
При кастомных иконках:
const icon = L.icon({
iconUrl: 'icon.png',
iconSize: [32, 32]
});
const marker = L.marker([51.5, -0.09], { icon }).addTo(map);
События остаются теми же, независимо от визуального представления.
При динамическом изменении состояния маркера (перемещение, изменение иконки, привязка popups) Leaflet гарантирует сохранение корректного порядка событий:
Эта последовательность позволяет строить предсказуемую логику взаимодействия даже при сложных сценариях обновления данных.