Reputation: 163
I have built out basic drag and drop feature that allows us to drag randomly placed absolute positioned elements within a container. Ideally I would want to push other elements that possibly intersect the dragged elements boundaries away, but I am presently unable find a solution.
I have this for the Drag and Drop Solution:
var draggableElements = document.getElementsByClassName("team_member");
for(var i = 0; i < draggableElements.length; i++){
dragElement(draggableElements[i]);
}
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
pos3 = parseInt(e.clientX);
pos4 = parseInt(e.clientY);
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
return false;
}
function elementDrag(e) {
e = e || window.event;
pos1 = pos3 - parseInt(e.clientX);
pos2 = pos4 - parseInt(e.clientY);
pos3 = parseInt(e.clientX);
pos4 = parseInt(e.clientY);
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
elmnt.classList.add("drag");
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
elmnt.classList.remove("drag");
}
}
Upvotes: 2
Views: 306
Reputation: 3860
This is a cool task to implement, I played a bit and came up with something like this, but for some reason it's a big buggy, my idea was to use the API : document.elementFromPoint()
to get the intersecting element during the drag. It seems to work but it's a bit clumsy and sometimes it fails.
Probably it would work better with an IntersectionObserver
, that could also make sure to handle multiple boundary drag ( for example if you have 3+ objects, object one will push object 2 that will push object 3, object 3 has to react ).
const draggableElements = document.querySelectorAll(".team_member");
draggableElements.forEach((el, i) => makeDraggable(el, i))
function makeDraggable(elem, idx) {
elem.onmousedown = dragMouseDown;
elem.position = {
x: 0,
y: 0,
prevX: 0,
prevY: 0
}
elem.style.left = `calc(35% + ${(idx* 60) + "px"})`
}
// ----- //
function dragMouseDown(e) {
e = e || window.event;
this.position.prevX = +(e.clientX);
this.position.prevY = +(e.clientY);
document.onmouseup = closeDragElement;
document.onmousemove = (e) => elementDrag(e, this);
return false;
}
function elementDrag(e, t) {
t.position.x = t.position.prevX - +(e.clientX);
t.position.y = t.position.prevY - +(e.clientY);
t.position.prevX = +(e.clientX);
t.position.prevY = +(e.clientY);
t.style.top = (t.offsetTop - t.position.y) + "px";
t.style.left = (t.offsetLeft - t.position.x) + "px";
t.classList.add("drag");
// Check intersection
const width = t.getBoundingClientRect().width
const height = t.getBoundingClientRect().height
const intersectionElemTop = document.elementFromPoint(e.clientX, e.clientY - height / 2)
const intersectionElemRight = document.elementFromPoint(e.clientX + width / 2, e.clientY)
const intersectionElemBottom = document.elementFromPoint(e.clientX, e.clientY + height / 2)
const intersectionElemLeft = document.elementFromPoint(e.clientX - width / 2, e.clientY)
const intersections = [{
type: "top",
node: intersectionElemTop
}, {
type: "right",
node: intersectionElemRight
}, {
type: "bottom",
node: intersectionElemBottom
}, {
type: "left",
node: intersectionElemLeft
}].filter(i => [...draggableElements].some(d => i.node === d && d !== t))
if (intersections[0]) {
const i = intersections[0]
switch (i.type) {
case "top":
{
i.node.style.top = t.getBoundingClientRect().y - height + "px";
}
break;
case "right":
{
i.node.style.left = t.getBoundingClientRect().x + width + "px";
}
break;
case "bottom":
{
i.node.style.top = t.getBoundingClientRect().y + height + "px";
}
break;
case "left":
{
i.node.style.left = t.getBoundingClientRect().x - width + "px";
}
break;
}
i.node.classList.add("dragged");
clearTimeout(i.timeout)
i.timeout = setTimeout(() => i.node.classList.remove("dragged"), 500);
}
}
function closeDragElement(e) {
document.onmouseup = null;
document.onmousemove = null;
e.target.classList.remove("drag");
}
.team_member {
position: fixed;
width: 50px;
height: 50px;
border: 2px solid red;
display: flex;
justify-content: center;
align-items: center;
cursor: grab;
top: calc(50% - 25px);
}
.drag {
background: blue;
}
.dragged {
background: red;
}
<div class="team_member">
One
</div>
<div class="team_member">
Two
</div>
Upvotes: 1