Анимация в deck.gl строится вокруг непрерывного пересчёта состояния сцены и повторного рендеринга WebGL-контекста, при котором изменения параметров слоёв, камеры и атрибутов геометрии интерпретируются как временные переходы между состояниями. Основой служит модель декларативного описания сцены: визуализация задаётся как функция от props, а анимация становится результатом изменения этих props во времени.
В основе работы deck.gl лежит цикл, синхронизированный с
requestAnimationFrame. Каждый кадр включает:
viewStatelayers)Ключевая особенность заключается в том, что библиотека не хранит «анимацию» как отдельную сущность. Вместо этого любое изменение входных данных интерпретируется как потенциальный переход состояния.
import {Deck} from '@deck.gl/core';
import {ScatterplotLayer} from '@deck.gl/layers';
const deckgl = new Deck({
initialViewState: {
longitude: 0,
latitude: 0,
zoom: 2
},
controller: true,
layers: []
});
Рендер-цикл активируется автоматически при изменении props или интерактивных событий камеры. Это создаёт основу для анимации без необходимости явного управления кадрами.
Любая анимация возникает из последовательного изменения входных данных. Например, изменение координат слоя приводит к плавному перемещению объектов при включённой интерполяции.
setInterval(() => {
deckgl.setProps({
layers: [
new ScatterplotLayer({
id: 'points',
data: [{position: [Math.random() * 360 - 180, 0]}],
getPosition: d => d.position,
getRadius: 100000
})
]
});
}, 1000);
При каждом обновлении setProps происходит пересборка
слоя и оценка необходимости анимационного перехода. Важно, что сам
механизм не зависит от таймера — он зависит от изменения состояния.
Плавность анимации достигается через интерполяцию значений атрибутов.
В deck.gl это реализовано на уровне слоя через
transitions.
new ScatterplotLayer({
id: 'animated-points',
data,
getPosition: d => d.position,
getRadius: d => d.radius,
transitions: {
getPosition: 500,
getRadius: 500
}
});
Каждое свойство, указанное в transitions, становится
объектом временной интерполяции. При изменении входных данных
система:
Математически процесс можно представить как линейную интерполяцию:
[ v(t) = v_0 + (v_1 - v_0) ]
где () — нормализованное время перехода.
Система переходов управляется внутренним таймером, синхронизированным с рендер-циклом. Каждое изменение props инициирует новый transition state.
Основные характеристики:
Пример изменения нескольких свойств одновременно:
new PolygonLayer({
id: 'polygons',
data,
getPolygon: d => d.coordinates,
getFillColor: d => d.color,
transitions: {
getPolygon: 800,
getFillColor: 1200
}
});
Разные длительности создают асинхронную динамику визуальных изменений.
Анимация в deck.gl не ограничивается слоями. Изменение
viewState также является источником временной динамики.
Камера описывается как набор параметров:
Изменение этих параметров может быть интерполировано аналогично атрибутам слоёв.
deckgl.setProps({
viewState: {
longitude: 30,
latitude: 50,
zoom: 5,
transitionDuration: 1000,
transitionInterpolator: new FlyToInterpolator()
}
});
FlyToInterpolator реализует нелинейную траекторию
движения камеры, учитывающую масштаб и географическое расстояние, что
делает переход визуально стабильным.
Каждый слой в deck.gl компилируется в набор WebGL атрибутов. Анимация на низком уровне сводится к обновлению буферов GPU.
Процесс включает:
В высокопроизводительных сценариях используется attribute updater, минимизирующий пересоздание буферов.
Помимо дискретных переходов, deck.gl поддерживает непрерывную анимацию через внешний цикл обновления состояния.
function animate() {
const time = Date.now() * 0.001;
deckgl.setProps({
layers: [
new ScatterplotLayer({
id: 'wave',
data,
getPosition: d => [
d.base[0],
d.base[1] + Math.sin(time + d.phase) * 5
],
getRadius: 50000
})
]
});
requestAnimationFrame(animate);
}
animate();
В этом режиме система работает как функция времени, где каждый кадр полностью пересчитывает визуальное состояние.
В сложных сценах одновременно активны:
requestAnimationFrame обновленияdeck.gl объединяет эти источники в единый render pass. Приоритет обновления определяется изменениями props, а не источником их происхождения.
Ключевой механизм оптимизации — сравнение предыдущего и текущего состояния слоя. Если данные не изменились, рендер не инициируется. Если изменились только отдельные поля, пересчитываются только затронутые атрибуты.
Это создаёт эффект:
Анимация не ограничивается линейной интерполяцией. Поддерживаются easing-функции, влияющие на скорость изменения параметров во времени.
Типовые функции:
Применение:
transitions: {
getPosition: {
duration: 1000,
easing: t => t * t * (3 - 2 * t)
}
}
Такие функции формируют ускорение и замедление движения, влияя на восприятие глубины и динамики сцены.
При работе с тысячами и миллионами объектов ключевым становится перенос вычислений в GPU. В deck.gl анимация часто реализуется через:
Shader-based подход позволяет выполнять интерполяцию параллельно для всех вершин:
float t = uniformProgress;
vec3 position = mix(positionStart, positionEnd, t);
Это обеспечивает масштабируемость без значительного роста CPU-нагрузки.
Фундаментальная модель может быть выражена как:
[ Layer(t) = f(Data(t), ViewState(t))]
где каждый кадр является вычислением функции от текущего времени. deck.gl не хранит «анимацию» как объект, а вычисляет её как производную состояния сцены.
Механизм обновления props фактически является реактивной системой. Любое изменение данных запускает пересборку графа слоёв. В этом контексте анимация возникает как побочный эффект реактивности:
Так формируется непрерывное визуальное движение без явного управления кадрами.