I’m trying to make multiple elements draggable using interact.js in my CodePen project, but it’s not working as expected. When I add the draggable="true" attribute to the elements, not all of them respond correctly to drag events, only the last one. All elements before the last one have a strange behaviour: At start drag, drag end is already fired.
<div class="configurator-container">
<div class="elements-panel">
<div class="element" id="element-1" draggable="true">
Element 1
</div>
<div class="element" id="element-2" draggable="true">
Element 2
</div>
<div class="element" id="element-3" draggable="true">
Element 3
</div>
<div class="element" id="element-4" draggable="true">
Element 4
</div>
<!-- Add more elements as needed -->
</div>
<div class="board-container">
<div class="board" id="board">
<!-- Dynamically add elements here -->
</div>
</div>
</div>
Here’s my setup:
Here’s my CodePen: https://codepen.io/brentrug/pen/OPLEJKj
What I’ve tried:
What I expect:
Can anyone help me figure out why this isn’t working?
Any guidance on how I can fix this would be greatly appreciated!
This is the JS code:
// Select all the .element divs
const elements = document.querySelectorAll('.element');
// Loop through each element and apply interact separately
elements.forEach(element => {
interact(element)
.draggable({
inertia: false, // Remove inertia for more responsive dragging
autoScroll: false,
modifiers: [
interact.modifiers.restrict({
restriction: 'parent',
endOnly: true
})
],
listeners: {
start(event) {
console.log('Drag started on', event.target.id);
const { target } = event;
target.classList.add('dragging');
target.style.zIndex = '1000'; // Higher z-index to ensure it's above other elements
// Set initial position for 'absolute' positioning (only for the dragged element)
const rect = target.getBoundingClientRect();
target.setAttribute('data-x', rect.left);
target.setAttribute('data-y', rect.top);
// Ensure position is set to absolute for the dragged element
target.style.position = 'absolute';
},
move(event) {
console.log('Dragging', event.target.id);
const { target } = event;
// Calculate new left and top values
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// Set the left and top properties for movement
target.style.left = `${x}px`;
target.style.top = `${y}px`;
// Store the new position
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
},
end(event) {
console.log('Drag ended on', event.target.id);
const { target } = event;
// Reset the element's position after drop
target.style.position = ''; // Reset position to original state
target.style.left = '';
target.style.top = '';
target.removeAttribute('data-x');
target.removeAttribute('data-y');
target.classList.remove('dragging');
target.style.zIndex = '1';
// Get the board where the element was dropped
const board = document.querySelector('.board'); // Assuming this is your board element
// Calculate final position relative to the board
const dragRect = event.rect;
const boardRect = board.getBoundingClientRect();
const x = dragRect.left - boardRect.left;
const y = dragRect.top - boardRect.top;
// Account for scroll position
const scrollX = window.scrollX || window.pageXOffset;
const scrollY = window.scrollY || window.pageYOffset;
// Adjust coordinates for scroll position
const adjustedX = x - scrollX;
const adjustedY = y - scrollY;
// Create new element with adjusted coordinates
const newElement = createElementOnBoard(target, adjustedX, adjustedY);
board.appendChild(newElement); // Append the new element to the board
}
}
});
});
I removed draggable="true"
from all elements and now it is working. This change allows interact.js to control dragging instead of the browser's built-in drag-and-drop feature. I also checked the interact.js sample code and i didn't see the draggable="true"
attribute used on any of the elements.