Для работы с множественными действиями на одном элементе необходимо подключить библиотеку Interact.js. Обычно это делается через CDN или установку через npm:
<script src="https://cdn.jsdelivr.net/npm/@interactjs/interactjs/dist/interact.min.js"></script>
или
npm install @interactjs/interactjs
После подключения создаётся интерактивный элемент с помощью метода
interact(target), где target — CSS-селектор
или DOM-элемент.
interact('.draggable-resizable')
.draggable({ /* настройки */ })
.resizable({ /* настройки */ });
Важное отличие работы с множественными действиями: все методы
(draggable, resizable,
gesturable) можно вызывать последовательно на одном и том
же элементе, а библиотека автоматически управляет конфликтами между
ними.
Interact.js позволяет комбинировать следующие действия:
Перетаскивание (drag) Позволяет перемещать элемент по странице. Основные параметры:
inertia — включение инерции после отпускания мыши.modifiers — ограничения движения (например, сетка,
границы контейнера).listeners — события start,
move, end.interact('.draggable-resizable')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
listeners: {
move(event) {
const { dx, dy } = event;
const target = event.target;
const x = (parseFloat(target.getAttribute('data-x')) || 0) + dx;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + dy;
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
}
});
Изменение размера (resize) Позволяет изменять ширину и высоту элемента. Настройки включают:
edges — определяет, с каких сторон можно изменять
размер.modifiers — ограничения минимальных и максимальных
размеров.listeners — события start,
move, end.interact('.draggable-resizable')
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
modifiers: [
interact.modifiers.restrictSize({
min: { width: 50, height: 50 },
max: { width: 500, height: 500 }
})
],
listeners: {
move(event) {
const target = event.target;
let { width, height } = event.rect;
target.style.width = width + 'px';
target.style.height = height + 'px';
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.deltaRect.left;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.deltaRect.top;
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
}
});
Жесты (gesturable) Позволяет работать с поворотом и масштабированием через мультитач. Настройки:
listeners — события start,
move, end.inertia — аналогично drag, поддерживает инерцию
поворота и масштабирования.interact('.draggable-resizable')
.gesturable({
listeners: {
move(event) {
const target = event.target;
const scale = (parseFloat(target.getAttribute('data-scale')) || 1) * (1 + event.ds);
const angle = (parseFloat(target.getAttribute('data-angle')) || 0) + event.da;
target.style.transform = `translate(${target.getAttribute('data-x')}px, ${target.getAttribute('data-y')}px) rotate(${angle}deg) scale(${scale})`;
target.setAttribute('data-scale', scale);
target.setAttribute('data-angle', angle);
}
}
});
Ключевой момент: один и тот же элемент может одновременно поддерживать drag, resize и gesturable. Для корректной работы нужно:
data-x, data-y,
data-scale, data-angle).transform для всех изменений.
Например:target.style.transform = `translate(${x}px, ${y}px) rotate(${angle}deg) scale(${scale})`;
delta изменений отдельно для каждой
функции, чтобы избежать перезаписи значений.Пример объединённого обработчика move для drag + resize
+ gesturable:
function updateTransform(target, dx=0, dy=0, dWidth=0, dHeight=0, dScale=1, dAngle=0) {
const x = (parseFloat(target.getAttribute('data-x')) || 0) + dx;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + dy;
const width = (parseFloat(target.style.width) || target.offsetWidth) + dWidth;
const height = (parseFloat(target.style.height) || target.offsetHeight) + dHeight;
const scale = ((parseFloat(target.getAttribute('data-scale')) || 1) * dScale);
const angle = (parseFloat(target.getAttribute('data-angle')) || 0) + dAngle;
target.style.width = width + 'px';
target.style.height = height + 'px';
target.style.transform = `translate(${x}px, ${y}px) rotate(${angle}deg) scale(${scale})`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
target.setAttribute('data-scale', scale);
target.setAttribute('data-angle', angle);
}
Interact.js предоставляет модификаторы, которые позволяют:
restrictRect,
restrictEdges.snap.restrictSize,
aspectRatio.Пример ограничения по сетке при перетаскивании и изменении размера:
modifiers: [
interact.modifiers.snap({
targets: [interact.snappers.grid({ x: 20, y: 20 })],
range: Infinity,
relativePoints: [{ x: 0, y: 0 }]
}),
interact.modifiers.restrictSize({
min: { width: 50, height: 50 },
max: { width: 400, height: 400 }
})
]
Interact.js поддерживает следующие события:
start — инициирование действия.move — каждое изменение
координат/размера/масштаба.end — завершение действия.inertiastart, inertiaresume,
inertiaend — при включённой инерции.Можно подписываться на события глобально через
interact(target).on(event, handler) или локально через
listeners в настройках действия.
top и
left напрямую, это снижает нагрузку на рендер.move.will-change: transform;
в CSS для GPU-ускорения.Interact.js обеспечивает гибкое управление множественными действиями на одном элементе, сочетая drag, resize и gesturable, при этом позволяя сохранять точный контроль над позицией, размером и трансформациями через единую систему атрибутов и модификаторов. Это делает библиотеку мощным инструментом для создания интерактивных пользовательских интерфейсов.