pure javascript draggable element
Asked Answered
S

2

6

I know there're example of doing this on the web but every example is different and so is my own implementation. I'm trying to figure what's wrong with my implementation since it doesn't work as expected.

code snippet:

var mousePressX = -1;
var mousePressY = -1;

document.getElementById("contextMenu").addEventListener("mousedown", function(event) {
    mousePressX = event.clientX;
    mousePressY = event.clientY;
}, false);

document.getElementById("contextMenu").addEventListener("mouseup", function(event) {
    mousePressX = -1;
    mousePressY = -1;
}, false);

document.getElementById("contextMenu").addEventListener("mousemove", function(event) {
    if (mousePressX != -1 && mousePressY != -1) {
        repositionElement(event.target, event.clientX, event.clientY);
    }
}, false);

function repositionElement(element, currentMouseX, currentMouseY) {
    element.style.left = element.offsetLeft + (currentMouseX - mousePressX) + 'px';
    element.style.top = element.offsetTop + (currentMouseY - mousePressY) + 'px';
}

jsfiddle : http://jsfiddle.net/4rLctko8/

can't really figure out what's wrong but I've noticed that if I change the following lines:

element.style.left = element.offsetLeft + (currentMouseX - mousePressX) + 'px';
element.style.top = element.offsetTop + (currentMouseY - mousePressY) + 'px';

to :

element.style.left = currentMouseX - mousePressX + 'px';
element.style.top = currentMouseY - mousePressY + 'px';

The element will be properly dragged only when it's being dragged towards the positive x-axis (to the right) and towards the positive y-axis (to the bottom) and when mouseup is triggered it'll be positioned in somewhere near the left-most top-most corner area (around 0,0)

Sweeten answered 17/4, 2015 at 15:30 Comment(0)
O
19

Quite interesting, had so far only done it with jQuery. Rewrote it a bit and made sure that every mousemove has it's event listener removed afterwards - that would be a memory leak that you might start to notice otherwise :

http://jsfiddle.net/8wtq17L8/

var contextmenu = document.getElementById('contextMenu');
var initX, initY, mousePressX, mousePressY;

contextmenu.addEventListener('mousedown', function(event) {

    initX = this.offsetLeft;
    initY = this.offsetTop;
    mousePressX = event.clientX;
    mousePressY = event.clientY;

    this.addEventListener('mousemove', repositionElement, false);

    window.addEventListener('mouseup', function() {
      contextmenu.removeEventListener('mousemove', repositionElement, false);
    }, false);

}, false);

function repositionElement(event) {
    this.style.left = initX + event.clientX - mousePressX + 'px';
    this.style.top = initY + event.clientY - mousePressY + 'px';
}

Seems to be working well. :-)

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Edit - thought I'd add a version with touch support too (although newer devices seem to emulate mouse events). Not like Jquery where you can select multiple event listeners so it's mostly a repetition, just with touch events :

http://codepen.io/Shikkediel/pen/VLZKor?editors=011

var object = document.getElementById('element'),
initX, initY, firstX, firstY;

object.addEventListener('mousedown', function(e) {

    e.preventDefault();
    initX = this.offsetLeft;
    initY = this.offsetTop;
    firstX = e.pageX;
    firstY = e.pageY;

    this.addEventListener('mousemove', dragIt, false);

    window.addEventListener('mouseup', function() {
        object.removeEventListener('mousemove', dragIt, false);
    }, false);

}, false);

object.addEventListener('touchstart', function(e) {

    e.preventDefault();
    initX = this.offsetLeft;
    initY = this.offsetTop;
    var touch = e.touches;
    firstX = touch[0].pageX;
    firstY = touch[0].pageY;

    this.addEventListener('touchmove', swipeIt, false);

    window.addEventListener('touchend', function(e) {
        e.preventDefault();
        object.removeEventListener('touchmove', swipeIt, false);
    }, false);

}, false);

function dragIt(e) {
    this.style.left = initX+e.pageX-firstX + 'px';
    this.style.top = initY+e.pageY-firstY + 'px';
}

function swipeIt(e) {
    var contact = e.touches;
    this.style.left = initX+contact[0].pageX-firstX + 'px';
    this.style.top = initY+contact[0].pageY-firstY + 'px';
}
Obtest answered 17/4, 2015 at 16:59 Comment(5)
Thanks ! I wanted to ask did you do window.addEventListener('mouseup' ... instead of this.addEventListener('mouseup' ... to avoid the possibility that you can drag the div around and release the mouse where it's out of the div so the release event method won't be called?Sweeten
That's because that wasn't the question. It would need a loop then.Obtest
I know this is old but I keep finding drag&drop solutions while I simply want this dragging feature (so no dropEvents). So this is exactly what I've been looking for... The only issue I have (which also happens with your Fiddle/Codepen) is when you move too fast and your mouse get's outside the div, dragging stops... How do you prevent this?Ardehs
@Ardehs You only need to change the 'mousemove' with the dragIt function to be over window and not the element you are dragging, that way it's registered even if you move the mouse fast and thus outside the element.Creeps
Is there a way to listen to onclick events with the dragable object seems not to work in mobile touch mode only on desktop?Darrondarrow
F
0

Extending upon @Shikkediel answer, my version is here

Basically, I switched to an absolute positioned div and simply got the offset x, y and added them to the initial x - y of the dragged element. The absolute position also helps in case you have multiple divs inside a single container.

document.getElementById('dragHandle').addEventListener('mousedown', 
function(e) {

  e.preventDefault();
  originalY = e.clientY;
  originalX = e.clientX;
  elementY = object2.offsetTop;
  elementX = object2.offsetLeft;

  window.addEventListener('mousemove', dragIt, false);

  window.addEventListener('mouseup', function()
  {
      window.removeEventListener('mousemove', dragIt, false);
  }, false);

  }, false);

function dragIt(e)
{
  let deltaY = e.clientY - originalY;
  let deltaX = e.clientX - originalX;
  originalY = e.clientY;
  originalX = e.clientX;
  elementY += deltaY;
  elementX += deltaX;
  object2.style.top = elementY + "px";

  object2.style.left = Math.min(Math.max(container.getBoundingClientRect().left, elementX), container.getBoundingClientRect().right- object2.offsetWidth) + "px";
  object2.style.top = Math.min(Math.max(container.getBoundingClientRect().top, elementY), container.getBoundingClientRect().bottom - object2.offsetHeight) + "px";
}

I also included a drag handle and constrained the dragging to the parent #container.

Feucht answered 13/12, 2022 at 22:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.