I have something like the attached code where some green divs can be dragged and dropped between list elements.
There are 2 issues that I don't seem to be able to solve:
1) The "ghost" dragged image in the larger "Take Me" div is almost invisible. The user has very little idea of what is been dragged. Can this be changed somehow ?
2) The drop target is the one under the mouse pointer. This is quite logical but it makes it difficult for the user to understand where the green is going to be dropped. If it was dragged by the bottom then the green makes a big jump down when the mouse button is released. Is there a way to make the top of the ghost image snap to the pointer ?
In the final application there will be many green divs and the user should be able to slot them together with no overlap so a clear idea of what is being dragged and precision dropping are important.
Would I be better off not using the drag events and implement dragdrop manually the old-fashioned way (most likely using some kind of library) ?
I need support only for the latest browsers and have tried only Chrome and FF on Windows so far.
function initDragDrop(){
initDragDrop.dragged = null;
// Dragged
$('div')
.on('dragstart',
function(event) {
initDragDrop.dragged = this;
initDragDrop.dragged.style.opacity = 0.5;
event.originalEvent.dataTransfer.setData('text/plain', 'dummy');
})
.on('dragend', function( event ) {
event.target.style.opacity = '';
});
// Drop targets
$('li')
.on('dragenter', function(event) {
event.preventDefault();
})
.on('drop dragdrop', function(event){
event.preventDefault();
event.stopPropagation();
event.target.classList.remove('dragover');
if ( initDragDrop.dragged ) {
initDragDrop.dragged.style.opacity = '';
$(this).append($(initDragDrop.dragged));
initDragDrop.dragged = null;
}
})
.on('dragover', function(event) {
event.target.classList.add('dragover');
event.preventDefault();
})
.on('dragleave', function(event) {
event.target.classList.remove('dragover');
});
}
initDragDrop();
ul {
width: 30em;
display: block;
}
ul.small {
margin-top: 4em;
width: 10em;
}
li {
height: 2em;
border: 1px solid grey;
}
li.dragover {
background: #ddd;
}
div {
background-color: lightgreen;
border: 2px solid darkgreen;
position: relative;
margin: 0;
width: 90%;
height: 5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li></li>
<li></li>
<li><div draggable="true">
Take Me
</div></li>
<li></li>
</ul>
<ul class="small">
<li></li>
<li></li>
<li><div draggable="true">
Take Me too
</div></li>
<li></li>
<li></li>
<li></li>
</ul>
You can't style the dragged element directly. As soon as the drag is started, it is a bitmap copy of what the element looked like at this moment.
But, you can change its style (or classes) before the drag starts, and revert it back right after. So, we should be able to stylize it to be at the good position before the "screenshot" occurs.
Here is an attempt where the styling works but not the positionning… I'm trying to figure it out:
(function initDragDrop() {
initDragDrop.dragged = null;
// Dragged
$('div')
.on('dragstart', function(event) {
initDragDrop.dragged = this;
initDragDrop.dragged.classList.add('ghost');
event.originalEvent.dataTransfer.setData('text/plain', 'dummy');
// Set style for the element before dragging it
var elm = event.target;
elm.classList.add('dragged');
elm.style.top = (event.clientY) - 5 + 'px';
elm.style.left = (event.clientX) - 5 + 'px';
// Reset style after drag has started
setTimeout((function(elm) {
return function() {
elm.classList.remove('dragged');
elm.style.removeProperty('top');
elm.style.removeProperty('left');
}
})(elm), 1000);
})
.on('dragend', function(event) {
// event.target.style.opacity = ''; // Not used
});
// Drop targets
$('li')
.on('dragenter', function(event) {
event.preventDefault();
})
.on('drop dragdrop', function(event) {
event.preventDefault();
event.stopPropagation();
event.target.classList.remove('dragover');
if (initDragDrop.dragged) {
initDragDrop.dragged.classList.remove('ghost');
$(this).append($(initDragDrop.dragged));
initDragDrop.dragged = null;
}
})
.on('dragover', function(event) {
event.target.classList.add('dragover');
event.preventDefault();
})
.on('dragleave', function(event) {
event.target.classList.remove('dragover');
});
})();
ul {
width: 30em;
display: block;
}
ul.small {
margin-top: 4em;
width: 10em;
}
li {
height: 2em;
border: 1px solid grey;
}
li.dragover {
background: #ddd;
}
div {
background-color: lightgreen;
border: 2px solid darkgreen;
position: relative;
margin: 0;
width: 90%;
height: 5em;
}
.ghost {
opacity: 0.5;
}
.dragged {
display: block;
position: fixed;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li></li>
<li></li>
<li>
<div draggable="true">
Take Me
</div>
</li>
<li></li>
</ul>
<ul class="small">
<li></li>
<li></li>
<li>
<div draggable="true">
Take Me too
</div>
</li>
<li></li>
<li></li>
<li></li>
</ul>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With