Unique version of w3schools example
If you want to achieve a similar effect as demonstrated in the linked w3schools example, you can utilize the CSS property position: absolute
. However, if you do not specify values for top
, left
, etc., the default values will be applied: top: 0
and left: 0
. This will result in the elements stacking on top of each other due to them all appearing at the same location.
To prevent this stacking behavior, you need to assign different values for top
, left
, etc. to each absolutely positioned element. For instance:
#mydiv2 {
top: 170px;
}
This solution addresses the scenario with two manually draggable elements, but may not be ideal for dynamically added content.
Functional demonstration:
To simplify the implementation, I omitted the initial if ... else
block within the dragElement()
function and directly attached the event listener to the entire element:
elmnt.onmousedown = dragMouseDown;
//Enable dragging for the DIV element:
dragElement(document.getElementById("mydiv2"));
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// Obtain the initial mouse cursor position:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// Call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// Calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// Set the new position for the element:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// Stop moving when the mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
#mydiv,
#mydiv2 {
position :absolute;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
cursor: move;
border: 1px solid #d3d3d3;
}
#mydiv2 {
top: 170px;
}
#mydivheader,
#mydivheader2 {
padding: 10px;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<div class="container">
<div class="row">
<div id="mydiv" class="col-sm-10">
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
<div id="mydiv2" class="col-sm-10">
<div id="mydivheader2">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
</div>
Applying transform: translate()
Basic setup
To handle dynamically generated content or cases where explicit positioning properties are not desired, consider utilizing transform: translate()
while omitting position: absolute
. This approach ensures that elements retain their positions without overlapping.
To implement this, adjust the existing calculation by subtracting the original values from the old translate
values before updating them with this difference:
pos1 = pos1 - (pos3 - e.clientX);
pos2 = pos2 - (pos4 - e.clientY);
Lastly, modify the styling lines from using top
and left
to a single line with translate
:
elmnt.style.transform = 'translate(' + (pos1) + "px, " + (pos2) + "px)";
Functional demonstration:
I updated the outdated var
declaration to let
since these variables are mutable.
//Enable dragging for the DIV element:
dragElement(document.getElementById("mydiv2"));
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// Obtain the initial mouse cursor position:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// Call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// Calculate the new cursor position:
pos1 = pos1 - (pos3 - e.clientX);
pos2 = pos2 - (pos4 - e.clientY);
pos3 = e.clientX;
pos4 = e.clientY;
// Set the new position for the element:
elmnt.style.transform = 'translate(' + (pos1) + "px, " + (pos2) + "px)";
}
function closeDragElement() {
// Stop moving when the mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
#mydiv,
#mydiv2 {
width: 160px;
background-color: #f1f1f1;
text-align: center;
cursor: move;
border: 1px solid #d3d3d3;
}
#mydivheader,
#mydivheader2 {
padding: 10px;
background-color: #2196F3;
color: #fff;
}
<div class="container">
<div class="row">
<div id="mydiv" class="col-sm-10">
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
<div id="mydiv2" class="col-sm-10">
<div id="mydivheader2">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
</div>
Descriptive variable names
The variable names used in the w3schools example pos1, pos2, pos3, pos4
might not provide clear context. It would be beneficial to rename them for better clarity: translate = { x: 0, y: 0 }
and client = { x: 0, y: 0 }
.
Functional demonstration:
//Enable dragging for the DIV element:
dragElement(document.getElementById("mydiv2"));
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
let translate = { x: 0, y: 0 };
let client = { x: 0, y: 0 };
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// Obtain the initial mouse cursor position:
client.x = e.clientX;
client.y = e.clientY;
document.onmouseup = closeDragElement;
// Call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// Calculate the new cursor position:
translate.x = translate.x - (client.x - e.clientX);
translate.y = translate.y - (client.y - e.clientY);
client.x = e.clientX;
client.y = e.clientY;
// Set the new position for the element:
elmnt.style.transform = 'translate(' + (translate.x) + "px, " + (translate.y) + "px)";
}
function closeDragElement() {
// Stop moving when the mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
#mydiv,
#mydiv2 {
width: 160px;
border: 1px solid #d3d3d3;
text-align: center;
cursor: move;
background-color: #f1f1f1;
}
#mydivheader,
#mydivheader2 {
padding: 10px;
background-color: #2196F3;
color: #fff;
}
<div class="container">
<div class="row">
<div id="mydiv" class="col-sm-10">
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
<div id="mydiv2" class="col-sm-10">
<div id="mydivheader2">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
</div>
Final version
For an integrated solution showcasing the functionality with dynamically added draggable components, refer to the following definitive implementation. I switched the outdated var
declarations to const
considering these variables remain constant.
Functional demonstration:
const d = ["module1", "module2", "module3", "module4", "module5"];
for(i in d) {
append_module_name_to_drag_div(d[i]);
dragElement(document.getElementById(d[i]));
}
function append_module_name_to_drag_div(module_name) {
const mydiv = document.createElement("div");
mydiv.id = module_name;
mydiv.className = 'module col-sm-10';
const mydivmarker = document.createElement("div");
mydivmarker.id = module_name+"header";
mydivmarker.className = 'mydivheader';
const marker_image = new Image();
marker_image.src = "http://www.clker.com/cliparts/w/O/e/P/x/i/map-marker-hi.png";
marker_image.height = 45;
marker_image.width = 35;
mydivmarker.append(marker_image);
mydiv.innerHTML = module_name;
mydiv.append(mydivmarker);
document.getElementById("markers").appendChild(mydiv);
}
function dragElement(elmnt) {
let translate = { x: 0, y: 0 };
let client = { x: 0, y: 0 };
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// Obtain the initial mouse cursor position:
client.x = e.clientX;
client.y = e.clientY;
document.onmouseup = closeDragElement;
// Call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// Calculate the new cursor position:
translate.x = translate.x - (client.x - e.clientX);
translate.y = translate.y - (client.y - e.clientY);
client.x = e.clientX;
client.y = e.clientY;
// Set the new position for the element:
elmnt.style.transform = 'translate(' + (translate.x) + "px, " + (translate.y) + "px)";
}
function closeDragElement() {
// Stop moving when the mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
.module {
width: 80px;
border: 1px solid #d3d3d3;
text-align: center;
cursor: move;
background-color: #f1f1f1;
}
.mydivheader {
padding: 10px;
background-color: #2196F3;
color: #fff;
}
<div class="container">
<div id="markers" class="row">
</div>
</div>