Binding drag and drop elements in JavaScript

I am trying to use drag and drop to move images from one <div>

to another.

Currently, I can move images anywhere in the destination <div>

, but I really want the images to be linked when deleted. Ideally, they could squeeze together on either side (not just the bottom or right, for example).

I've tried several different things (including usage <canvas>

) and it didn't work.

This is what I have so far:

var clone;
var offsetx = null;
var offsety = null;
var isClone = false;

function allowDrop(ev) {
  ev.preventDefault();
}

function drag(ev) {
  offsetx = ev.target.offsetLeft - event.clientX;
  offsety = ev.target.offsetTop - event.clientY;
  
  ev.dataTransfer.setData("text", ev.target.id);
}

function dropTrash(ev) {
  ev.preventDefault();

  var data = ev.dataTransfer.getData("text");
  var remove = document.getElementById(data);

  remove.parentNode.removeChild(remove);
}

function drop(ev) {
  ev.preventDefault();
  
  var data = ev.dataTransfer.getData("text");
}

function dropClone(ev) {
  ev.preventDefault();
  
  var data = ev.dataTransfer.getData("text");
  var num = Math.random() * (1000 - 1) + 1;
  
  isClone = true;   
    
  clone = document.getElementById(data).cloneNode(true);
  clone.id = "newId" + num.toString();
  clone.style.position = "absolute";
  clone.style.left = (event.clientX+offsetx)+"px";
  clone.style.top = (event.clientY+offsety)+"px"; 

  ev.target.appendChild(clone);
}	
      

html, body { 
  height: 100%; 
  padding: 0; 
  margin: 0; 
}

div { 
  width: 50%; 
  height: 50%; 
  float: left; 
}

#div1 { 
  background: #DDD; 
}

#div2 {
  background: #AAA; 
}

#div3 {
  background: #777; 
}

#div4 { 
  background: #444; 
}

#imgDiv {
  width: 611px;
  height: 324px;
  border: 5px solid #DDD;
}
      

<div id="div1">
</div>

<div id="div2">
</div>

<div id="div3" ondrop="dropTrash(event)" ondragover="allowDrop(event)">
  <img  id="drag1" src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Bartagame_fcm.jpg/1200px-Bartagame_fcm.jpg" draggable="true" ondragstart="drag(event)" width="105" height="105">
  <img  id="drag2" src="http://www.earthtimes.org/newsimage/lizard_Ngo_Van_Tri_big_281.jpg" draggable="true" ondragstart="drag(event)" width="105" height="105">	
</div>

<div id="div4">
  <div align="center" id="imgDiv" ondrop="dropClone(event)" ondragover="allowDrop(event)"></div>
</div>
      

Run codeHide result


+3


source to share


1 answer


When you start dragging an image, you need to keep the cursor position relative to that particular image.

There are several position properties in MouseEvent to help you calculate this, but if browser support is not an issue, I have for MouseEvent.offsetX and MouseEvent.offsetY . From the docs:

The offsetX

/ offsetY

read-only property of the MouseEvent interface provides the offset at the coordinate X

/ Y

mouse pointer between this event and the padding edge of the target node.

So, dragstart

you just do:

x = e.offsetX;
y = e.offsetY;

      

Then, when you drop the image in yours, let it call it canvas (note the italics, as this is not an element <canvas>

, but any other element that you use as the dropout area <div>

in this particular example), you need to know the position of the cursor relative to of this canvas, so you might think you can use offsetX

and again offsetY

, and you're partially right. This will give you the expected value if you snap an image on the canvas itself, but there may be other images in it, and you can flush the current one on top of another, getting offsetX

and offsetY

relative instead.

What you can do is use MouseEvent.pageX

and MouseEvent.pageY

, and from that value, subtract the position (top left corner) of that canvas element, which you can get from HTMLElement.offsetLeft and HTMLElement.offsetTop :



e.pageX - imageCanvas.offsetLeft;
e.pageY - imageCanvas.offsetTop;

      

With this, you get the position of the cursor relative to the canvas element.

Now you need to subtract the value X

and Y

that you have stored on dragstart

, and it will give you the value left

and top

the upper-left corner of the drag image relative to the canvas element:

image.style.left = (e.pageX - imagesCanvas.offsetLeft - x) + 'px';
image.style.top = (e.pageY - imagesCanvas.offsetTop - y) + 'px';

      

Taken together, it will look like this:

let x;
let y;
let currentTarget = null;
let cloneElement = false;

function startDrag(e, clone) {
  const target = e.target;
  
  if (target.tagName === 'IMG') {
    x = e.offsetX;
    y = e.offsetY;
    currentTarget = target;
    cloneElement = clone;
  }
}

function cloneImage(e) {
  startDrag(e, true);
}

function moveImage(e) {
  startDrag(e, false);
}

function removeImage(e) { 
  if (!cloneElement) {
    currentTarget.remove();
  }
}

function stickImage(e) { 
  const image = cloneElement ? currentTarget.cloneNode(true) : currentTarget;
  
  imagesCanvas.appendChild(image);
  
  // + 1 for the border
  
  image.style.left = (e.pageX - imagesCanvas.offsetLeft - x + 1) + 'px';
  image.style.top = (e.pageY - imagesCanvas.offsetTop - y + 1) + 'px';
  
  currentTarget = null;
}

function allowDrag(e) {
  e.preventDefault();
}

// Bind event listeners:

const imagesBarElement = document.getElementById('imagesBar');
const imagesCanvasElement = document.getElementById('imagesCanvas');

document.addEventListener('dragenter', allowDrag);
document.addEventListener('dragover', allowDrag);

imagesBarElement.addEventListener('dragstart', cloneImage);
imagesBarElement.addEventListener('drop', removeImage);

imagesCanvasElement.addEventListener('dragstart', moveImage);
imagesCanvasElement.addEventListener('drop', stickImage);
      

body {
  margin: 0;
  font-size: 0;
  display: flex;
  flex-direction: column;
  height: 100vh;
  user-select: none;
}

img {
  width: 100px;
  height: 100px;
}

#imagesBar {
  height: 100px;
  border-bottom: 1px solid #CCC;
  padding: 10px 0;
}

#imagesBar > img {
  margin: 0 0 0 10px;
}

#imagesCanvas {
  position: relative;
  background: #EEE;
  flex-grow: 1;
  overflow: hidden;
}

#imagesCanvas > img {
  position: absolute;
}
      

<div id="imagesBar">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Bartagame_fcm.jpg/1200px-Bartagame_fcm.jpg" draggable="true">
  <img src="http://www.earthtimes.org/newsimage/lizard_Ngo_Van_Tri_big_281.jpg" draggable="true">	
</div>

<div id="imagesCanvas"></div>
      

Run codeHide result


+1


source







All Articles