Interact.js предоставляет мощные инструменты для создания интерактивных элементов с поддержкой drag-and-drop, resizable, gesturable событий. Анимации переходов позволяют не только визуально улучшить взаимодействие с элементами, но и создавать плавные реакции на действия пользователя, такие как перетаскивание или изменение размеров.
В основе анимаций лежит сочетание CSS-переходов и событий, которые Interact.js генерирует. Для создания плавного движения важно понимать разницу между динамическими позициями элемента и трансформациями через CSS.
Interact.js чаще всего использует CSS transform: translate(x, y) для перемещения элементов. Преимущество трансформаций:
Пример плавного перемещения при перетаскивании:
interact('.draggable')
.draggable({
listeners: {
move(event) {
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);
}
}
});
Чтобы добавить плавный переход после отпускания элемента, можно использовать CSS:
.draggable {
transition: transform 0.3s ease-out;
}
И тогда при изменении позиции через style.transform
элемент будет плавно перемещаться в новую точку.
Interact.js имеет встроенные модули inertia и snap, которые создают эффект «отскока» и инерции:
inertia: true — элемент продолжает движение после
отпускания, постепенно замедляясь.snap — элемент автоматически привязывается к сетке или
определенным точкам.Пример с инерцией:
interact('.draggable')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.snap({
targets: [
interact.snappers.grid({ x: 50, y: 50 })
],
range: Infinity,
relativePoints: [{ x: 0, y: 0 }]
})
],
listeners: {
move(event) {
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);
}
}
});
Эта комбинация позволяет создавать плавные анимации с автоматическим выравниванием по сетке и реалистичной физикой движения.
Скорость анимации и тип кривой задаются через CSS-переходы:
.draggable {
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
ease-out — замедление в конце движения.linear — постоянная скорость.cubic-bezier — точная кастомизация кривой
ускорения.Можно динамически менять скорость через JS:
target.style.transition = 'transform 0.2s ease-in-out';
Это полезно, если нужно ускорить или замедлить анимацию в зависимости от состояния взаимодействия.
Interact.js поддерживает resizable элементы с возможностью плавного изменения размеров:
interact('.resizable')
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
listeners: {
move(event) {
const target = event.target;
let x = (parseFloat(target.getAttribute('data-x')) || 0);
let y = (parseFloat(target.getAttribute('data-y')) || 0);
target.style.width = `${event.rect.width}px`;
target.style.height = `${event.rect.height}px`;
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
}
});
Для плавного изменения размеров также добавляется CSS:
.resizable {
transition: width 0.3s ease, height 0.3s ease, transform 0.3s ease;
}
Плавность можно сохранить даже при одновременном перемещении и изменении размеров. Важный момент — использовать одинаковую transition для transform, width и height, чтобы избежать резких скачков.
.element {
transition: transform 0.4s ease, width 0.4s ease, height 0.4s ease;
}
В JS-коде можно централизованно обновлять координаты и размеры:
function updateElement(event) {
const target = event.target;
let x = (parseFloat(target.getAttribute('data-x')) || 0) + (event.dx || 0);
let y = (parseFloat(target.getAttribute('data-y')) || 0) + (event.dy || 0);
if (event.rect) {
target.style.width = `${event.rect.width}px`;
target.style.height = `${event.rect.height}px`;
x += event.deltaRect.left;
y += event.deltaRect.top;
}
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
Этот подход обеспечивает синхронную анимацию перемещения и изменения размеров.
Для более сложных анимаций с многослойными эффектами или
динамическим ускорением рекомендуется использовать
requestAnimationFrame вместо CSS-переходов. Это позволяет
контролировать каждый кадр движения и интегрировать
дополнительные эффекты, такие как вращение, масштабирование или
тени.
Пример анимации с инерцией:
let vx = 0, vy = 0;
interact('.draggable')
.draggable({
inertia: true,
listeners: {
move(event) {
vx = event.dx;
vy = event.dy;
animate(event.target);
}
}
});
function animate(target) {
let x = parseFloat(target.getAttribute('data-x')) || 0;
let y = parseFloat(target.getAttribute('data-y')) || 0;
function frame() {
x += vx;
y += vy;
target.style.transform = `translate(${x}px, ${y}px)`;
vx *= 0.95;
vy *= 0.95;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
if (Math.abs(vx) > 0.5 || Math.abs(vy) > 0.5) {
requestAnimationFrame(frame);
}
}
requestAnimationFrame(frame);
}
Такой метод позволяет создавать натуральную динамику движения, которая трудно достижима через простые CSS-переходы.
offsetLeft/Top.
Это предотвращает конфликты с CSS-свойствами.snap,
restrict, inertia) совместно с анимациями для
создания интуитивного и плавного UX.