Simple drag and drop code
Asked Answered
M

5

11

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);
}
Mattland answered 25/8, 2013 at 2:27 Comment(0)
B
12

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.

Bonni answered 25/8, 2013 at 2:58 Comment(5)
Thanks for the detailed reply. I was using the Do While for mousemove while mousedown is active, otherwise it should not run... if I enable the Do While loop, Firefox comes to a halt though.Mattland
@Mattland I gotcha, though it won't be necessary due to how often the mousemove event calls eleMouseMove()Bonni
I updated it a little for my requirement. It can be helpful for others too, thus jsfiddle.net/kjwLe9bq sharing.Plop
This is from long ago, but it's worth noting (as the code in the last comment demonstrates) that the event listener for mouseup should be added in the eleMouseDown function, not in eleMouseMove; the latter is called a lot, and you don't want to be adding a mouseup listener every time the user moves their mouse.Mcclinton
Version to avoid the jump on the initial mouse move: jsfiddle.net/fpb7j/308Greenwood
D
12

you can try this fiddle too, http://jsfiddle.net/dennisbot/4AH5Z/

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>titulo de mi pagina</title>
<style>
    #target {
        width: 100px;
        height: 100px;
        background-color: #ffc;
        border: 2px solid blue;
        position: absolute;
    }
</style>
<script>
   window.onload = function() {
        var el = document.getElementById('target');
        var mover = false, x, y, posx, posy, first = true;
        el.onmousedown = function() {
            mover = true;
        };
        el.onmouseup = function() {
            mover = false;
            first = true;
        };
        el.onmousemove = function(e) {
            if (mover) {
                if (first) {
                    x = e.offsetX;
                    y = e.offsetY;
                    first = false;
                }
                posx = e.pageX - x;
                posy = e.pageY - y;
                this.style.left = posx + 'px';
                this.style.top = posy + 'px';
            }
        };
   }
</script>
</head>
<body>
    <div id="target" style="left: 10px; top:20px"></div>
</body>
</html>
Denouement answered 11/2, 2014 at 6:30 Comment(2)
Why do you use offsetX/Y?Underact
To stop the draggable jumping to the mouse pointer. I get it.Underact
C
1

I've just made a simple drag.

It's a one liner usage, and it handles things like the offset of the mouse to the top left corner of the element, onDrag/onStop callbacks, and SVG elements dragging

Here is the code.

// simple drag
function sdrag(onDrag, onStop) {
    var startX = 0;
    var startY = 0;
    var el = this;
    var dragging = false;

    function move(e) {
        el.style.left = (e.pageX - startX ) + 'px';
        el.style.top = (e.pageY - startY ) + 'px';
        onDrag && onDrag(el, e.pageX, startX, e.pageY, startY);
    }

    function startDragging(e) {
        if (e.currentTarget instanceof HTMLElement || e.currentTarget instanceof SVGElement) {
            dragging = true;
            var left = el.style.left ? parseInt(el.style.left) : 0;
            var top = el.style.top ? parseInt(el.style.top) : 0;
            startX = e.pageX - left;
            startY = e.pageY - top;
            window.addEventListener('mousemove', move);
        }
        else {
            throw new Error("Your target must be an html element");
        }
    }

    this.addEventListener('mousedown', startDragging);
    window.addEventListener('mouseup', function (e) {
        if (true === dragging) {
            dragging = false;
            window.removeEventListener('mousemove', move);
            onStop && onStop(el, e.pageX, startX, e.pageY, startY);
        }
    });
}

Element.prototype.sdrag = sdrag;

and to use it:

document.getElementById('my_target').sdrag();

You can also use onDrag and onStop callbacks:

document.getElementById('my_target').sdrag(onDrag, onStop);

Check my repo here for more details: https://github.com/lingtalfi/simpledrag

Conveyancing answered 2/9, 2016 at 19:12 Comment(0)
G
1

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

Gangrel answered 26/6, 2020 at 3:15 Comment(1)
of course you should use CSS classes instead of inline styles. consider it 'quick and dirty'.Gangrel
A
-2

https://docs.oracle.com/javase/8/javafx/events-tutorial/hellodraganddropjava.htm#CHDEAEAI

Simple way using dragboard and ClipBoard

Almedaalmeeta answered 17/7, 2023 at 13:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.