Snap-эффекты позволяют элементам автоматически “прилипать” к
определённым координатам или линиям на странице при перемещении или
изменении размера. Это достигается с помощью модуля
interact.snap, который поддерживает гибкие параметры для
настройки поведения объектов. Snap используется для упрощения
выравнивания элементов, создания сеток и визуальных ограничителей при
drag-and-drop или resize операциях.
Базовая структура подключения snap к интерактивному элементу выглядит следующим образом:
interact('.draggable')
.draggable({
listeners: {
move(event) {
Object.assign(event.target.style, {
transform: `translate(${event.pageX}px, ${event.pageY}px)`
});
}
},
modifiers: [
interact.modifiers.snap({
targets: [
interact.snappers.grid({ x: 50, y: 50 })
],
range: Infinity,
relativePoints: [{ x: 0.5, y: 0.5 }]
})
]
});
Ключевые моменты:
targets — массив целей snap, к которым объект может
притягиваться. Это могут быть сетки, конкретные координаты, линии или
функции.range — радиус действия snap. Если расстояние до цели
превышает это значение, snap не срабатывает.relativePoints — точка на объекте, которая будет
использоваться для вычисления положения относительно snap-цели.
Например, {x:0.5, y:0.5} — центр элемента.Привязка к сетке является наиболее распространённым способом использования snap. Она позволяет элементам перемещаться строго по шагам сетки, что особенно удобно для интерфейсов с позиционированием элементов или для визуальных редакторов.
Простейший пример сетки:
interact('.draggable')
.draggable({
modifiers: [
interact.modifiers.snap({
targets: [
interact.snappers.grid({ x: 100, y: 100 })
],
range: Infinity,
relativePoints: [{ x: 0.5, y: 0.5 }]
})
],
inertia: true
});
x и y определяют шаги сетки по горизонтали
и вертикали.inertia: true создаёт эффект
естественного движения, при котором объект немного “докатится” до
ближайшей позиции сетки после отпускания.Сетка может быть динамической, если нужно, чтобы шаги зависели от размеров контейнера или других параметров:
const gridSize = () => ({
x: window.innerWidth / 12,
y: window.innerHeight / 8
});
interact('.draggable')
.draggable({
modifiers: [
interact.modifiers.snap({
targets: [
interact.snappers.grid(gridSize)
]
})
]
});
Помимо сетки, можно привязывать элементы к произвольным точкам на странице:
interact('.draggable')
.draggable({
modifiers: [
interact.modifiers.snap({
targets: [
{ x: 200, y: 150 },
{ x: 400, y: 300 },
interact.snappers.grid({ x: 100, y: 100 })
],
range: 50
})
]
});
targets можно добавлять объекты с координатами
или другие snappers.range объект не притягивается к цели,
что позволяет задать локальные ограничения для snap.Snap также может быть функциональным, с вычислением цели на лету:
interact('.draggable')
.draggable({
modifiers: [
interact.modifiers.snap({
targets: [
function (x, y) {
return { x: Math.round(x / 50) * 50, y: Math.round(y / 50) * 50 };
}
]
})
]
});
Такой подход полезен для создания адаптивной сетки или сложной логики притяжения к линиям и объектам с нестандартным расположением.
Параметры snap:
offset — смещение snap-цели относительно координат
элемента.endOnly — если true, snap срабатывает
только после завершения перемещения или ресайза.lockAxis — ограничивает движение объекта по одной оси
до срабатывания snap.range — радиус действия, как уже упоминалось, ключевой
для контроля чувствительности.interact('.resizable')
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
modifiers: [
interact.modifiers.snap({
targets: [
interact.snappers.grid({ x: 20, y: 20 })
],
endOnly: true
})
],
listeners: {
move(event) {
let { x, y } = event.target.dataset;
x = (parseFloat(x) || 0) + event.deltaRect.left;
y = (parseFloat(y) || 0) + event.deltaRect.top;
Object.assign(event.target.style, {
width: `${event.rect.width}px`,
height: `${event.rect.height}px`,
transform: `translate(${x}px, ${y}px)`
});
event.target.dataset.x = x;
event.target.dataset.y = y;
}
}
});
endOnly: true особенно полезен для resizable элементов,
чтобы snap не мешал плавному изменению размеров, а применялся только
после окончания действия.
Snap часто используется вместе с модификатором restrict,
который ограничивает область перемещения или изменения размера элемента.
Это позволяет создавать интерактивные панели, редакторы и конструктивные
интерфейсы:
interact('.draggable')
.draggable({
modifiers: [
interact.modifiers.snap({
targets: [ interact.snappers.grid({ x: 50, y: 50 }) ],
range: Infinity
}),
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
]
});
endOnly позволяет избегать конфликтов между snap и
ограничением в реальном времени.endOnly уменьшает нагрузку на события
mousemove или resize.Snap и привязка к сетке находят широкое применение в:
Эта функциональность позволяет создавать удобные, предсказуемые и точные взаимодействия, делая работу с элементами страницы интуитивной и контролируемой.