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;
}
};
Related
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.
Trying to identify the relative value of the clicked x and y coordinate and the offsets of the parent container to find the true value where the mouse was clicked on the web page.
The problem is: I am displaying NaN as the x and y on the screen? Not sure why?
// get the position of click
function getPosition(el) {
var xPosition = 0;
var yPosition = 0;
while (el) {
if (el.nodeName == "BODY") {
// deal with browser quirks with body/window/document and page scroll
var xScrollPos = el.scrollLeft || document.documentElement.scrollLeft;
var yScrollPos = el.scrollTop || document.documentElement.scrollTop;
xPosition += (el.offsetLeft - xScrollPos + el.clientLeft);
yPosition += (el.offsetTop - yScrollPos + el.clientTop);
} else {
xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft);
yPosition += (el.offsetTop - el.scrollTop + el.clientTop)
}
el = el.offsetParent;
}
return {
x: xPosition,
y: yPosition,
a: "hahah",
};
}
function handleClick(event) {
// Return the current element clicked on
var el = event.currentTarget;
// Return the offset values of the element clicked on
var relOffsetValues = getPosition(el);
// Get the clicked values that is relative to the element
var valuesRelToClickedElementX = event.ClientX;
var valuesRelToClickedElementY = event.ClientY;
// Find the true value of x and y by adding the offset and the to clicked value of x and y
var realValueX = relOffsetValues.x + valuesRelToClickedElementX;
var realValueY = relOffsetValues.y + valuesRelToClickedElementY;
// display the x and y of the mouse click
alert("x:" + realValueX + ", y:" + realValueY);
}
// Set up event handlers according to standards
window.addEventListener("load", function(){
document.addEventListener("click", handleClick);
});
2 things need to be corrected to work:
Make event.ClientX to event.clientX and event.ClientY to event.clientY. Notice the small letter in clientX and clientY.
instead of document.addEventListener("click", handleClick); use document.body. addEventListener("click", handleClick);
Vinod
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;
};
Is there a way in javascript to check whether the mouse position currently lies within an element's bounds?
Is there a function you can suggest or a method thats quick?
if ( document.mouse.x > ele.offsetLeft && document.mouse.x < ele.offsetRight ...check y bounds)
{
return true;
}
else return false;
You could store the boundary coordinates and the mouse coordinates. This would let you check it any time you want.
var coords = [0,0];
$(document).mousemove(function(e){
var C = coords; // one global lookup
C[0] = e.pageX;
C[1] = e.pageY;
});
var box_area = {x1:0, y1:0, x2:0, y2:0};
var box = $('#box');
function store_boundary() {
var B = box, O = B.offset();
box_area = {
x1: O.left,
y1: O.top,
x2: O.left + B.width(),
y2: O.top + B.height()
};
}
store_boundary();
function is_mouse_in_area() {
var C = coords, B = box_area;
if (C[0] >= B.x1 && C[0] <= B.x2) {
if (C[1] >= B.y1 && C[1] <= B.y2) {
return true;
}
}
return false;
};
I would like to have given you an answer without jQuery, but I think .offset() (left/top coordinates relative to the document) is really well done and very well tested. You could write your own, however, that totals up offsetLeft and offsetTop up to document. For that matter, you could also replace $.mousemove() with:
document.addEventListener('mousemove',function(e){ ... },false);
One last thing: if you reflow the page, you need to call store_boundary() again.
var t = $("#element");
var mouseX = event.clientX + document.body.scrollLeft;
var mouseY = event.clientY + document.body.scrollTop;
if (mouseX >= t.offset().left && mouseX <= t.offset().left + t.width()
&& mouseY >= t.offset().top && mouseY <= t.offset().top + t.height()) {
return true;
}
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