DrapNDrop

by dpnminh

HTML

<div class="test-zone">

  <div class="drop-zone">
    <div class="drag-target" draggable=true id="target">
      Me
    </div>
  </div>
  <div class="drop-zone">
  </div>
</div>

CSS

.test-zone{
  display: grid;
  grid-template-columns: repeat(2, 200px);
  grid-gap: 10px;
}
.drop-zone {
  height: 200px;
  padding: 10px;
  
  position: relative;
  background: lightgray;
}

.drag-target {
  width: 100%;
  height: 100px;
  background: lightpink;
  display: flex;
  align-items: center;
  cursor: move;
  /* fallback if grab cursor is unsupported */
  cursor: grab;
  cursor: -moz-grab;
  cursor: -webkit-grab;
  justify-content: center;
}

.moving {
  position: absolute;
  box-shadow: 5px 10px #888888;
  transform: rotate(10deg);
  cursor: move;
  cursor: grabbing;
  cursor: -moz-grabbing;
  cursor: -webkit-grabbing;
  z-index:10;
}

.drag-target::active,
.drag-target::hover {
  cursor: move;
  cursor: -webkit-grabbing;
  cursor: -moz-grabbing;
  cursor: -o-grabbing;
  cursor: -ms-grabbing;
  cursor: grabbing;
}

JavaScript

let dragItem;
let orgPos = {}

document.addEventListener("dragstart", (event) => {
  var img = new Image();
  img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
  event.dataTransfer.setDragImage(img, 0, 0);
  if (event.target.getAttribute('id') === 'target') {
    dragItem = event.target;
    let clientRec = dragItem.getBoundingClientRect()
    orgPos = {
      x: event.x - clientRec.x,
      y: event.y - clientRec.y,
      originX: clientRec.x,
      originY: clientRec.y
    }
    dragItem.classList.add('moving')
  }
}, false)

document.addEventListener('dragover', (event) => {

  dragItem.style.left = (event.pageX - orgPos.x) + 'px'
  dragItem.style.top = (event.pageY - orgPos.y) + 'px'
})

document.addEventListener('dragend', (event) => {
  dragItem.classList.remove('moving')
  dragItem.style.left = (orgPos.originX) + 'px'
  dragItem.style.top = (orgPos.originY) + 'px'

}, false)

document.addEventListener("dragenter", function(event) {
  // highlight potential drop target when the draggable element enters it
  if (event.target.className == "drop-zone") {
    event.target.style.background = "purple";
  }

}, false);

document.addEventListener("dragleave", function(event) {
  // reset background of potential drop target when the draggable element leaves it
  if (event.target.className == "drop-zone") {
    event.target.style.background = "";
  }

}, false);

document.addEventListener('drop', (event) => {
  event.preventDefault();
  // move dragged elem to the selected drop target
  if (event.target.className == "drop-zone") {
    event.target.style.background = "";
    dragItem.parentNode.removeChild(dragged);
    event.target.appendChild(dragged);
  dragItem.style.left = (event.target.getBoundingClientRect().x) + 'px'
  dragItem.style.top = (event.target.getBoundingClientRect().y) + 'px'
  }

})