При работе с интерактивными картами значительная часть функциональности зависит от успешной загрузки различных компонентов: самой карты, тайлов, слоёв, геоданных и внешних ресурсов. Для контроля этих процессов в Leaflet предусмотрена развитая система событий загрузки.
События позволяют:
Большинство объектов Leaflet наследуются от класса
Evented, благодаря чему поддерживают механизм подписки на
события через методы:
on()
off()
once()
fire()
Пример подписки:
map.on('load', function () {
console.log('Карта загружена');
});
loadСобытие load является одним из наиболее часто
используемых событий загрузки.
Оно возникает после первой успешной инициализации карты и установки начального центра и масштаба.
const map = L.map('map');
map.on('load', function () {
console.log('Карта готова');
});
map.setView([55.751244, 37.618423], 10);
После выполнения setView() карта получает координаты и
уровень масштабирования, вслед за чем генерируется событие
load.
Часто некоторые действия необходимо выполнять только после полной инициализации карты:
map.on('load', function () {
L.marker([55.751244, 37.618423])
.addTo(map)
.bindPopup('Москва');
});
Без ожидания загрузки часть операций может выполняться раньше готовности интерфейса.
whenReady()Для определения готовности карты существует специальный метод
whenReady().
Он выполняет переданную функцию сразу после завершения начальной загрузки.
map.whenReady(function () {
console.log('Карта полностью готова');
});
Эквивалентное использование через стрелочную функцию:
map.whenReady(() => {
console.log('Готово');
});
loadСобытие:
map.on('load', callback);
и метод:
map.whenReady(callback);
очень похожи, однако whenReady() гарантирует выполнение
функции даже в том случае, если карта уже успела загрузиться к моменту
вызова метода.
Это делает его особенно удобным при работе с модульным кодом.
Большинство карт используют тайловые слои
(TileLayer).
Каждый слой загружает множество изображений с сервера.
const tiles = L.tileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
);
Для контроля процесса существуют специальные события.
loadingСобытие loading возникает в момент начала загрузки новых
тайлов.
tiles.on('loading', function () {
console.log('Началась загрузка');
});
Событие генерируется:
Пример отображения индикатора:
tiles.on('loading', function () {
document.getElementById('loader').style.display = 'block';
});
load для
тайлового слояПосле завершения загрузки всех необходимых тайлов генерируется
событие load.
tiles.on('load', function () {
console.log('Все тайлы загружены');
});
Скрытие индикатора загрузки:
tiles.on('load', function () {
document.getElementById('loader').style.display = 'none';
});
Полный пример:
tiles.on('loading', function () {
loader.style.display = 'block';
});
tiles.on('load', function () {
loader.style.display = 'none';
});
tileloadstartЕсли требуется контролировать загрузку каждого отдельного тайла,
используется событие tileloadstart.
tiles.on('tileloadstart', function (event) {
console.log('Начало загрузки тайла');
});
Объект события содержит информацию о загружаемом элементе.
tiles.on('tileloadstart', function (event) {
console.log(event.tile);
});
Свойство tile содержит DOM-элемент изображения.
tileloadПосле успешной загрузки конкретного тайла возникает событие
tileload.
tiles.on('tileload', function (event) {
console.log('Тайл загружен');
});
Получение адреса изображения:
tiles.on('tileload', function (event) {
console.log(event.tile.src);
});
Подобный механизм полезен для:
tileerrorВо время загрузки могут возникать ошибки.
Например:
Для обработки таких ситуаций применяется событие
tileerror.
tiles.on('tileerror', function (event) {
console.error('Ошибка загрузки тайла');
});
Получение информации об ошибке:
tiles.on('tileerror', function (event) {
console.log(event);
});
Пример замены проблемного изображения:
tiles.on('tileerror', function (event) {
event.tile.src = 'images/not-found.png';
});
tileabortИногда загрузка тайла прерывается ещё до завершения.
Причины:
Для таких случаев предусмотрено событие tileabort.
tiles.on('tileabort', function () {
console.log('Загрузка тайла отменена');
});
Это событие помогает более точно рассчитывать статистику загрузки.
Нередко требуется показать пользователю процент выполнения загрузки.
Простейшая реализация:
let loaded = 0;
let started = 0;
tiles.on('tileloadstart', function () {
started++;
});
tiles.on('tileload', function () {
loaded++;
const percent =
Math.round((loaded / started) * 100);
console.log(percent + '%');
});
Более точный вариант должен учитывать:
При работе с удалёнными наборами данных часто используется API браузера.
После получения данных создаётся слой GeoJSON.
fetch('/data/cities.geojson')
.then(response => response.json())
.then(data => {
L.geoJSON(data).addTo(map);
});
Хотя сам объект GeoJSON не выполняет сетевые запросы,
событие загрузки можно организовать через завершение запроса.
fetch('/data/cities.geojson')
.then(response => response.json())
.then(data => {
const layer = L.geoJSON(data);
layer.addTo(map);
console.log('GeoJSON загружен');
});
Leaflet предоставляет класс ImageOverlay.
const image = L.imageOverlay(
'image.png',
bounds
);
Для него доступны события загрузки изображения.
loadimage.on('load', function () {
console.log('Изображение загружено');
});
После появления изображения на карте обработчик будет вызван автоматически.
errorПри невозможности загрузить изображение возникает событие
error.
image.on('error', function () {
console.log('Ошибка загрузки изображения');
});
Пример:
image.on('error', function () {
alert('Файл недоступен');
});
Для видеооверлеев применяется аналогичный механизм.
const video = L.videoOverlay(
'movie.mp4',
bounds
);
Отслеживание загрузки:
video.on('load', function () {
console.log('Видео загружено');
});
Обработка ошибок:
video.on('error', function () {
console.log('Ошибка загрузки видео');
});
Иногда событие должно обработаться только один раз.
Для этого используется метод once().
tiles.once('load', function () {
console.log('Первое завершение загрузки');
});
После выполнения обработчик автоматически удаляется.
Это особенно удобно для:
При динамическом создании слоёв важно своевременно освобождать обработчики.
Удаление конкретной функции:
function onLoaded() {
console.log('Загружено');
}
tiles.on('load', onLoaded);
tiles.off('load', onLoaded);
Удаление всех обработчиков события:
tiles.off('load');
Удаление всех событий объекта:
tiles.off();
Типичный жизненный цикл тайлового слоя выглядит следующим образом:
loading
↓
tileloadstart
↓
tileload
↓
tileload
↓
tileload
↓
load
При ошибках возможны дополнительные события:
loading
↓
tileloadstart
↓
tileerror
↓
load
Либо:
loading
↓
tileloadstart
↓
tileabort
Понимание этой последовательности позволяет точно проектировать механизмы индикации загрузки и мониторинга состояния карты.
Практический пример:
const loader =
document.getElementById('loader');
tiles.on('loading', function () {
loader.classList.add('visible');
});
tiles.on('load', function () {
loader.classList.remove('visible');
});
CSS:
#loader {
display: none;
}
#loader.visible {
display: block;
}
Такой подход широко применяется в веб-ГИС, поскольку загрузка большого количества тайлов или пространственных данных может занимать заметное время.
В сложных приложениях карта может ожидать загрузки сразу нескольких ресурсов:
let mapReady = false;
let dataReady = false;
function checkReady() {
if (mapReady && dataReady) {
console.log('Все ресурсы готовы');
}
}
map.whenReady(function () {
mapReady = true;
checkReady();
});
fetch('/data.geojson')
.then(response => response.json())
.then(data => {
dataReady = true;
checkReady();
});
Подобная схема позволяет синхронизировать:
| Событие | Объект | Назначение |
|---|---|---|
load |
Map | Карта готова к работе |
loading |
TileLayer | Начало загрузки тайлов |
load |
TileLayer | Завершение загрузки всех тайлов |
tileloadstart |
TileLayer | Начало загрузки одного тайла |
tileload |
TileLayer | Успешная загрузка тайла |
tileerror |
TileLayer | Ошибка загрузки тайла |
tileabort |
TileLayer | Отмена загрузки тайла |
load |
ImageOverlay | Изображение загружено |
error |
ImageOverlay | Ошибка загрузки изображения |
load |
VideoOverlay | Видео загружено |
error |
VideoOverlay | Ошибка загрузки видео |
Система событий загрузки в Leaflet обеспечивает полный контроль над жизненным циклом карты и её ресурсов, позволяя строить надёжные интерфейсы, корректно реагирующие на состояние сетевых запросов, загрузку тайлов и получение пространственных данных.