Для начала работы с библиотекой Interact.js необходимо подключить её к проекту. Наиболее простой способ — использовать CDN:
<script src="https://cdn.jsdelivr.net/npm/@interactjs/interactjs/dist/interact.min.js"></script>
Альтернативно, при использовании сборщиков модулей, таких как Webpack или Vite, можно установить пакет через npm:
npm install @interactjs/interactjs
и импортировать в коде:
import interact from '@interactjs/interactjs';
Interact.js не требует дополнительных зависимостей и совместим с большинством современных браузеров.
Основная функция для интерактивных схем — это возможность перемещать
элементы. Для этого используется метод .draggable().
interact('.diagram-node')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
listeners: {
move: dragMoveListener
}
});
function dragMoveListener(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);
}
Ключевые моменты:
inertia: true обеспечивает плавное скольжение при
отпускании элемента.modifiers.restrictRect ограничивает перемещение рамками
родителя.data-x и data-y используются для
хранения текущего положения, что позволяет применять относительные
смещения.Для изменения размеров элементов диаграммы применяют
.resizable(). Interact.js позволяет легко добавлять ручки
изменения размера и настраивать ограничения.
interact('.diagram-node')
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
modifiers: [
interact.modifiers.restrictSize({
min: { width: 50, height: 50 },
max: { width: 400, height: 400 }
})
],
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);
}
}
});
Особенности:
edges задаёт стороны, с которых возможна
корректировка.modifiers.restrictSize предотвращает выход размеров за
допустимые пределы.deltaRect позволяет корректно обновлять
позицию при изменении размеров.Для схем с соединениями между узлами полезно комбинировать
перетаскивание узлов с динамическим рисованием линий. Interact.js
поддерживает события dragstart, dragmove и
dragend, которые можно использовать для обновления
координат линий в реальном времени.
interact('.diagram-node')
.draggable({
listeners: {
start(event) {
event.target.classList.add('dragging');
},
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);
updateConnections(target);
},
end(event) {
event.target.classList.remove('dragging');
}
}
});
function updateConnections(node) {
const connections = document.querySelectorAll(`line[data-from='${node.id}'], line[data-to='${node.id}']`);
connections.forEach(line => {
const fromNode = document.getElementById(line.getAttribute('data-from'));
const toNode = document.getElementById(line.getAttribute('data-to'));
line.setAttribute('x1', fromNode.getBoundingClientRect().x + fromNode.offsetWidth / 2);
line.setAttribute('y1', fromNode.getBoundingClientRect().y + fromNode.offsetHeight / 2);
line.setAttribute('x2', toNode.getBoundingClientRect().x + toNode.offsetWidth / 2);
line.setAttribute('y2', toNode.getBoundingClientRect().y + toNode.offsetHeight / 2);
});
}
Важно: Использование идентификаторов узлов и
атрибутов data-from/data-to позволяет
динамически обновлять линии при перемещении.
Для сложных интерактивных схем, например с масштабированием и
вращением узлов, применяют gesturable. Это особенно
актуально для touch-интерфейсов.
interact('.diagram-node')
.gesturable({
listeners: {
move(event) {
const target = event.target;
let currentAngle = parseFloat(target.getAttribute('data-angle')) || 0;
let currentScale = parseFloat(target.getAttribute('data-scale')) || 1;
currentAngle += event.da;
currentScale *= (1 + event.ds);
target.style.transform = `translate(${target.getAttribute('data-x')}px, ${target.getAttribute('data-y')}px) rotate(${currentAngle}deg) scale(${currentScale})`;
target.setAttribute('data-angle', currentAngle);
target.setAttribute('data-scale', currentScale);
}
}
});
Особенности:
event.da — изменение угла в градусах.event.ds — относительное изменение масштаба.data-x и data-y позволяет
одновременно перемещать, масштабировать и вращать объект.Interact.js позволяет комбинировать draggable,
resizable и gesturable на одном элементе. При
этом важно правильно управлять порядком событий и обновлением
трансформаций:
interact('.diagram-node')
.draggable({ listeners: { move: dragMoveListener } })
.resizable({ edges: { left:true, right:true, bottom:true, top:true }, listeners: { move: resizeListener } })
.gesturable({ listeners: { move: gestureListener } });
В этом случае необходимо централизованно отслеживать текущие значения
x, y, angle и scale,
чтобы трансформации не конфликтовали между собой.
data-* или
отдельной структуре данных.requestAnimationFrame для оптимизации
отрисовки сложных соединений.Interact.js предоставляет мощный набор инструментов для создания интерактивных диаграмм и схем с поддержкой перетаскивания, изменения размеров, вращения и масштабирования. Гибкая система событий и модификаторов позволяет полностью контролировать поведение элементов и реализовывать сложные интерфейсы без необходимости писать низкоуровневый код управления событиями.