I’m trying to make a drag-and-drop engine in JavaScript. Right now, I’m adding a bounds feature which will trap the .drag object inside its parent element. However, to do this, I need to understand how positioning works in html, and I don’t. Can anyone thoroughly explain it?
Javascript Engine:
// JavaScript Document
var posX;
var posY;
var element;
var currentPos;
document.addEventListener("mousedown", drag, false);
function drag(event) {
if(~event.target.className.search(/drag/)) {
element = event.target;
element.style.zIndex="100";
currentPos = findPos(element);
posX = event.clientX -currentPos.x;
posY = event.clientY -currentPos.y;
if(~event.target.className.search(/bound/))
document.addEventListener("mousemove", boundMovement, false);
else
document.addEventListener("mousemove", freeMovement, false);
}
}
function freeMovement(event) { // This functions works
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 boundMovement(event) { // This function doesn't work
if (typeof(element.mouseup) == "undefined")
document.addEventListener("mouseup", drop, false);
//Prevents redundantly adding the same event handler repeatedly
// Below logic is false- I wish to understand why =]
currentPos = findPos(element.offsetParent);
if((event.clientX - posX) <= currentPos.x)
element.style.left = event.clientX - posX + "px";
if((event.clientY - posY) <= currentPos.y)
element.style.top = event.clientY - posY + "px";
}
function drop() {
element.style.zIndex="1";
document.removeEventListener("mousemove", boundMovement, false);
document.removeEventListener("mousemove", freeMovement, false);
document.removeEventListener("mouseup", drop, false);
//alert("DEBUG_DROP");
}
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 };
}
}
Here is the CSS I am using:
@charset "utf-8";
/* CSS Document */
.drag {
position: absolute;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.bound {
/* Class to signify that the drag_object can not leave the parent element */
;
}
.square {
width: 100px;
height: 100px;
background: red;
cursor:move;
}
p {
padding: 0px;
margin: 0px;
outline-style: dotted;
outline-color: #000;
outline-width: 1px;
}
Some example HTML:
<p class="drag bound square">Thing One</p>
<p class="drag square">Thing Two</p>
Please note I am including the JavaScript so that if I have questions on how things are applied relative to what I’ve written. Also, thank you all for reading and helping. StackOverflow has been an exceptional resource in learning how to code in JavaScript.
EDIT:
1) I should say that I am coding the engine to help me learn the language. This is my first week of JavaScript, and I would like to be able to code in the language before I use a library.
2) For example I would really like for someone to explain how offsets are working here. I would like to know how instead of using position:absolute to make my JavaScript engine, I can use position:relative so that elements can stack on top of each other ect.
I’ve posted a solution at http://jsfiddle.net/vJ6r6/.
First of all, I nested the items to be dragged inside the bounding box:
Also, I turned them into div’s because p’s can’t be nested. (Don’t forget to change the style declaration as well.)
Then, I set styles on the bounding box:
The key property is
position: relative, which causes the items inside it to be positioned relative to it, rather than to the page. Note that because I’m using relative positioning, this example works best when you want to keep the items in a particular container.My changes to the JavaScript were more radical, so here’s the whole thing:
Note that this line:
Is equivalent to this: