jQuery hover not triggered when element is programatically moved under the mouse - javascript

I have an image with a hover effect (higher opacity when mouse is over it). It works as desired when the mouse moves in and out.
However, the image itself is moving (I'm periodically changing the css attribute top). When the mouse does not move and the image moves under the mouse cursor, no related events are triggered. That means, the hover functions are not called. I also tried using the mouseenter and mouseleave events instead, but they don't work either.
What would be a good approach to get the desired behavior (hover effect whenever the mouse is over the image, regardless of why it got there)?

You won't be able to trigger mouse events if the mouse isn't moving, though you will be able to check where the mouse is when the image is moving. What you need to do is track the mouse position in a global variable, and check to see if that position is inside your image when it moves.
jQuery has a nice article about how to do it using their library: http://docs.jquery.com/Tutorials:Mouse_Position
To find the position of your image you can use the jQuery position function: http://api.jquery.com/position/
With that position you can create a bounds using the height/width of your image. On your image move check to see if that global mouse position is inside your image bounds and you should be good to go.
This is how I would write the code(completely untested btw):
var mousex = 0;
var mousey = 0;
jQuery(document).ready(function(){
$(document).mousemove(function(e){
mousex = e.pageX;
mousey = e.pageY;
});
})
img.move(function(){
...move code...
var p = $(this).position();
if(mousex >= p.left && mousex <= p.left + $(this).width
&& mousey <= p.top && mousey >= p.top + $(this).height)
{
...opacity code...
}
});

You could manually test to see if the mouse is in the image when you move the image then fire the desired event.
Mouse position using jQuery outside of events will show you how to keep track of the mouse position. Then just find the offset of the image and see if it's inside the image.

In addition to wajiw's and ryan's answers, you should trigger the mouseenter and mouseleave events as you detect that the mouse is over/not over the image, so that whatever code you bound to .hover() is still executed:
$(".my-image").trigger("mouseenter");
$(".my-image").trigger("mouseleave");

#wajiw has posted a great solution, but unfortunately it's plagued with typos meaning it won't work out of the box until you fix it.
Here is a class you can use which is tested and works which will allow you to test if an object is under the mouse.
Class definition
// keeps track of recent mouse position and provides functionality to check if mouse is over an object
// useful for when nodes appear underneath the mouse without mouse movement and we need to trigger hover
// see http://stackoverflow.com/questions/4403518
function MouseTracker($) {
var mouseX, mouseY;
$(document).mousemove(function(e) {
mouseX = e.pageX;
mouseY = e.pageY;
});
return {
isOver: function(node) {
var p = $(node).offset();
if (mouseX >= p.left && mouseX <= p.left + $(node).width()
&& mouseY >= p.top && mouseY <= p.top + $(node).height())
{
return true;
}
return false;
}
}
}
Usage example
var mouseTracker = new MouseTracker(jQuery);
if (mouseTracker.isOver($('#my-object-in-question'))) {
$('#my-object-in-question').trigger("mouseenter");
}
Hope that helps.
I could make this into a jQuery plugin very easily if anyone wants it, just drop me a line and I'll go ahead.
Matt

Related

Can't start new jquery functions during drag event

I noticed that the CSS hover function doesn't trigger when dragging an element from outside the page. I wanted to have a "drop it here" div that lights up when the mouse is over it, but hover didn't work and neither does this:
// Cosmetic thing
$('#dropzone').on({
dragover: function(e) {
$('#dropzone').addClass('on');
},
dragleave: function(e) {
$('#dropzone').removeClass('on');
}
});
I can see in the inspector the class IS being added, but it doesn't light up.
I also tried closing my popup drop area, with a mousemove event while dragging, but the event doesn't seem to work until after I let go of the mouse:
$(document).on('mousemove',function(e){
console.log('x:'+e.pageX+' y:'+e.pageY);
if (e.pageX <= 0 || e.pageX > $(document).width() || e.pageY <= 0 || e.pageY > $(document).height())
{
dropperOff();
$(document).unbind('mousemove');
}
});
Lastly I tried to just have a constant mousemove tracking event that populates a mouseX and mouseY variable at all times. When I move the mouse, it works fine, but the moment a dragenter event fires, the mousemove event stops working too.
This behavior is making it very hard to make the page work. Is there a way around this or do I have to give up on making my dropzone light up and detect when the drag event leaves the page?

jQuery - how to animate draggable div towards moving cursor during drag event

I am using jquery UI draggable and want to have a draggable div animate during a drag event. Imagine that when stationary, the square div in the example is attached to a magnet. Wen you click on it and start dragging, it will not drag until a certain distance threshold is reached (distance = distance between center of div and current mouse position). After that threshold is reached, the div will animate toward the mouse and should then proceed to a normal drag event.
My problem is that when the mouse is dragged past the distance threshold at a fast enough speed, the div will start flashing because it is switching between showing the animated div and the one that is being dragged. Another problem that occurs is that if you drag the mouse fast enough and then stop, the div animates to the last recorded mouse position, but by the time the calculation is made, the mouse might already be at a different position, so the mouse is at one spot and the div is at another. Any ideas on how to make the div animate towards the mouse and then continue the drag event in one smooth transition? (also, i want the animation do be long enough so that you can see the div moving. if duration is set to 1, it works fine but I want it to be more visually appealing and smooth) Here is a demo: http://jsfiddle.net/b84wn2nf/
Here is some of the code found in the demo:
$(".dragSquare").draggable({
drag: function (event, ui) {
if($(this).hasClass("stuck")){
var mx = event.pageX;
var my = event.pageY;
ui.position.left = $(this).position().left;
ui.position.top = $(this).position().top;
var d = Math.floor(Math.sqrt(Math.pow(mx - ($(this).offset().left + ($(this).width() / 2)), 2) + Math.pow(my - ($(this).offset().top + ($(this).height() / 2)), 2)));
console.log(d)
if (d > 200) {
var animateToX = event.pageX - $(this).width() / 2;
var animateToY = event.pageY - $(this).height() / 2;
$(this).stop(true, true).animate({
left: animateToX + 'px',
top: animateToY + 'px'
}, {
/*easing: 'easeOutBounce,'*/
duration: 500,
start: function () {},
complete: function () {
$(this).removeClass("stuck");
}
});
}
}
} });
Okay, So I know I posted this a long time ago, and since then, I started to use the Snap.js SVG library instead of jQuery, which makes it much easier to cancel a drag, but before the switch, I solved the problem the only way I could: by modifying the source code.
In jquery-ui.js, locate the jQuery UI Draggable section, and then scroll down to _mouseDrag method.
What you need to do in your own code is set a global variable to tell jQuery if you want the drag behavior to be overridden. I used 'cancelDrag' as the variable name. So when its set to false, dragging behaves normally.
In _mouseDrag, you will see the following code:
this.helper[0].style.left = this.position.left + "px";
this.helper[0].style.top = this.position.top + "px";
What you need to do is wrap it in a conditional statement that depends on your boolean variable, so it looks like this:
if(!cancelDrag){
this.helper[0].style.left = this.position.left + "px";
this.helper[0].style.top = this.position.top + "px";
}
Basically, if cancelDrag is set to true, jQuery drag handler will not change the position of your element. Its not ideal, and should probably not be used, but it works. Make sure that if you modify this file, you are not using the minified source.

CSS background position relative to cursor

I'm wondering how to do an effect like this:
http://www.gazprom.com/
(please note, the moving blue background, in top blue menu), and its relativity to cursor position)
Is there any script that follows cursor and changes background position style?
This effect can be achieved using small piece of JavaScript:
JavaScript
document.addEventListener('mousemove', function (event) {
if (window.event) { // IE fix
event = window.event;
}
// Grab the mouse's X-position.
var mousex = event.clientX;
var header = document.getElementById('header');
header.style.backgroundPosition = mousex/3 + 'px 0';
}, false);
Working Demo
How it works :
It binds a function on the mousemove event on document.
It grabs the current mouse position using event.clientX.
It changes the background-position of element #header with 1/3rd of the speed (mousex/3). Reference

How to track mouse position from on page load as well as on mouse move?

I am tracking mouse movements using the following JavaScript:
var mouseX = 0;
var mouseY = 0;
document.onmousemove = function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
My problem is that if the mouse hasn't been moved since the page had been loaded, the mouseX and mouseY values both equal 0. How can I get the mouse values when the page is loaded as well as when the mouse is moved?
The browser doesn't know where the mouse is until it moves.
It's more complicated than just "get me the cursor position". What if there is no mouse (tablet) or what if the mouse is not over the browser window?
For the same reason, you can't get hover events on an item if the cursor is already hovering when the page loads. It takes a mouse movement for those events to fire.
Go to some site, hover over a link that has a hover effect (like underline), refresh the page (without moving your cursor) and you'll see that even though your cursor is hovering over the link, it doesn't get the hover treatment until you move the cursor.
Unfortunately this is a browser-level issue, not a javascript issue.
You can define mouseover event for the document in order to catch the first mouse interaction on page load.

How to properly scroll an overflowing div based on mouse position within its container

I am working on a small jQuery plugin that autoscrolls through a set of overflowing elements within a container div based on the mouse position within that container div.
See the Demo Here
The idea is for this plugin to be an improvement of something I wrote a while ago. See the autoscrolling navigation in the lower left here The old problem with this was that it jumps around when you mouseenter from anywhere but the bottom(javascript perspective) of the container div.
Now everything is working fine with my plugin but when you mouseenter from the top it screws up from time to time(move your mouse in and out fast and it will happen for sure), I think this is because I am getting different values from my mouseenter event and my mousemove event which are both used to calculate how to scroll the inner elements. Here is the function, the rest of the source is pretty small and decently commented.
projList.mousemove(function(e){
//keep it from freaking out when we mouseenter from Top of div
if(enterMouseY > divHeight){
enterMouseY = divHeight;
}
mouseY = e.pageY-projList.offset().top;
//ok that didnt work... try to keep it from freaking out when we mouseenter from Top of div
if (mouseY > divHeight){
mouseY = divHeight;
}
//distnace from top of container div to where our mouse Entered
var distToTop = divHeight - enterMouseY;
//here is the calculation, I parameterize the mouseY pos as a value between 0-1
//0 being where we entered and 1 being the top or bottom of the div
//then multiply that by how much we have to scroll to get to the end of the list
//are we moving up or down
if(mouseY>enterMouseY){
//if up calculate based on Top
var dist =totalScrollDistance * ((mouseY-enterMouseY-projList.offset().top)/(distToTop));
}else if(mouseY<enterMouseY){
//if up calculate based on Bottom
var dist =totalScrollDistance * ((mouseY-enterMouseY-projList.offset().top)/(enterMouseY));
}else if(mouseY = enterMouseY){
var dist = 0;
}
//set the position of the list offsetting wherever we left it
pos = dist+lastPos;
//scroll to that position
projList.scrollTop(pos);
//are we trying to scroll past the scrollable amount
if(pos<0){
pos = 0;
}
if(pos>totalScrollDistance){
pos = totalScrollDistance;
}
$('#div1').text("mouseY: "+ mouseY +" enterMouseY: "+ enterMouseY +" distance:"+ dist.toFixed(1) + " pos:"+ pos.toFixed(1));
});
I solved this problem, there was an error in my calculations, but works how I described above.
You can see it in action here
http://web.archive.org/web/20130529212243/http://www.robincwillis.com/AutoScroll/

Categories