How to start mouseover event while dragging
Solution 1
Here is an example using the X-Y coordinate solution.
The example can be improved, but is a good starting point.
Simply keeps track of the mouse location and checks if it appears to be inside any bounding boxes of the droppable objects. Hence, if the mouseup event fires on any one of them, dragged object is dropped.
You can also use the coordinates of the object you are dragging for detecting if its on a droppable box, but it requires a little more code for finding the bounding box coords and using the mouse is enough for me.
The code uses jQuery but no jQueryUI. I tested in Chrome, Firefox and Opera, but not IE :)
I'm also adding the code to here if jsfiddle is not accessible.
HTML
<p>Drag orange boxes to grey ones</p>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="draggable"></div>
<div class="draggable"></div>
<div class="draggable"></div>
CSS
.droppable {
width:50px;
height:50px;
float: left;
background-color: #DDD;
margin: 5px;
}
.draggable {
width:40px;
height:40px;
float: right;
background-color: #FC0;
margin: 5px;
cursor: pointer;
}
.dropped {
background-color: #FC0;
}
.somethingover {
background-color: #FCD;
}
JS
var dragged, mousex, mousey, coordinates = [];
var continueDragging = function(e) {
// Change the location of the draggable object
dragged.css({
"left": e.pageX - (dragged.width() / 2),
"top": e.pageY - (dragged.height() / 2)
});
// Check if we hit any boxes
for (var i in coordinates) {
if (mousex >= coordinates[i].left && mousex <= coordinates[i].right) {
if (mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
// Yes, the mouse is on a droppable area
// Lets change the background color
coordinates[i].dom.addClass("somethingover");
}
} else {
// Nope, we did not hit any objects yet
coordinates[i].dom.removeClass("somethingover");
}
}
// Keep the last positions of the mouse coord.s
mousex = e.pageX;
mousey = e.pageY;
}
var endDragging = function(e) {
// Remove document event listeners
$(document).unbind("mousemove", continueDragging);
$(document).unbind("mouseup", endDragging);
// Check if we hit any boxes
for (var i in coordinates) {
if (mousex >= coordinates[i].left && mousex <= coordinates[i].right) {
if (mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
// Yes, the mouse is on a droppable area
droptarget = coordinates[i].dom;
droptarget.removeClass("somethingover").addClass("dropped");
dragged.hide("fast", function() {
$(this).remove();
});
}
}
}
// Reset variables
mousex = 0;
mousey = 0;
dragged = null;
coordinates = [];
}
var startDragging = function(e) {
// Find coordinates of the droppable bounding boxes
$(".droppable").each(function() {
var lefttop = $(this).offset();
// and save them in a container for later access
coordinates.push({
dom: $(this),
left: lefttop.left,
top: lefttop.top,
right: lefttop.left + $(this).width(),
bottom: lefttop.top + $(this).height()
});
});
// When the mouse down event is received
if (e.type == "mousedown") {
dragged = $(this);
// Change the position of the draggable
dragged.css({
"left": e.pageX - (dragged.width() / 2),
"top": e.pageY - (dragged.height() / 2),
"position": "absolute"
});
// Bind the events for dragging and stopping
$(document).bind("mousemove", continueDragging);
$(document).bind("mouseup", endDragging);
}
}
// Start the dragging
$(".draggable").bind("mousedown", startDragging);
Solution 2
In all presented answers, I don't see the most simple and obvious one (maybe I'm missing something in OP question). But, if someone stumble upon this later, and needs fast and simple solution in pure JS..
You do it by changing element className ondragover, and changing back to original class ondragleave
my_element.ondragover = function(ev) {
ev.preventDefault();
this.className = 'myElem_dragover';
}
my_element.ondragleave = function(ev) {
ev.preventDefault();
this.className = 'myElem_orig';
}
CSS
.myElem_orig { //this is your initial class for element
top: 30px;
left: 20px;
.....
background-color: blue;
}
.myElem_orig:hover { //this is hover state, just changing bg color
background-color: red;
}
.myElem_dragover { //new class, needs all attributes from original class
top: 30px;
left: 20px;
........
background-color: red; //behaves the same like hover does
}
edit:
forgot to mention, you need to bring back original class ondrop too, otherwise div will stay in dragover class
Solution 3
There are two basic ways you can do this:
- track
mousemove
and react to x/y coordinates - have a transparent target that has a higher
z-index
than the drag container
First option doesn't really use the mouseover event at all, but will give you the same net result.
Be aware that some browsers (ie) won't trigger mouseover
on transparent elements, so you have to fake it by setting a background image that is transparent or setting a random image as background and positioning it outside the element like this:
element {
background: url(/path/to/img) no-repeat -10000px 0;
}
Solution 4
jQuery-ui has a droppable plugin for this.
The plugin, when used with a draggable element will trigger dropover
events, which can be bound to any action you require.
See Mottie's answer to this question (demo included)
V.Rashkov
Updated on July 05, 2022Comments
-
V.Rashkov almost 2 years
When I drag an element over another
div
on which I have a mouseover event, the event doesn't trigger. However, it works if I hover over it without dragging.Is there a way to detect hover events on an element if I drag another one over it?
-
Purag over 12 yearsThat might interfere with the element being dragged, depending on how he has it set up.
-
OrganicPanda about 12 yearsI was a bit skeptical at first but this technique has worked very well for me - thanks very much!
-
Abc about 9 yearsI think this question pre-dates widespread use of the built-in HTML draggable attribute, which is definitely the easiest way to go unless you're doing custom behaviors.
-
Wellyngton about 8 yearsThat's what I was looking for, not any custom behavior. Thanks.
-
Lucas over 7 yearsI agree with greg. This answer is excellent now-a-days and will get popular very soon I feel.
-
Kelderic almost 7 yearsOne downside to the dragover/dragout is that it can't tell, as far as I know, which side of an element you are hovering over. Say it's a list of items that you are drag'n'drop sorting, if you hover over the top half of an item, you'd want to dragged content to be placed ABOVE that item. But you can only see that you are hovering on it, now the location within.
-
Wolf War almost 7 years@AndyMercer in
dragOver
event you can test on which half the mouse is, up or down, and according to that make decision. With theobject.getBoundingClientRect()
you get for instance, bottom border and subtract mouse Y coordinate from it. You get value that is bigger or lover than object height/2 -
Kelderic almost 7 yearsKinda funny, I just posted a question asking about that, and your comment here may have just answered it. I'll investigate the
dragover
event some more, thanks. -
Wolf War almost 7 years@AndyMercer
getBoundingClientRect()
is not part of the drag&drop API if you were thinking that. It's just that indragOver
event you can test many things, on of them is bounding rectangle, and calculate position with pure math. -
Kelderic almost 7 yearsYep, that is the logic I used. I gave you credit in the answer to the question I posted. stackoverflow.com/questions/44415228/…, thanks mate!