javascripthtmlcssinteractjs

Why are my draggable elements not functioning as expected?


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
                }
            }
        });
});

Solution

  • 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.