requestAnimationFrame — это метод браузера, который
позволяет выполнять анимации плавно и эффективно, синхронизируя их с
частотой обновления экрана. В Interact.js он используется для
оптимизации визуальных изменений элементов при перетаскивании,
масштабировании или вращении, чтобы исключить дрожание и лаги.
Метод принимает функцию обратного вызова, которая вызывается перед следующей перерисовкой браузера:
function animate(time) {
// действия с элементом
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Параметр time — это высокоточный временной штамп в
миллисекундах, который можно использовать для вычисления прогресса
анимации.
Interact.js предоставляет события drag,
resize и gesture. Все визуальные обновления
элементов должны выполняться через requestAnimationFrame
для плавности:
interact('.draggable')
.draggable({
listeners: {
move(event) {
requestAnimationFrame(() => {
const target = event.target;
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
});
}
}
});
Ключевые моменты:
requestAnimationFrame.data-x и data-y
обеспечивает корректное накопление смещения.transform вместо
top/left уменьшает перерисовку и повышает
производительность.При работе с несколькими элементами или интенсивными изменениями
рекомендуется использовать один общий цикл
requestAnimationFrame вместо вызова для каждого события.
Это уменьшает нагрузку на браузер и предотвращает коллизии:
const elements = new Map();
interact('.draggable').draggable({
listeners: {
move(event) {
const target = event.target;
const prev = elements.get(target) || { x: 0, y: 0 };
prev.x += event.dx;
prev.y += event.dy;
elements.set(target, prev);
}
}
});
function animate() {
elements.forEach((pos, target) => {
target.style.transform = `translate(${pos.x}px, ${pos.y}px)`;
});
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Преимущества:
requestAnimationFrame обновляет все
элементы.requestAnimationFrame предоставляет
timestamp, который можно использовать для расчета временной
дельты между кадрами. Это особенно полезно для анимаций с постоянной
скоростью независимо от частоты обновления экрана:
let lastTime = 0;
function animate(time) {
const delta = time - lastTime;
lastTime = time;
elements.forEach((pos, target) => {
const speed = 0.5; // пиксели на миллисекунду
pos.x += pos.dx * (delta * speed);
pos.y += pos.dy * (delta * speed);
target.style.transform = `translate(${pos.x}px, ${pos.y}px)`;
});
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Особенности:
requestAnimationFrame в Interact.jsInteract.js поддерживает физически реалистичную инерцию через опцию
inertia. Для кастомных эффектов инерции часто используется
requestAnimationFrame:
let velocity = { x: 0, y: 0 };
let isMoving = false;
function applyInertia(target) {
if (!isMoving) return;
velocity.x *= 0.95;
velocity.y *= 0.95;
const x = (parseFloat(target.getAttribute('data-x')) || 0) + velocity.x;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + velocity.y;
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
if (Math.abs(velocity.x) > 0.1 || Math.abs(velocity.y) > 0.1) {
requestAnimationFrame(() => applyInertia(target));
} else {
isMoving = false;
}
}
Принципы работы:
velocity)
для эффекта затухания.requestAnimationFrame до
полного прекращения движения.requestAnimationFrame идеально сочетается с
CSS-свойствами transform и opacity. Это
позволяет реализовать сложные эффекты drag, scale и rotate без
значительной нагрузки на браузер. Пример комбинированного перемещения и
масштабирования:
interact('.box').draggable({
listeners: {
move(event) {
requestAnimationFrame(() => {
const target = event.target;
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
const scale = 1 + 0.001 * (x + y);
target.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
});
}
}
});
Выводы по использованию
requestAnimationFrame: