Множественные свойства в Popmotion представляют собой модель анимации, в которой изменяется не одно числовое значение, а целый набор параметров объекта одновременно. Такая форма используется для управления положением, размером, цветом, прозрачностью и любыми другими стилевыми или пользовательскими параметрами в рамках одной анимации.
В основе лежит объектная интерполяция: вместо передачи единственного
значения для анимации задаются структуры вида from и
to, содержащие несколько ключей. Каждый ключ
интерполируется независимо, но синхронно по общему таймингу
анимации.
Базовая форма анимации множественных свойств строится вокруг объекта:
import { animate } from 'popmotion';
animate({
from: {
x: 0,
y: 0,
opacity: 0
},
to: {
x: 300,
y: 150,
opacity: 1
},
duration: 800
});
В данной конфигурации каждое свойство обрабатывается как независимая шкала интерполяции:
x изменяется от 0 до 300y изменяется от 0 до 150opacity изменяется от 0 до 1Popmotion синхронизирует прогресс анимации между всеми ключами, используя единый временной контекст. Это позволяет гарантировать, что все изменения происходят согласованно по фазам easing-функции.
Каждое свойство внутри объекта получает одинаковое значение прогресса
t, вычисляемое из временной функции анимации. Затем
применяется линейная или нелинейная интерполяция:
value = start + (end - start) * easing(t)
Для множественных свойств этот процесс повторяется для каждого ключа
независимо, но с общим t.
Такой подход исключает рассинхронизацию координат и визуальных параметров при сложных трансформациях.
В большинстве практических сценариев множественные свойства
применяются через styler, который агрегирует обновления
DOM-элементов.
import { animate, styler } from 'popmotion';
const element = document.querySelector('.box');
const boxStyler = styler(element);
animate({
from: {
x: 0,
y: 0,
scale: 0.5
},
to: {
x: 400,
y: 200,
scale: 1
},
duration: 600,
onUpdate: (latest) => {
boxStyler.set(latest);
}
});
Метод set принимает объект и обновляет сразу несколько
CSS-трансформаций или свойств. Это снижает количество операций с DOM и
предотвращает промежуточные перерисовки.
При необходимости более тонкого контроля применяется явная деструктуризация значений:
animate({
from: { x: 0, y: 0 },
to: { x: 300, y: 300 },
onUpdate: ({ x, y }) => {
element.style.transform = `translate(${x}px, ${y}px)`;
}
});
Такой подход позволяет:
Множественные свойства не ограничены числами. Поддерживаются строки, цвета и сложные структуры, если для них предусмотрена интерполяция.
animate({
from: {
background: 'rgb(0, 0, 0)',
color: '#ffffff'
},
to: {
background: 'rgb(255, 100, 50)',
color: '#000000'
},
duration: 1000,
onUpdate: (v) => {
element.style.background = v.background;
element.style.color = v.color;
}
});
Интерполяция цветов выполняется поканально (R, G, B), что обеспечивает плавный переход без скачков.
Частый сценарий — комбинирование геометрических и визуальных параметров:
animate({
from: {
x: 0,
y: 0,
rotate: 0,
scale: 0.8,
opacity: 0
},
to: {
x: 500,
y: 200,
rotate: 180,
scale: 1,
opacity: 1
},
duration: 900,
onUpdate: (v) => {
element.style.transform =
`translate(${v.x}px, ${v.y}px) rotate(${v.rotate}deg) scale(${v.scale})`;
element.style.opacity = v.opacity;
}
});
Здесь наблюдается разделение ответственности:
transformПри работе с объектами допускается неполное определение значений. Отсутствующие ключи не участвуют в интерполяции.
animate({
from: { x: 0, y: 0 },
to: { x: 300, y: 0 },
onUpdate: (v) => {
boxStyler.set({
x: v.x
});
}
});
В таком случае только x подвергается изменению, а
остальные свойства остаются неизменными. Это полезно для каскадных
анимаций, где разные параметры управляются разными процессами.
При увеличении количества параметров возникает необходимость структурирования обновлений. Множественные свойства часто группируются по смысловым блокам:
x, yscale, rotateopacity, filterprogress,
stateanimate({
from: {
x: 0,
y: 0,
scale: 0.5,
blur: 10,
progress: 0
},
to: {
x: 200,
y: 100,
scale: 1,
blur: 0,
progress: 1
},
onUpdate: (v) => {
element.style.transform =
`translate(${v.x}px, ${v.y}px) scale(${v.scale})`;
element.style.filter = `blur(${v.blur}px)`;
element.dataset.progress = v.progress;
}
});
Такая структура позволяет рассматривать анимацию как набор параллельных временных функций, объединённых общим источником времени.
Обновление нескольких свойств в одном onUpdate снижает
количество вызовов рендера. Вместо множества операций применяется единая
точка синхронизации:
Особенно заметен эффект при использовании styler,
который оптимизирует запись через внутренние batching-механизмы.
При усложнении интерфейсов используется вложенная структура объектов:
animate({
from: {
position: { x: 0, y: 0 },
visual: { opacity: 0 }
},
to: {
position: { x: 300, y: 200 },
visual: { opacity: 1 }
},
onUpdate: (v) => {
element.style.transform =
`translate(${v.position.x}px, ${v.position.y}px)`;
element.style.opacity = v.visual.opacity;
}
});
Такая организация данных улучшает читаемость модели состояния и упрощает масштабирование анимационных сценариев при увеличении числа параметров.