В Leaflet анимация встроена в ядро работы карты и прежде всего касается переходов между состояниями вида. Основные методы, управляющие плавностью перемещения:
Ключевой параметр — animate: true, который включает
интерполяцию движения камеры.
map.setView([55.751244, 37.618423], 10, {
animate: true,
duration: 1.5
});
Параметр duration задаёт время анимации в секундах, а
Leaflet самостоятельно рассчитывает траекторию перемещения.
Метод flyTo добавляет нелинейную динамику: сначала
ускорение, затем замедление, создавая эффект «полёта» над картой.
map.flyTo([55.751244, 37.618423], 12, {
duration: 2
});
Зумирование в Leaflet также анимируется через интерполяцию уровней масштабирования тайлов и геометрии слоёв.
Основные параметры:
zoomAnimation: true — включает анимацию зумаzoomSnap — шаг дискретизации зумаzoomDelta — изменение зума при колесике мышиconst map = L.map('map', {
zoomAnimation: true,
zoomSnap: 0.5,
zoomDelta: 1
});
При включённой анимации происходит плавное масштабирование тайлов и перерасчёт координат слоёв.
Стандартный объект L.Marker не поддерживает физическую
анимацию движения между точками, но обновление позиции можно визуально
сгладить через частые изменения координат.
marker.setLatLng([55.75, 37.61]);
Однако для плавного движения применяются дополнительные подходы:
requestAnimationFrameПример ручной интерполяции:
function animateMarker(marker, from, to, duration) {
const start = performance.now();
function frame(time) {
const t = Math.min(1, (time - start) / duration);
const lat = from[0] + (to[0] - from[0]) * t;
const lng = from[1] + (to[1] - from[1]) * t;
marker.setLatLng([lat, lng]);
if (t < 1) requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
Слои вроде L.Circle, L.Polygon,
L.Polyline можно анимировать через изменение их геометрии
или стилей.
circle.setRadius(1000);
Для плавного изменения используется интерполяция:
function animateCircle(circle, fromR, toR, duration) {
const start = performance.now();
function step(time) {
const t = Math.min(1, (time - start) / duration);
const radius = fromR + (toR - fromR) * t;
circle.setRadius(radius);
if (t < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
Изменение формы полигона достигается обновлением массива координат:
polygon.setLatLngs(newLatLngs);
При частом обновлении создаётся эффект морфинга формы.
Leaflet использует CSS для части визуальных эффектов, особенно для
DOM-слоёв (DivIcon, Popup,
Tooltip).
Для попапов и тултипов применяются CSS transition:
.leaflet-popup {
opacity: 0;
transition: opacity 0.3s ease;
}
.leaflet-popup.leaflet-zoom-animated {
opacity: 1;
}
L.DivIcon позволяет полностью управлять DOM-элементом
маркера, включая CSS-анимации.
const icon = L.divIcon({
className: 'custom-marker',
html: '<div class="pulse"></div>'
});
CSS-пульсация:
.pulse {
width: 20px;
height: 20px;
background: red;
border-radius: 50%;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(2);
opacity: 0;
}
}
При изменении размеров контейнера или данных карты используется:
map.invalidateSize();
Хотя метод не является анимацией напрямую, его часто комбинируют с CSS transition контейнера карты для плавного ресайза.
Тайлы в Leaflet загружаются с постепенным появлением, что создаёт эффект мягкой подгрузки карты. Это управляется опцией:
const map = L.map('map', {
fadeAnimation: true,
zoomAnimation: true
});
При включённом fadeAnimation новые тайлы плавно
проявляются вместо резкого появления.
Основные параметры, влияющие на всю систему анимации:
zoomAnimationfadeAnimationmarkerZoomAnimationtrackResizeconst map = L.map('map', {
zoomAnimation: true,
fadeAnimation: true,
markerZoomAnimation: true
});
При большом количестве анимированных объектов важно учитывать нагрузку:
setLatLng создают перерасчёт
проекцииDivIcon быстрее, чем
Canvas-перерисовка на каждом кадреДля оптимизации используется:
requestAnimationFrameL.LayerGroup для пакетных измененийmap.options.zoomAnimation = false;
map.options.fadeAnimation = false;
Для движения объектов по маршрутам используется интерполяция между точками линии:
function interpolatePath(path, t) {
const index = Math.floor(t * (path.length - 1));
return path[index];
}
Более точные реализации используют расстояния между точками и
нормализацию по длине пути, что позволяет добиться равномерного движения
вдоль Polyline.
При работе с большим количеством объектов применяется Canvas-слой:
const map = L.map('map', {
preferCanvas: true
});
Canvas снижает нагрузку при частых обновлениях координат, поскольку перерисовывается один слой вместо множества DOM-элементов.
На практике анимации часто комбинируются:
flyTo)Синхронизация достигается через единый таймлайн на
requestAnimationFrame, где все изменения рассчитываются в
одном цикле обновления.