I’m currently making a Drag-and-Drop engine in JavaScript. I’m currently working on making “bounds” for some “drag-able” objects. A drag-object has bounds if its parent (or a parent of a parent ect.) has the class .bound. The function I am using to find out if the drag-object is bounded is (Yes, this function also creates the drag-object.):
function makeObj(e) {
obj = new Object();
obj.element = e;
obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;
obj.posX = event.clientX - e.offsetLeft;
obj.posY = event.clientY - e.offsetTop;
var curleft = curtop = 0;
if (e.offsetParent) {
do {
curleft += e.offsetLeft;
curtop += e.offsetTop;
//alert(e.id + ":" + e.innerHTML);
if(~e.className.search(/bound/)) {
obj.boundX = curleft - obj.element.offsetLeft;
obj.boundY = curtop - obj.element.offsetTop;
return obj;
}
} while (e = e.offsetParent);
}
return obj;
}
For clarification: This function MAKES the drag-object. My problem lies in the loops. The loops don’t find the first parent node with a .bound class.
This html “should” affect the function:
<div id="center" class="bound">
<h1>Hello World! <hr /></h1>
<div id="box" class="bound">
<p class="drag square" id="one"> One </p>
<p class="drag square" id="two"> Two </p>
</div>
</div>
As much as this html:
<div id="center"> <!-- Difference is here -->
<h1>Hello World! <hr /></h1>
<div id="box" class="bound">
<p class="drag square" id="one"> One </p>
<p class="drag square" id="two"> Two </p>
</div>
</div>
However, the first html affects the loops (and how the drag objects behave), and I don’t know why.
P.S. The function is slightly broken. I haven’t managed to set the “correct” value for obj.boundX and obj.boundY without using this inferior (because it makes the parentNode the bound element regardless of class) function:
function makeBoundlessObj(e) {
obj = new Object();
obj.element = e;
obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;
obj.posX = event.clientX - e.offsetLeft;
obj.posY = event.clientY - e.offsetTop;
return obj;
}
I will post the entire engine below (and a jsfiddle link) just in case it is useful:
// JavaScript Document
var dragObj;
document.addEventListener("mousedown", down, false);
function down(event) {
if(~event.target.className.search(/drag/)) {
dragObj = makeObj(event.target);
dragObj.element.style.zIndex="100";
document.addEventListener("mousemove", freeMovement, false);
}
}
function freeMovement(event) {
if (typeof(dragObj.element.mouseup) == "undefined")
document.addEventListener("mouseup", drop, false);
//Prevents redundantly adding the same event handler repeatedly
dragObj.element.style.left = Math.max(0, Math.min(event.clientX - dragObj.posX, dragObj.boundX)) + "px";
dragObj.element.style.top = Math.max(0, Math.min(event.clientY - dragObj.posY, dragObj.boundY)) + "px";
}
function drop() {
dragObj.element.style.zIndex="1";
document.removeEventListener("mousemove", freeMovement, false);
document.removeEventListener("mouseup", drop, false);
//alert("DEBUG_DROP");
}
function makeBoundlessObj(e) {
obj = new Object();
obj.element = e;
obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;
obj.posX = event.clientX - e.offsetLeft;
obj.posY = event.clientY - e.offsetTop;
return obj;
}
function makeObj(e) {
obj = new Object();
obj.element = e;
obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;
obj.posX = event.clientX - e.offsetLeft;
obj.posY = event.clientY - e.offsetTop;
var curleft = curtop = 0;
if (e.offsetParent) {
do {
curleft += e.offsetLeft;
curtop += e.offsetTop;
//alert(e.id + ":" + e.innerHTML);
if(~e.className.search(/bound/)) {
obj.boundX = curleft - obj.element.offsetLeft;
obj.boundY = curtop - obj.element.offsetTop;
return obj;
}
} while (e = e.offsetParent);
}
return obj;
}
function findPos(obj) { // Donated by `lwburk` on StackOverflow
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return { x: curleft, y: curtop };
}
}
In case the problem was not clear:
My JavaScript function makeObj() isn’t setting the correct boundX and boundY because elements with the class .bound are affecting the function when they shouldn’t be.
Thank you all for reading and helping!
As far as I can tell, the loop is functioning as you desire. It is finding the first element tagged with the
boundclass. The problem you’re seeing is related to theposition:relativethat comes along with theboundclass.Consider the following HTML:
It functions identically to your “first” HTML (the one where center is tagged with the
boundclass).The important thing here is that tagging an element with
position:relativeorposition:absolutemakes the child elements see its upper left corner as(0,0). In CSS, child elements look up to their first ancestor that is tagged with a relative or absolute position. Elements that are not tagged as such are not seen by the child as having an upper left corner at(0,0).The trouble here is that you’re using the
offsetLeftandoffsetTopof the desired bound (the nearest ancestor with theboundclass; in this casebox), which varies when that element’s nearest ancestor tagged with relative/absolute changes. In the first case, the nearest positioned ancestor iscenter… in the second case it’s the document. In the first casemakeObjreturns (0, 22). In the second it returns (108,82).Unless you’re doing this as an academic exercise or a fun project, consider just using an existing DnD library like the one that comes with Dojo: http://docs.dojocampus.org/dojo/dnd