Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple drag and drop code

Im struggling with seemingly a simple javascript exercise, writing a vanilla drag and drop. I think Im making a mistake with my 'addeventlisteners', here is the code:

var ele = document.getElementsByClassName ("target")[0];
var stateMouseDown = false;
//ele.onmousedown = eleMouseDown;
ele.addEventListener ("onmousedown" , eleMouseDown , false);

function eleMouseDown () {
    stateMouseDown = true;
    document.addEventListener ("onmousemove" , eleMouseMove , false);
}

function eleMouseMove (ev) {
    do {
        var pX = ev.pageX;
        var pY = ev.pageY;
        ele.style.left = pX + "px";
        ele.style.top = pY + "px";
        document.addEventListener ("onmouseup" , eleMouseUp , false);
    } while (stateMouseDown === true);
}

function eleMouseUp () {
    stateMouseDown = false;
    document.removeEventListener ("onmousemove" , eleMouseMove , false);
    document.removeEventListener ("onmouseup" , eleMouseUp , false);
}
like image 356
Kayote Avatar asked Aug 25 '13 02:08

Kayote


People also ask

How drag and drop works in JavaScript?

The HTML Drag and Drop API relies on the DOM's event model to get information on what is being dragged or dropped and to update that element on drag or drop. With JavaScript event handlers, you can turn any element into a draggable item or an item that can be dropped into.

Is drag and drop possible using HTML5?

Complete HTML/CSS Course 2022 Now HTML 5 came up with a Drag and Drop (DnD) API that brings native DnD support to the browser making it much easier to code up. HTML 5 DnD is supported by all the major browsers like Chrome, Firefox 3.5 and Safari 4 etc.


2 Answers

this is how I do it

var MOVE = {
  startX: undefined,
  startY: undefined,
  item: null
};

function contentDiv(color, width, height) {
  var result = document.createElement('div');
  result.style.width = width + 'px';
  result.style.height = height + 'px';
  result.style.backgroundColor = color;
  return result;
}

function movable(content) {
  var outer = document.createElement('div');
  var inner = document.createElement('div');
  outer.style.position = 'relative';
  inner.style.position = 'relative';
  inner.style.cursor = 'move';
  inner.style.zIndex = 1000;
  outer.appendChild(inner);
  inner.appendChild(content);
  inner.addEventListener('mousedown', function(evt) {
    MOVE.item = this;
    MOVE.startX = evt.pageX;
    MOVE.startY = evt.pageY;
  })
  return outer;
}

function bodyOnload() {
  document.getElementById('td1').appendChild(movable(contentDiv('blue', 100, 100)));
  document.getElementById('td2').appendChild(movable(contentDiv('red', 100, 100)));
  document.addEventListener('mousemove', function(evt) {
    if (!MOVE.item) return;
    if (evt.which!==1){ return; }
    var dx = evt.pageX - MOVE.startX;
    var dy = evt.pageY - MOVE.startY;
    MOVE.item.parentElement.style.left = dx + 'px';
    MOVE.item.parentElement.style.top = dy + 'px';
  });
  document.addEventListener('mouseup', function(evt) {
    if (!MOVE.item) return;
    var dx = evt.pageX - MOVE.startX;
    var dy = evt.pageY - MOVE.startY;
    var sty = MOVE.item.style;
    sty.left = (parseFloat(sty.left) || 0) + dx + 'px';
    sty.top = (parseFloat(sty.top) || 0) + dy + 'px';
    MOVE.item.parentElement.style.left = '';
    MOVE.item.parentElement.style.top = '';
    MOVE.item = null;
    MOVE.startX = undefined;
    MOVE.startY = undefined;
  });
}
bodyOnload();
table {
user-select: none
}
<table>
  <tr>
    <td id='td1'></td>
    <td id='td2'></td>
  </tr>
</table>

While dragging, the left and right of the style of the parentElement of the dragged element are continuously updated. Then, on mouseup (='drop'), "the changes are committed", so to speak; we add the (horizontal and vertical) position changes (i.e., left and top) of the parent to the position of the element itself, and we clear left/top of the parent again. This way, we only need JavaScript variables for pageX, pageY (mouse position at drag start), while concerning the element position at drag start, we don't need JavaScript variables for that (just keeping that information in the DOM).

If you're dealing with SVG elements, you can use the same parent/child/commit technique. Just use two nested g, and use transform=translate(dx,dy) instead of style.left=dx, style.top=dy

like image 93
mathheadinclouds Avatar answered Sep 17 '22 20:09

mathheadinclouds


Here's a jsfiddle with it working: http://jsfiddle.net/fpb7j/1/

There were 2 main issues, first being the use of onmousedown, onmousemove and onmouseup. I believe those are only to be used with attached events:

document.body.attachEvent('onmousemove',drag);

while mousedown, mousemove and mouseup are for event listeners:

document.body.addEventListener('mousemove',drag);

The second issue was the do-while loop in the move event function. That function's being called every time the mouse moves a pixel, so the loop isn't needed:

var ele = document.getElementsByClassName ("target")[0];
ele.addEventListener ("mousedown" , eleMouseDown , false);

function eleMouseDown () {
    stateMouseDown = true;
    document.addEventListener ("mousemove" , eleMouseMove , false);
}

function eleMouseMove (ev) {
    var pX = ev.pageX;
    var pY = ev.pageY;
    ele.style.left = pX + "px";
    ele.style.top = pY + "px";
    document.addEventListener ("mouseup" , eleMouseUp , false);
}

function eleMouseUp () {
    document.removeEventListener ("mousemove" , eleMouseMove , false);
    document.removeEventListener ("mouseup" , eleMouseUp , false);
}

By the way, I had to make the target's position absolute for it to work.

like image 22
iRector Avatar answered Sep 20 '22 20:09

iRector