Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing drag and drop on relatively positioned elements in JavaScript

I apologize for posting so many questions- I'm still learning! So, I can drag and drop the first element in the html no problem; however, when I try to drag and drop the second one, it appears quite a bit below the mouse. It still drags wherever I move the mouse, but far below. What's wrong?

Here is the javascript:

// JavaScript Document

var posX;
var posY;
var element;

document.addEventListener("mousedown", drag, false);

function drag(event) {
    if(event.target.className == "square") {
        element = event.target;
        posX = event.clientX -parseInt(element.offsetLeft);
        posY = event.clientY -parseInt(element.offsetTop);
        document.addEventListener("mousemove", move, false);
    }
}

function move(event) {

    if (typeof(element.mouseup) == "undefined")
        document.addEventListener("mouseup", drop, false);
    //Prevents redundantly adding the same event handler repeatedly

    element.style.left = event.clientX - posX + "px";
    element.style.top = event.clientY - posY + "px";
}    

function drop() {
    document.removeEventListener("mousemove", move, false);
    document.removeEventListener("mouseup", drop, false);
    //alert("DEBUG_DROP");
}    

Here is the html:

<body>

<p class="square">Thing One</p>
<p class="square">Thing Two</p>

</body>

Here is the css:

/* CSS Document */

.square {
    position: relative;
    width: 100px;
    height: 100px;
    background: red;
}

p {
    padding: 0px;
    margin: 0px;
}

Thank you all for your time! I greatly appreciate it!

like image 355
Dbz Avatar asked Aug 24 '26 15:08

Dbz


2 Answers

There are two separate issues to consider here:

  1. How can I get the position of an element on the page?
  2. What happens when I assign new values to the left and top style properties?

The answer to the first question relies on an understanding of element.offsetLeft and element.offsetTop. These properties give the offset relative to element.offsetParent which is defined as "the closest (nearest in the containment hierarchy) positioned containing element".

In your document this is the <body> element, so it works as you expected. If you were to place your squares inside other elements you'd find that your code would stop working. What you'd need is a function to walk up the tree of containing elements and sum each of the offsets, like this:

function findPos(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
}

Used like this:

var pos= findPos(element);
posX = event.clientX - pos.x;
posY = event.clientY - pos.y;

Answering the second question requires an understanding of relatively positioned elements. Elements that are positioned relatively appear in a position relative to where they would normally appear on the page. When you assign values to top and left you're not giving absolute values. You're giving positions that are treated as relative to the element's original position in the layout. This is a feature of relative positioning, not a bug. You probably want to use position: absolute; instead.

like image 115
Wayne Avatar answered Aug 26 '26 06:08

Wayne


if you're using relative positioning somewhere, then the element's offset may not be relative to the top-left of the document.

you need to find the absolute offset of the element.

like image 20
Kae Verens Avatar answered Aug 26 '26 05:08

Kae Verens