Detect container, while moving an element over it - javascript

I making a simple drag'n'drop interface. I have a bunch of containers ("wrapper") and some dynamically added items ("dragElement") in one of them. So I need, when I move item over another container, JS detect it and move the item there when the drag is finished.
I tried to detect container with "onmouseover" and "mouseup" when dragging item, but had no success, because, actually, mouse always was over the dragged element.
So how can I detect container when drag item? In pure JS please...
document.onmousedown = function(e) {
var dragElement = e.target;
if (!dragElement.classList.contains('draggable')) return;
var coords, shiftX, shiftY, detectPage;
startDrag(e.clientX, e.clientY);
document.onmousemove = function(e) {
moveAt(e.clientX, e.clientY);
};
wrapper.onmouseover = function(e) {
detectPage = e.target;
console.log(detectPage);
};
dragElement.onmouseup = function() {
finishDrag();
};
function startDrag(clientX, clientY) {
shiftX = clientX - dragElement.getBoundingClientRect().left;
shiftY = clientY - dragElement.getBoundingClientRect().top;
dragElement.style.position = 'fixed';
document.body.appendChild(dragElement);
moveAt(clientX, clientY);
};
function finishDrag() {
dragElement.style.top = parseInt(dragElement.style.top) - wrapper.getBoundingClientRect().top + 'px';
dragElement.style.position = 'absolute';
wrapper.onmouseup = function(e) {
var selectPage = e.target;
}
wrapper.appendChild(dragElement);
document.onmousemove = null;
dragElement.onmouseup = null;
};
function moveAt(clientX, clientY) {
var newX = clientX - shiftX;
var newY = clientY - shiftY;
if (newX < 0) newX = 0;
if (newX > wrapper.offsetWidth - dragElement.offsetWidth) {
newX = wrapper.offsetWidth - dragElement.offsetWidth;
}
dragElement.style.left = newX + 'px';
dragElement.style.top = newY + 'px';
};
return false;
};

Well, no one help. So one free day gone to find the solution. All I can found is to delete function finishDrag() from dragElement.onmouseup and change it to the code below.
If in shorter, when onmouseup comes, dragElement must go to display:none and now we can get access to the object near the mouse cursor through elementFromPoint. When we done with it, we can easily detects container, bring an element back to display:block and put it to that container...
Hope, it helps to someone...
dragElement.onmouseup = function(e) {
dragElement.style.display = 'none';
var selectPage = document.elementFromPoint(e.clientX, e.clientY);
dragElement.style.display = 'block';
dragElement.style.top = parseInt(dragElement.style.top) - selectPage.getBoundingClientRect().top + 'px';
dragElement.style.position = 'absolute';
selectPage.appendChild(dragElement);
document.onmousemove = null;
dragElement.onmouseup = null;
};

Related

How to make text inside a draggable div selectable with a mouse in Javascript?

So, I have a div with a table inside and a form at the bottom. The div is a popup and has a draggable functionality, but when I select any text inside the div using the mouse, the div moves. Currently, the only way to select text is through double-click.
What's the way to achieve this in Javascript?
Here's the code for the drag functionality:
var drag = new Object();
drag.obj = editTable;
drag.obj.addEventListener('mousedown', function(e) {
drag.top = parseInt(drag.obj.offsetTop);
drag.left = parseInt(drag.obj.offsetLeft);
drag.oldx = drag.x;
drag.oldy = drag.y;
drag.drag = true;
});
window.addEventListener('mouseup', function() {
drag.drag = false;
});
window.addEventListener('mousemove', function(e) {
drag.x = e.clientX;
drag.y = e.clientY;
var diffw = drag.x - drag.oldx;
var diffh = drag.y - drag.oldy;
if (drag.drag) {
drag.obj.style.left = drag.left + diffw + 'px';
drag.obj.style.top = drag.top + diffh + 'px';
e.preventDefault();
}
});
Thanks in advance!

Move multiple divs on the same page

My problem is when I add a mousemove listener on document, all divs are moving but when I add a mousemove listener on my element, I have to move the cursor slowly.
Here is my code :
let componentsItems = document.getElementsByClassName("componentItem");
[].forEach.call(componentsItems, function (componentItem) {
componentItem.addEventListener("click", function (event) {
let selectedComponent = getComponentToDisplay(event.target.getAttribute("data-exchange"));
let mapContainer = document.getElementById("mapContainer");
let mainElement = document.createElement("div");
mainElement.innerHTML = "test";
mainElement.style.position = "absolute";
mapContainer.appendChild(mainElement);
mainElement.addEventListener("mouseup", function (e) {
isDown = false;
});
mainElement.addEventListener("mousedown", function (e) {
isDown = true;
offset = [
mainElement.offsetLeft - e.clientX,
mainElement.offsetTop - e.clientY
];
});
document.addEventListener("mousemove", function (e) {
e.preventDefault();
mousePosition = {
x: e.clientX,
y: e.clientY
};
let left = (mousePosition.x + offset[0]);
let top = (mousePosition.y + offset[1]);
if(isDown){
if(mapContainer.offsetTop < top && mapContainer.offsetWidth > left){
mainElement.style.left = left + 'px';
mainElement.style.top = top + 'px';
}
}
});
});
});
For each component in my menu, I add an onclick listener to appendChild element in the "MapContainer" div.
The drag and drop problem.
The problem is you are attaching multiple mousemove listeners to document, and each one with every one of the different mainElements.
The solution:
Remember which element we are about to move.
mainElement.addEventListener("mousedown", function (e) {
isDown = true;
element = mainElement;
offset = [
mainElement.offsetLeft - e.clientX,
mainElement.offsetTop - e.clientY
];
});
On the outter scope (outside foreach) create a unique mousemove event listener, and update the element that we mousedowned before.
document.addEventListener("mousemove", function (e) {
e.preventDefault();
mousePosition = {
x: e.clientX,
y: e.clientY
};
let left = (mousePosition.x + offset[0]);
let top = (mousePosition.y + offset[1]);
if(isDown){
if(mapContainer.offsetTop < top && mapContainer.offsetWidth > left){
element.style.left = left + 'px';
element.style.top = top + 'px';
}
}
});
Other ways to solve this problem is to create (and delete) the eventlistener on the mousedown and mouseup event handlers respectively. But I believe it's less efficient and definitely more complicated.

Jquery multiple div same class, drag just "this" div

I'm using a drag function (not jquery UI, I don't want Jquery UI) on a div with a class, but I have more div with the same class, How can I intercept the click on this div
Here my code:
$(function(){
var dragging = false;
var iX, iY;
// how can I intercept $(this, ".marker") ??
$(".marker").mousedown(function(e) {
dragging = true;
iX = e.clientX - this.offsetLeft;
iY = e.clientY - this.offsetTop;
this.setCapture && this.setCapture();
return false;
});
document.onmousemove = function(e) {
if (dragging) {
var e = e || window.event;
var oX = e.clientX - iX;
var oY = e.clientY - iY;
// how can I find the ID related to this div ?
$('.marker').css({"left":oX + "px", "top":oY + "px"});
return false;
}
};
$(document).mouseup(function(e) {
dragging = false;
// $(".marker")[0].releaseCapture();
e.cancelBubble = true;
})
})
And here the original codePen https://codepen.io/Jonh/pen/jgyLB
Here the JS that create the div, they are created by JS dynamically
for (i = 0; i < theFeat.length; i++) {
markerText = theFeat[i].value;
mk_totalHeight += 50;
$('<div>', { id: 'd' + i, style:"top:" + mk_totalHeight + "px;"}).addClass('marker').appendTo('#map');
$('<div>', { id: i, style:"background-image:url('../../../symbols/marker" + (i + 1) + ".png');" }).addClass('markerIcon').appendTo('#d'+ i);
$('<span>', { id: 's' + i, text: markerText}).appendTo('#d' + i);
} // end for loop
It's useful if you have just one div but how can I implement that on a class that is on a various div, I have to copy the function and add as a select the ID? (the max allowed div are 4, so it will be #d0, #d1, #d2, #d3)
So one of your listeners,
// how can I intercept $(this, ".marker") ??
$(".marker").mousedown(function(e) {
dragging = true;
iX = e.clientX - this.offsetLeft;
iY = e.clientY - this.offsetTop;
this.setCapture && this.setCapture();
return false;
});
...won't, in fact, work as you expect. Because the .marker elements are being created dynamically, event listeners on them will fail. Rather, listen at the nearest parent node:
// Try something like this:
$("#map").on("mousedown", ".marker", function(e){
// Either of the following should get to the element that
// triggered the mousedown
var target = $(this);
// OR YOU CAN USE
var target = $(e.currentTarget);
// ... whatever other processing you need...
});
After the comment of #Snowmonkey I notice that the problem was on document.onmousemove where do you change the CSS property, this is my solution.
I created a var to get the selected div
$(".marker").mousedown(function(e) {
dragging = true;
mdiv = $(this);
iX = e.clientX - this.offsetLeft;
iY = e.clientY - this.offsetTop;
this.setCapture && this.setCapture();
return false;
});
Then on the onmousemove function, I have the target stored on a var and I can get the ID
document.onmousemove = function(e) {
if (dragging) {
var e = e || window.event;
var oX = e.clientX - iX;
var oY = e.clientY - iY;
$("#" + mdiv.attr('id')).css({"left":oX + "px", "top":oY + "px"});
return false;
}
};

Drag div content by grabbing its background

When the content goes outside the div, we use scrollbars to see it. How can I scroll the div content by grabbing and dragging its background? I've searched the solution but did not find what I need. Here is my fiddle:
https://jsfiddle.net/vaxobasilidze/xhn49e1j/
Drag any item to the right div and move it outside the container to the right or bottom. scrollbars appear to help you to scroll. Here is an example of what I want to achieve. See the first diagram on the link and drag it:
https://jsplumbtoolkit.com/
Any tips on how to do this?
You should just need to detect when the mouse is down and then when the mouse is moving afterwards you can store the previous mouse coordinates and reference the current coordinates. Finally you can scroll the div in question by an amount based on the difference in drag since the last mousemove call.
var mouseDown = false;
var prevCoords = { x: 0, y: 0 };
$("#mainDiv").mousedown(function() {
mouseDown = true;
}).mousemove(function(e) {
var currentScrollX = $('#mainDiv').scrollLeft();
var currentScrollY = $('#mainDiv').scrollTop();
if(mouseDown) {
$('#mainDiv').scrollLeft(currentScrollX + prevCoords.x - (e.clientX + currentScrollX))
$('#mainDiv').scrollTop(currentScrollY + prevCoords.y - e.clientY)
};
prevCoords.x = e.clientX + currentScrollX;
prevCoords.y = e.clientY;
}).mouseup(function() {
mouseDown = false;
});
https://jsfiddle.net/6rx30muh/
EDIT: Fixed bug with wiggling tables when dragging:
var mouseDown = false;
var prevCoords = { x: 0, y: 0 };
$("#mainDiv").mousedown(function() {
mouseDown = true;
}).mousemove(function(e) {
var currentScrollX = $('#mainDiv').scrollLeft();
var currentScrollY = $('#mainDiv').scrollTop();
if(mouseDown) {
$('#mainDiv').scrollLeft(currentScrollX + prevCoords.x - e.clientX)
$('#mainDiv').scrollTop(currentScrollY + prevCoords.y - e.clientY)
};
prevCoords.x = e.clientX;
prevCoords.y = e.clientY;
}).mouseup(function() {
mouseDown = false;
});
Check for mousemove between mousedown and mouseup on the body element is a good place to start.
element = $('body');
element.addEventListener("mousedown", function(){
flag = 0;
}, false);
element.addEventListener("mousemove", function(){
flag = 1;
}, false);
element.addEventListener("mouseup", function(){
if(flag === 0){
console.log("click");
}
else if(flag === 1){
console.log("drag");
}
}, false);

draggable div problem

I found this function to make my divs draggable and it works fine. right now if i have my mouse anywhere on the div it drags, but i only want it to drag the div if my mouse is on the rd_header div. here is the function
var makeDraggable = function(element) {
element = jQuery(element);
var move = function(event) {
if(element.data('mouseMove')) {
var changeX = event.clientX - element.data('mouseX');
var changeY = event.clientY - element.data('mouseY');
var newX = parseInt(element.css('left')) + changeX;
var newY = parseInt(element.css('top')) + changeY;
element.css('left', newX);
element.css('top', newY);
element.data('mouseX', event.clientX);
element.data('mouseY', event.clientY);
}
}
element.mousedown(function(event) {
element.data('mouseMove', true);
element.data('mouseX', event.clientX);
element.data('mouseY', event.clientY);
});
element.parents(':last').mouseup(function() {
element.data('mouseMove', false);
});
element.mouseout(move);
element.mousemove(move);
}
and i call it with this
makeDraggable(jQuery('#rd_main'));
i tried calling iot on the header div instead and changing the function variables element. to element.closest('div') but had no luck. i would appreciate any help
here is my divs
<div id="rd_main">
<div class="rd_header">Action Log</div>
<div id="rd_logdiv" class="sb"></div>
</div>
makeDraggable('#rd_main', 'rd_header');
Then update your function with this:
var makeDraggable = function(element, triggerClass) {
element = $(element);
var move = function(event) {
if (element.data('mouseMove') && isAvailable) {
var changeX = event.clientX - element.data('mouseX');
var changeY = event.clientY - element.data('mouseY');
var newX = parseInt(element.css('left')) + changeX;
var newY = parseInt(element.css('top')) + changeY;
element.css('left', newX);
element.css('top', newY);
element.data('mouseX', event.clientX);
element.data('mouseY', event.clientY);
}
},
isAvailable = false;
element.mousedown(function(event) {
var target = $(event.target);
isAvailable = target.hasClass(triggerClass) || target.closest('.' + triggerClass); //Check if we over wanted element
element.data('mouseMove', true);
element.data('mouseX', event.clientX);
element.data('mouseY', event.clientY);
});
element.parents(':last').mouseup(function() {
element.data('mouseMove', false);
});
element.mouseout(move);
element.mousemove(move);
}
try using element.children().first() because rd_header div is the first child of your rd_main
div.
Any way why don't you use Jquery draggable instead of your own function ? http://jqueryui.com/demos/draggable/#handle

Categories

Resources