В интерактивных картографических приложениях пользователь постоянно изменяет положение карты: перетаскивает её мышью, перемещает пальцем на сенсорных устройствах, программно изменяет центр карты или выполняет анимационный переход к другой области. Для отслеживания подобных действий в Leaflet предусмотрен набор специальных событий перемещения.
События перемещения позволяют:
Основными событиями являются:
movestartmovemoveenddragstartdragdragendКаждое из них решает собственную задачу и применяется в различных сценариях.
Событие movestart возникает в момент начала любого
перемещения карты.
Причинами его возникновения могут быть:
setView();panTo();Пример:
map.on('movestart', function () {
console.log('Началось перемещение карты');
});
При запуске этого обработчика карта ещё не изменила своё положение окончательно, однако процесс движения уже начался.
Часто событие используется для:
Например:
map.on('movestart', function () {
document.getElementById('status').textContent =
'Загрузка данных...';
});
Событие move генерируется непрерывно во время
перемещения карты.
Это наиболее часто вызываемое событие среди всех событий движения.
Пример:
map.on('move', function () {
console.log('Карта перемещается');
});
Во время одного перетаскивания событие может возникать десятки или сотни раз.
Получение текущего центра карты:
map.on('move', function () {
const center = map.getCenter();
console.log(center.lat, center.lng);
});
Такой подход позволяет в режиме реального времени отображать координаты текущего центра.
Пример обновления интерфейса:
map.on('move', function () {
const center = map.getCenter();
document.getElementById('lat').textContent =
center.lat.toFixed(6);
document.getElementById('lng').textContent =
center.lng.toFixed(6);
});
Поскольку событие вызывается очень часто, внутри обработчика нежелательно размещать тяжёлые операции.
Плохой пример:
map.on('move', function () {
loadThousandsOfObjects();
});
Во время движения такой код может значительно снизить производительность.
Более правильный вариант:
map.on('moveend', function () {
loadThousandsOfObjects();
});
Событие move лучше использовать для:
Событие moveend возникает после полного завершения
перемещения карты.
Пример:
map.on('moveend', function () {
console.log('Перемещение завершено');
});
Это одно из наиболее важных событий в Leaflet.
Обычно именно здесь выполняются:
Получение текущих границ карты:
map.on('moveend', function () {
const bounds = map.getBounds();
console.log(bounds);
});
Распространённый сценарий — загрузка объектов только для текущей видимой области.
Пример:
map.on('moveend', function () {
const bounds = map.getBounds();
fetch(`/api/points?bbox=${
bounds.toBBoxString()
}`)
.then(response => response.json())
.then(data => {
console.log(data);
});
});
В данном случае запрос выполняется только после завершения движения карты.
Такой подход уменьшает:
После завершения перемещения часто требуется узнать новый центр карты.
Пример:
map.on('moveend', function () {
const center = map.getCenter();
console.log(
'Широта:',
center.lat
);
console.log(
'Долгота:',
center.lng
);
});
Метод getCenter() возвращает объект
LatLng.
Доступные свойства:
center.lat
center.lng
Событие dragstart относится исключительно к ручному
перетаскиванию карты пользователем.
Пример:
map.on('dragstart', function () {
console.log('Началось перетаскивание');
});
Важно понимать разницу между событиями:
| Событие | Когда возникает |
|---|---|
movestart |
Любое начало перемещения |
dragstart |
Начало ручного перетаскивания |
Если карта была перемещена через код:
map.panTo([55.75, 37.61]);
то:
movestart → да
dragstart → нет
Событие drag возникает непрерывно во время ручного
перемещения карты.
Пример:
map.on('drag', function () {
console.log('Карта перетаскивается');
});
Срабатывание происходит только при взаимодействии пользователя.
Программные изменения положения карты это событие не вызывают.
Получение координат центра:
map.on('drag', function () {
const center = map.getCenter();
console.log(center);
});
Событие dragend возникает после завершения ручного
перетаскивания.
Пример:
map.on('dragend', function () {
console.log('Перетаскивание завершено');
});
Типичная область применения:
Например:
map.on('dragend', function () {
const center = map.getCenter();
localStorage.setItem(
'mapLat',
center.lat
);
localStorage.setItem(
'mapLng',
center.lng
);
});
Во время обычного ручного перемещения карта генерирует события в следующем порядке:
dragstart
movestart
drag
move
drag
move
drag
move
...
dragend
moveend
Таким образом:
drag* описывают действия пользователя;move* описывают изменение положения карты вообще.Метод panTo() выполняет плавный переход к новым
координатам.
Пример:
map.panTo([59.9386, 30.3141]);
При этом будут вызваны:
movestart
move
move
move
...
moveend
События перетаскивания отсутствуют.
Метод setView() изменяет центр карты.
Пример:
map.setView(
[48.8566, 2.3522],
12
);
Если происходит изменение положения карты, Leaflet генерирует события движения.
Например:
map.on('moveend', function () {
console.log('Центр обновлён');
});
После каждого завершённого перемещения можно получать текущие границы карты.
Пример:
map.on('moveend', function () {
const bounds =
map.getBounds();
const north =
bounds.getNorth();
const south =
bounds.getSouth();
const east =
bounds.getEast();
const west =
bounds.getWest();
console.log(
north,
south,
east,
west
);
});
Подобный подход широко применяется в:
Иногда требуется, чтобы одна карта повторяла движения другой.
Пример:
map1.on('move', function () {
map2.setView(
map1.getCenter(),
map1.getZoom(),
{
animate: false
}
);
});
Более безопасный вариант использует флаг блокировки:
let syncing = false;
map1.on('move', function () {
if (syncing) return;
syncing = true;
map2.setView(
map1.getCenter(),
map1.getZoom(),
{
animate: false
}
);
syncing = false;
});
Без такой проверки возможно возникновение бесконечного цикла событий.
Часто необходимо восстанавливать положение карты после перезагрузки страницы.
Сохранение:
map.on('moveend', function () {
const center =
map.getCenter();
localStorage.setItem(
'lat',
center.lat
);
localStorage.setItem(
'lng',
center.lng
);
localStorage.setItem(
'zoom',
map.getZoom()
);
});
Восстановление:
const lat =
localStorage.getItem('lat');
const lng =
localStorage.getItem('lng');
const zoom =
localStorage.getItem('zoom');
if (lat && lng && zoom) {
map.setView(
[lat, lng],
zoom
);
}
Несколько событий могут использоваться одновременно.
Пример:
map.on('movestart', function () {
console.log('Старт');
});
map.on('move', function () {
console.log('Движение');
});
map.on('moveend', function () {
console.log('Финиш');
});
Результат:
Старт
Движение
Движение
Движение
Движение
Финиш
Подобная схема позволяет реализовать полный контроль над жизненным циклом перемещения карты.
Для прекращения отслеживания событий используется метод
off().
Пример:
function onMove() {
console.log('move');
}
map.on('move', onMove);
Удаление:
map.off('move', onMove);
Удаление всех обработчиков конкретного события:
map.off('move');
Удаление всех событий объекта карты:
map.off();
Событие move
Подходит для:
Не рекомендуется для:
Событие moveend
Подходит для:
События dragstart, drag,
dragend
Используются тогда, когда необходимо реагировать именно на действия пользователя, а не на любые изменения положения карты.
События movestart, move,
moveend
Используются для отслеживания всех вариантов перемещения независимо от того, были они инициированы пользователем или программным кодом.