Interact.js предоставляет гибкую систему управления событиями drag, resize, gesture и drop, позволяя обрабатывать несколько жестов одновременно. Основная идея заключается в том, что каждый элемент может быть настроен на прослушивание нескольких типов взаимодействий, и библиотека обеспечивает координацию их работы.
Ключевым моментом является конфликт жестов, когда два или более действия могут выполняться одновременно. Interact.js использует механизм pointer-events и внутренние приоритеты событий для их согласованного выполнения.
Для одновременного использования жестов необходимо правильно настроить объект Interactable:
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);
}
}
})
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
modifiers: [
interact.modifiers.restrictEdges({
outer: 'parent',
endOnly: true
})
],
listeners: {
move(event) {
const { width, height } = event.rect;
const target = event.target;
target.style.width = `${width}px`;
target.style.height = `${height}px`;
}
}
});
Здесь элемент одновременно поддерживает
перетаскивание и изменение размера.
Использование атрибутов data-x и data-y
позволяет синхронизировать положение элемента при движении и
масштабировании.
Interact.js предоставляет объект interaction, который
содержит информацию о всех активных указателях. Для
одновременного жеста важно использовать методы
interactable.options и interaction:
interaction.pointerIsDown — проверка, удерживается ли
указатель.interaction.pointers — массив всех активных указателей,
что позволяет реализовать жесты с несколькими пальцами.interaction.prepared — текущая подготовка к событию,
помогает отслеживать активные действия на элементе.Пример обработки многофакторного жеста (drag + resize):
interact('.multi-touch')
.gesturable({
listeners: {
start(event) {
event.target.dataset.startAngle = event.angle;
},
move(event) {
const rotation = event.angle - parseFloat(event.target.dataset.startAngle);
event.target.style.transform = `rotate(${rotation}deg)`;
}
}
})
.draggable({
listeners: {
move(event) {
const x = (parseFloat(event.target.dataset.x) || 0) + event.dx;
const y = (parseFloat(event.target.dataset.y) || 0) + event.dy;
event.target.style.transform = `translate(${x}px, ${y}px)`;
event.target.dataset.x = x;
event.target.dataset.y = y;
}
}
});
Использование gesturable совместно с
draggable позволяет одновременно вращать и перемещать
элемент, при этом Interact.js корректно синхронизирует изменения
трансформации.
Одновременные жесты могут конфликтовать, особенно если применяется ограничение перемещения или изменения размера. Interact.js предлагает модификаторы, которые позволяют:
Пример сочетания snap и draggable:
interact('.snapped-draggable')
.draggable({
modifiers: [
interact.modifiers.snap({
targets: [
interact.createSnapGrid({ x: 50, y: 50 })
],
range: Infinity,
relativePoints: [{ x: 0, y: 0 }]
})
],
listeners: {
move(event) {
const x = (parseFloat(event.target.dataset.x) || 0) + event.dx;
const y = (parseFloat(event.target.dataset.y) || 0) + event.dy;
event.target.style.transform = `translate(${x}px, ${y}px)`;
event.target.dataset.x = x;
event.target.dataset.y = y;
}
}
});
Модификаторы гарантируют, что при одновременном использовании жестов элемент не выйдет за пределы разрешённой области и не пересечёт запрещённые координаты.
Interact.js позволяет контролировать приоритет событий, что важно при наложении drag, resize и gesturable. Основные инструменты:
autoScroll — приоритет скроллинга контейнера во время
drag.ignoreFrom и allowFrom — разрешают или
запрещают обработку событий на определённых вложенных элементах.pointerTypes — фильтрация типов указателей для разных
жестов (мышь, touch, pen).Пример приоритета drag над gesturable:
interact('.priority-example')
.gesturable({
pointerTypes: ['touch'],
listeners: { move: event => console.log('Gesture detected') }
})
.draggable({
pointerTypes: ['mouse', 'touch'],
ignoreFrom: '.no-drag',
listeners: { move: event => console.log('Drag detected') }
});
Таким образом, можно настроить гибкую логику, где разные жесты активируются в зависимости от источника указателя и конкретной области элемента.
dataset или отдельные переменные,
чтобы синхронизировать изменения нескольких жестов.interaction.pointers.length, чтобы корректно обрабатывать
события с несколькими пальцами.Эти принципы позволяют создавать сложные интерфейсы с интерактивными элементами, где пользователь может одновременно перемещать, изменять размер и вращать объекты, не сталкиваясь с конфликтами событий и некорректной обработкой указателей.