Анимация камеры

Камера в Mapbox GL JS определяет положение наблюдателя относительно карты и отвечает за отображаемую область, масштаб, наклон и ориентацию. Анимация камеры позволяет плавно изменять эти параметры, создавая эффект перемещения по карте без резких скачков.

Камера управляет следующими характеристиками:

  • center — координаты центра карты;
  • zoom — уровень масштабирования;
  • bearing — угол поворота карты;
  • pitch — угол наклона;
  • padding — внутренние отступы отображаемой области.

Анимация камеры используется для:

  • перехода между локациями;
  • демонстрации маршрутов;
  • фокусировки на выбранном объекте;
  • создания интерактивных презентаций;
  • построения навигационных интерфейсов;
  • визуализации пространственных данных.

Основные методы анимации

Mapbox GL JS предоставляет несколько способов изменения положения камеры.

jumpTo()

Метод выполняет мгновенное перемещение без анимации.

map.jumpTo({
    center: [37.6176, 55.7558],
    zoom: 12
});

Особенности:

  • отсутствует плавный переход;
  • выполняется максимально быстро;
  • подходит для технических операций и начальной настройки карты.

easeTo()

Создаёт плавное перемещение между двумя состояниями камеры.

map.easeTo({
    center: [37.6176, 55.7558],
    zoom: 12,
    duration: 3000
});

Переход выполняется с использованием функции сглаживания, благодаря чему движение выглядит естественно.


flyTo()

Имитирует полёт над картой.

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 12
});

В отличие от easeTo(), данный метод изменяет не только положение, но и траекторию движения камеры, создавая эффект приближения и удаления во время перелёта.


fitBounds()

Автоматически подбирает положение камеры так, чтобы заданная область полностью помещалась в окне карты.

map.fitBounds([
    [37.5, 55.7],
    [37.8, 55.9]
]);

По умолчанию переход анимируется.


Плавное перемещение с easeTo()

Метод easeTo() является наиболее универсальным инструментом анимации.

Изменение центра карты

map.easeTo({
    center: [30.3141, 59.9386],
    duration: 2000
});

Камера плавно переместится к Санкт-Петербургу за две секунды.


Изменение масштаба

map.easeTo({
    zoom: 14,
    duration: 1500
});

Анимация затрагивает только уровень приближения.


Одновременное изменение нескольких параметров

map.easeTo({
    center: [30.3141, 59.9386],
    zoom: 14,
    pitch: 60,
    bearing: 45,
    duration: 4000
});

В процессе анимации изменяются:

  • положение;
  • масштаб;
  • угол наклона;
  • ориентация карты.

Настройка продолжительности

Параметр duration задаётся в миллисекундах.

map.easeTo({
    center: [30.3141, 59.9386],
    duration: 5000
});

Значение:

1000 = 1 секунда
3000 = 3 секунды
5000 = 5 секунд

Чрезмерно длинные анимации могут ухудшать пользовательский опыт, поэтому обычно используют диапазон от 500 до 3000 миллисекунд.


Функция сглаживания

Mapbox GL JS позволяет настраивать характер движения камеры через параметр easing.

Функция получает число от 0 до 1 и возвращает преобразованное значение.

Пример линейного движения:

map.easeTo({
    center: [37.6176, 55.7558],
    duration: 3000,
    easing: t => t
});

Замедление в конце

map.easeTo({
    center: [37.6176, 55.7558],
    duration: 3000,
    easing: t => 1 - Math.pow(1 - t, 3)
});

Визуально камера быстро стартует и плавно останавливается.


Плавный старт и остановка

map.easeTo({
    center: [37.6176, 55.7558],
    duration: 3000,
    easing: t => {
        return t < 0.5
            ? 4 * t * t * t
            : 1 - Math.pow(-2 * t + 2, 3) / 2;
    }
});

Подобные кривые часто используются в интерфейсной анимации.


Анимация полёта с flyTo()

Метод flyTo() реализует кинематографическое перемещение камеры.

Базовый пример

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 12
});

Пользователь наблюдает виртуальный перелёт между текущей и целевой точкой.


Полёт с наклоном

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 15,
    pitch: 70
});

Получается эффект пролёта над городом.


Полёт с поворотом

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 15,
    bearing: 180
});

Во время движения карта дополнительно вращается.


Параметры flyTo()

speed

Определяет скорость перелёта.

map.flyTo({
    center: [37.6176, 55.7558],
    speed: 0.8
});

Стандартное значение обычно находится около единицы.


curve

Управляет кривизной траектории.

map.flyTo({
    center: [37.6176, 55.7558],
    curve: 1.8
});

Чем больше значение, тем более выраженным становится эффект воздушного полёта.


essential

Используется для поддержки системных настроек доступности.

map.flyTo({
    center: [37.6176, 55.7558],
    essential: true
});

Если анимация критически важна для интерфейса, рекомендуется явно указывать этот параметр.


Управление наклоном карты

Трёхмерные сцены особенно выигрышно смотрятся в сочетании с анимацией камеры.

Изменение pitch

map.easeTo({
    pitch: 60,
    duration: 2000
});

Наклон постепенно увеличивается до 60 градусов.


Возврат к виду сверху

map.easeTo({
    pitch: 0,
    duration: 2000
});

Камера возвращается в классический режим.


Анимация наклона и приближения

map.easeTo({
    zoom: 16,
    pitch: 75,
    duration: 3000
});

Часто применяется для просмотра 3D-зданий.


Управление поворотом карты

Параметр bearing задаёт направление взгляда.

Поворот на 90 градусов

map.easeTo({
    bearing: 90,
    duration: 2000
});

Полный разворот

map.easeTo({
    bearing: 180,
    duration: 3000
});

Постепенное вращение

map.easeTo({
    bearing: map.getBearing() + 45,
    duration: 1000
});

Каждый вызов поворачивает карту ещё на 45 градусов.


Непрерывное вращение карты

Для создания автоматической анимации используется цикл.

function rotateCamera(timestamp) {
    map.rotateTo(
        (timestamp / 100) % 360,
        {
            duration: 0
        }
    );

    requestAnimationFrame(rotateCamera);
}

requestAnimationFrame(rotateCamera);

Применение:

  • демонстрационные стенды;
  • презентации проектов;
  • визуализация 3D-моделей;
  • интерактивные витрины.

Анимация через rotateTo()

Для вращения существует специализированный метод.

map.rotateTo(180, {
    duration: 3000
});

Преимущества:

  • более явное назначение;
  • удобство работы с углом поворота;
  • повышенная читаемость кода.

Анимация через zoomTo()

Для изменения масштаба можно использовать отдельный метод.

map.zoomTo(14, {
    duration: 2000
});

Эквивалентно:

map.easeTo({
    zoom: 14,
    duration: 2000
});

Анимация через panTo()

Перемещает карту к новым координатам.

map.panTo(
    [37.6176, 55.7558],
    {
        duration: 2000
    }
);

Подходит для случаев, когда требуется изменить только центр карты.


Использование событий анимации

Mapbox GL JS генерирует события в процессе движения камеры.

movestart

Срабатывает при начале перемещения.

map.on('movestart', () => {
    console.log('Начало движения');
});

move

Вызывается во время движения.

map.on('move', () => {
    console.log(map.getCenter());
});

Используется для синхронизации интерфейса с положением камеры.


moveend

Срабатывает после завершения анимации.

map.on('moveend', () => {
    console.log('Перемещение завершено');
});

zoomstart и zoomend

map.on('zoomstart', () => {
    console.log('Начало масштабирования');
});

map.on('zoomend', () => {
    console.log('Масштабирование завершено');
});

Последовательность анимаций

Несколько переходов можно выполнять поочерёдно.

map.flyTo({
    center: [37.6176, 55.7558],
    zoom: 10,
    duration: 3000
});

map.once('moveend', () => {

    map.easeTo({
        zoom: 15,
        pitch: 60,
        duration: 2000
    });

});

После завершения перелёта начинается вторая анимация.


Создание экскурсии по карте

Распространённый сценарий — автоматический тур по нескольким точкам.

const locations = [
    [37.6176, 55.7558],
    [30.3141, 59.9386],
    [49.1064, 55.7961]
];

let index = 0;

function showNextLocation() {

    map.flyTo({
        center: locations[index],
        zoom: 12,
        duration: 4000
    });

    index = (index + 1) % locations.length;

    map.once('moveend', () => {
        setTimeout(showNextLocation, 1000);
    });
}

showNextLocation();

Подобная схема используется для:

  • презентаций;
  • туристических сервисов;
  • аналитических панелей;
  • информационных киосков.

Анимация к выбранному объекту

После клика по маркеру камера может автоматически фокусироваться на объекте.

marker.getElement().addEventListener('click', () => {

    map.flyTo({
        center: marker.getLngLat(),
        zoom: 16,
        pitch: 60,
        duration: 2500
    });

});

Такой подход делает навигацию по карте более наглядной.


Работа с fitBounds()

Метод особенно полезен при отображении нескольких объектов.

const bounds = [
    [37.55, 55.70],
    [37.75, 55.85]
];

map.fitBounds(bounds, {
    padding: 50,
    duration: 2000
});

Параметр padding создаёт внутренние отступы между границами области и краями карты.


Анимация с учётом интерфейсных панелей

Если часть карты перекрывается боковой панелью, используется параметр padding.

map.easeTo({
    center: [37.6176, 55.7558],
    padding: {
        left: 400,
        top: 20,
        right: 20,
        bottom: 20
    },
    duration: 2000
});

Карта автоматически смещает объект интереса в видимую область.


Отмена текущей анимации

Любое новое движение камеры прерывает предыдущее.

map.flyTo({
    center: [37.6176, 55.7558],
    duration: 10000
});

setTimeout(() => {

    map.jumpTo({
        center: [30.3141, 59.9386]
    });

}, 2000);

Через две секунды выполняется немедленный переход, который прекращает активный перелёт.


Практические рекомендации

Использование easeTo()

Наиболее подходит для:

  • пользовательских действий;
  • перемещения между близкими точками;
  • локальных изменений масштаба;
  • изменения наклона и ориентации.

Использование flyTo()

Наиболее эффективно для:

  • больших расстояний;
  • демонстрационных режимов;
  • туристических приложений;
  • визуальных презентаций данных.

Ограничение длительности

Оптимальными считаются значения:

300–700 мс   — интерфейсные переходы
1000–2500 мс — навигация
3000–5000 мс — презентационные перелёты

Избегание чрезмерного движения

Частые вращения, сильный наклон и длинные перелёты способны ухудшать восприятие карты. В рабочих интерфейсах обычно используются умеренные значения:

zoom: 12-16
pitch: 30-60
bearing: 0-45

Такой диапазон обеспечивает хороший баланс между информативностью, производительностью и визуальной привлекательностью анимации камеры в Mapbox GL JS.