Html/css newbie here,
I am using interact.js to attain a certain UI where I can drop items from a list into a drop zone. The problem is my list can grow very long and I need to add scroll to the list, and when I try to do so I have create a 'div' and put the list items into it to show the scroll behaviour.
But when I put the list items inside a div and the drop zone outside it, the items do not get dropped there and the list shows a weird behaviour, all of them starts getting stacked on top of the bottom list item (at the bottom of the div containing the items).
This is my html:
<div class="items">
<p style="padding-top: 20px; font-size:18px">Stacked Items</p>
<div style = "height: 400px; overflow: scroll">
<div id="itemstodrop" class="drag-drop"> item 1 </div>
<div id="itemstodrop" class="drag-drop"> item 2 </div>
<div id="itemstodrop" class="drag-drop"> item 3 </div>
<div id="itemstodrop" class="drag-drop"> item 4 </div>
<div id="itemstodrop" class="drag-drop"> item 5 </div>
<div id="itemstodrop" class="drag-drop"> item 6 </div>
<div id="itemstodrop" class="drag-drop"> item 7 </div>
<div id="itemstodrop" class="drag-drop"> item 8 </div>
<div id="itemstodrop" class="drag-drop"> item 9 </div>
<div id="itemstodrop" class="drag-drop"> item 10 </div>
<div id="itemstodrop" class="drag-drop"> item 11 </div>
<div id="itemstodrop" class="drag-drop"> item 12 </div>
</div>
<div id="inner-dropzone" class="dropzone">Drop here</div>
</div>
This is my script which holds interact.js code:
import interact from
'https://cdn.jsdelivr.net/npm/@interactjs/interactjs/index.js'
// enable draggables to be dropped into this
var startPos = null;
//define the initial position for each rig tile.
function dragMoveListener (event) {
var target = event.target
// keep the dragged position in the data-x/data-y attributes
var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)'
// update the posiion attributes
target.setAttribute('data-x', x)
target.setAttribute('data-y', y)
}
// this function is used later in the resizing and gesture demos
window.dragMoveListener = dragMoveListener
//ALL THE FUNCTIONS BELOW TALK ABOUT THE DRAGGABLE AREA.
interact('.dropzone').dropzone({
// only accept elements matching this CSS selector
accept: '#itemstodrop',
// the item should go 100% inside the draggable area...
overlap: 0.9999999, //somehow it does not take the value 100%
// listen for drop related events:
ondropactivate: function (event) {
// add active dropzone feedback
event.target.classList.add('drop-active')
},
ondragenter: function (event) {
//when item enters the draggable area
var draggableElement = event.relatedTarget
var dropzoneElement = event.target
console.log(draggableElement.firstChild.nodeValue);
// feedback the possibility of a drop
dropzoneElement.classList.add('drop-target')
draggableElement.classList.add('can-drop')
},
ondragleave: function (event) {
console.log(startPos)
event.draggable.draggable({
snap: {
targets: [startPos]
}
});
//when item leaves the draggable area
// remove the drop feedback style
event.target.classList.remove('drop-target')
event.relatedTarget.classList.remove('can-drop')
},
ondrop: function (event) {
//when the item is droppd in the draggable area
{% comment %} event.relatedTarget.textContent = 'Dropped' {% endcomment %}
},
ondropdeactivate: function (event) {
// remove active dropzone feedback
event.target.classList.remove('drop-active')
event.target.classList.remove('drop-target')
}
})
interact('.drag-drop')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
autoScroll: true,
// dragMoveListener from the dragging demo above
listeners: { move: dragMoveListener }
})
</script>
This is how it looks when rendered: (Basically can't drop any item to drop area.)
Full working page for demo: (I have added a comment which tells where have I put the div.)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#outer-dropzone {
height: 140px;
}
#inner-dropzone {
height: 80px;
}
.dropzone {
background-color: #ccc;
border: dashed 4px transparent;
border-radius: 4px;
margin: 10px auto 30px;
padding: 10px;
width: 80%;
transition: background-color 0.3s;
}
.drop-active {
border-color: #aaa;
}
.drop-target {
background-color: #29e;
border-color: #fff;
border-style: solid;
}
.drag-drop {
display: inline-block;
min-width: 40px;
padding: 2em 0.5em;
color: #fff;
background-color: #29e;
border: solid 2px #fff;
touch-action: none;
-webkit-transform: translate(0px, 0px);
transform: translate(0px, 0px);
transition: background-color 0.3s;
}
.drag-drop.can-drop {
color: #000;
background-color: #4e4;
}
</style>
</head>
<body>
{% comment %} I NEED THIS DIV UNDER THIS COMMENT, TO ADD A SCROLL AREA. BUT WHEN I GIVE THIS DIV, THE DROP DOES NOT OCCUR. {% endcomment %}
<div>
<div id="no-drop" class="drag-drop"> #no-drop </div>
<div id="yes-drop" class="drag-drop"> #yes-drop </div>
</div>
<div id="outer-dropzone" class="dropzone">
#outer-dropzone
<div id="inner-dropzone" class="dropzone">#inner-dropzone</div>
</div>
<script type="module">
import interact from
'https://cdn.jsdelivr.net/npm/@interactjs/interactjs/index.js'
// enable draggables to be dropped into this
interact('.draggable')
.draggable({
// enable inertial throwing
inertia: true,
// keep the element within the area of it's parent
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
// enable autoScroll
autoScroll: true,
listeners: {
// call this function on every dragmove event
move: dragMoveListener,
// call this function on every dragend event
end (event) {
var textEl = event.target.querySelector('p')
textEl && (textEl.textContent =
'moved a distance of ' +
(Math.sqrt(Math.pow(event.pageX - event.x0, 2) +
Math.pow(event.pageY - event.y0, 2) | 0))
.toFixed(2) + 'px')
}
}
})
function dragMoveListener (event) {
var target = event.target
// keep the dragged position in the data-x/data-y attributes
var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)'
// update the posiion attributes
target.setAttribute('data-x', x)
target.setAttribute('data-y', y)
}
// this function is used later in the resizing and gesture demos
window.dragMoveListener = dragMoveListener
//ALL THE FUNCTIONS BELOW TALK ABOUT THE DRAGGABLE AREA.
interact('.dropzone').dropzone({
// only accept elements matching this CSS selector
accept: '#yes-drop',
// the item should go 100% inside the draggable area...
overlap: 0.9999999, //somehow it does not take the value 100%
// listen for drop related events:
ondropactivate: function (event) {
// add active dropzone feedback
event.target.classList.add('drop-active')
},
ondragenter: function (event) {
//when item enters the draggable area
var draggableElement = event.relatedTarget
var dropzoneElement = event.target
console.log(draggableElement.firstChild.nodeValue);
// feedback the possibility of a drop
dropzoneElement.classList.add('drop-target')
draggableElement.classList.add('can-drop')
},
ondragleave: function (event) {
//when item leaves the draggable area
// remove the drop feedback style
event.target.classList.remove('drop-target')
event.relatedTarget.classList.remove('can-drop')
},
ondrop: function (event) {
//when the item is droppd in the draggable area
{% comment %} event.relatedTarget.textContent = 'Dropped' {% endcomment %}
},
ondropdeactivate: function (event) {
// remove active dropzone feedback
event.target.classList.remove('drop-active')
event.target.classList.remove('drop-target')
}
})
interact('.drag-drop')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
autoScroll: true,
// dragMoveListener from the dragging demo above
listeners: { move: dragMoveListener }
})
</script>
</body>
</html>
You need to change accept: '#rigstodrop'
to accept: '#itemstodrop'
because here your div has id itemstodrop
which you need to drag and drop . Also , use restriction: '.items'
to restrict rect not to go beyond that area .
Demo code :
var startPos = null;
//define the initial position for each rig tile.
function dragMoveListener(event) {
var target = event.target
// keep the dragged position in the data-x/data-y attributes
var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)'
// update the posiion attributes
target.setAttribute('data-x', x)
target.setAttribute('data-y', y)
}
// this function is used later in the resizing and gesture demos
window.dragMoveListener = dragMoveListener
interact('.dropzone').dropzone({
// only accept elements matching this CSS selector
accept: '#itemstodrop', //change this
// the item should go 100% inside the draggable area...
overlap: 0.9999999,
ondropactivate: function(event) {
// add active dropzone feedback
event.target.classList.add('drop-active')
},
ondragenter: function(event) {
//when item enters the draggable area
var draggableElement = event.relatedTarget
var dropzoneElement = event.target
console.log(draggableElement.firstChild.nodeValue);
// feedback the possibility of a drop
dropzoneElement.classList.add('drop-target')
draggableElement.classList.add('can-drop')
},
ondragleave: function(event) {
console.log(startPos)
event.draggable.draggable({
snap: {
targets: [startPos]
}
});
//when item leaves the draggable area
// remove the drop feedback style
event.target.classList.remove('drop-target')
event.relatedTarget.classList.remove('can-drop')
},
ondrop: function(event) {
//when the item is droppd in the draggable area
event.relatedTarget.textContent = 'Dropped'
},
ondropdeactivate: function(event) {
// remove active dropzone feedback
event.target.classList.remove('drop-active')
event.target.classList.remove('drop-target')
}
})
interact('.drag-drop')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: '.items', //change this
endOnly: true
})
],
autoScroll: true,
// dragMoveListener from the dragging demo above
listeners: {
move: dragMoveListener
}
})
.itemstodrop {
touch-action: none;
user-select: none;
}
#inner-dropzone {
height: 80px;
}
.dropzone {
background-color: #ccc;
border: dashed 4px transparent;
border-radius: 4px;
margin: 10px auto 30px;
padding: 10px;
width: 80%;
transition: background-color 0.3s;
}
.drop-active {
border-color: #aaa;
}
.drop-target {
background-color: #29e;
border-color: #fff;
border-style: solid;
}
.drag-drop {
display: inline-block;
min-width: 40px;
padding: 2em 0.5em;
color: #fff;
background-color: #29e;
border: solid 2px #fff;
touch-action: none;
-webkit-transform: translate(0px, 0px);
transform: translate(0px, 0px);
transition: background-color 0.3s;
}
.drag-drop.can-drop {
color: #000;
background-color: #4e4;
}
<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
<div class="items">
<p style="padding-top: 20px; font-size:18px">Stacked Rigs</p>
<div style="height: auto;overflow: scroll">
<div id="itemstodrop" class="drag-drop itemstodrop"> item 1 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 2 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 3 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 4 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 5 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 6 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 7 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 8 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 9 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 10 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 11 </div>
<div id="itemstodrop" class="drag-drop itemstodrop"> item 12 </div>
<!--put this inside div-->
<div id="inner-dropzone" class="dropzone">Drop here</div>
</div>
</div>