I currently have several elements in a row that have a mouseover event that fires some animation. My problem is that if someone mouses over several of the elements in quick succession the animation gets a little frantic.
I'm curious if there is a way to have a mouseover event that only fires if the mouse is over an element for a certain amount of time (say 250 milliseconds). Can this be done with jQuery?
I would suggest you use setTimeout for this:
(function ($) {
var t;
$('ul li').hover(function() {
var that = this;
window.clearTimeout(t);
t = window.setTimeout(function () {
$(that).animate({opacity: .5}, 'slow').animate({opacity: 1});
}, 250);
});
}(jQuery));
If there are multiple items activated in rapid succession the timeout will override the timeout-id thus preventing the first item that should not start from animating.
It does not require any arcane plugin (although hoverIntent may provide some nice additional features you may want to use) and window.setTimeout is supported everywhere.
UPDATE
I updated the code sample to work.. was writing this from memory yesterday and didn't get the setTimeout call quite right.. Also see this jsFiddle for reference.
The issue I see with this is that it will execute the hover animation even if you leave the . So you could also add a $('ul').mouseleave(function() { window.clearTimeout(t) }); to prevent that.
greetings Daniel
I suggest that you check out the jQuery HoverIntent plugin ( 1.4k minified ). Here's the link: http://cherne.net/brian/resources/jquery.hoverIntent.html. It's a great plugin, I've used it many times!
Here's a small sampling of code:
var config = {
over: makeTall, // function = onMouseOver callback (REQUIRED)
timeout: 500, // number = milliseconds delay before onMouseOut
out: makeShort // function = onMouseOut callback (REQUIRED)
};
$("#demo3 li").hoverIntent( config )
yes:
to accomplish this put a setTimeout in your onMouseover function and a clearTimeout on mouseout
You may need a little more logic, but that's the nuts and bolts of it
here's an example of stop() in action, hope that will help:
without stop():
http://jsfiddle.net/5djzM/
with stop() cleaning the queue of animations:
http://jsfiddle.net/KjybD/
Related
I have made a very simple hover animation for a thumbnail by using a SVG icon. See here. The JS code I used is like so:
var elemRemoveAnim = null;
$('.vedio-thumb').hover(
function(){
$(this).find('.youtube-icon > .youtube-red')[0].classList.add('y-animated' , 'fadeInUp');
$(this).find('.youtube-icon > .youtube-white')[0].classList.add('y-animated' , 'fadeInUp');
},
function(){
removeVedioAnim($(this));
});
function removeVedioAnim(elem) {
elemRemoveAnim = elem;
setTimeout(function(){
elemRemoveAnim.find('.youtube-icon > .youtube-red')[0].classList.remove('y-animated' , 'fadeInUp');
elemRemoveAnim.find('.youtube-icon > .youtube-white')[0].classList.remove('y-animated' , 'fadeInUp');
}, 1000);
}
As you can see, I am trying to remove the animation class, after a delay of 1000ms, that's because iif you hover over and immediately hover out (you'll have to do it really fast), you'll notice that the animation gets stuck, i.e. the white arrow will still only be in half transition. Technically this is happening because the animation class has been removed too soon.
If I add the code in the hover out function, this aggravates the situation even more. Is there a more versatile solution to this problem?
One more problem with the with this solution is that once you hover and then if you hover out and you do it 2-3 times really fast, for the 2-3 time you've hovered the animation will take play only once, simply the setTimeout function will wait 1 second to remove the classes. I wonder if there is a more elegant way to do this.
SEE DEMO
Use "animationend" event to capture the end of fadingInUp motion on the arrow, that runs longer (the white one).
$utube_white.one("animationend webkitAnimationEnd oAnimationEnd",function() {
$utube_red.get(0).classList.remove('y-animated' , 'fadeInUp');
$utube_white.get(0).classList.remove('y-animated' , 'fadeInUp');
isLocked = false;
});
In your example there's no need for a mouseleave function in HOVER event, because you don't do anything particular on it - just remove animation classes without any other motion. This could be done in "Animationend" event in the first "HandlerIn" function.
Instead of a mouseleave function put the empty $.noop to prevent jQuery think that your hover function contains only one argument.
.hover(handlerIn, $.noop) and not .hover( handlerInOut ). You can change it, it's up to you, but in the last case the function will fire on both MouseOn and MouseOut.
Use a flag "isLocked" as well to prevent firing HandlerIn on quick hovers.
I am trying to create a script that does the following:
Waits until a point on the page is reached by scrolling (.clients with an offset of 500px
Start fading in img's contained inside the .clients div once this event is triggered
Fade in with a slight delay between each item (so they fade in in sequence)
Due to other parts of my code the fade-in has to be with change of opacity:1 and cannot be .fadeIn()
I'm somewhere there but having a few issues. Here is my code:
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function(){
if ( $w.scrollTop() > targetOffset-500 ) {
$('.home .clients img').each(function(index){
console.log(index);
$(this).delay(500 * index).css('opacity','1');
});
}
});
First problem
The event does fire at the correct scroll-point in the page, but it continues to fire. I would like it to only fire once and then not register again. When 500 above .clients is reached, the event should fire, and never again.
Second problem
My .each() does not seem to work correctly. Everything fades in at once. My method for making a small .delay() between the fade-ins doesn't seem to be working. I tried multiplying the index by 500. So the first index is 0, so it fires immediately. The second index is 1 so it should fire after 500 milliseconds and so on. I'd like to work out why this method isn't working.
Any help appreciated. I'd appreciate trying to make the code above work rather than writing something entirely new, unless that's the only way. I'd appreciate explanation of what I was doing wrong so I can learn, instead of just pure-code answers.
JSFiddle
Sidney has attacked most of the problems except one. The scroll event fires multiple times, so it checks the conditional multiple times and then actually sets the animation multiple times. To keep this from happening, I typically like to add another boolean to check if the process has fired at all. I've simplified the code to make the changes more legible.
var working = false;
$(window).on('scroll', function(){
if($(window).scrollTop() > 1000 && !working){
working = true;
setTimeout(function(){
working = false;
}, 500);
};
});
As Tushar mentioned in the comments below your post, instead of using .delay() you could use a plain setTimeout().
On the jQuery docs for .delay() they mention that using setTimeout is actually better in some use-cases too - this is one of them.
The .delay() method is best for delaying between queued jQuery
effects. Because it is limited—it doesn't, for example, offer a way to
cancel the delay—.delay() is not a replacement for JavaScript's native
setTimeout function, which may be more appropriate for certain use
cases.
Using setTimeout your code would look like this:
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function() {
if ($w.scrollTop() > targetOffset - 500) {
$('.home .clients img').each(function(index) {
setTimeout(function() {
$(this).css('opacity','1');
}, (500 * index));
});
}
});
Also, you can unbind an event using .off()
so in your if ($w.scrollTop() > targetOffset - 500) { ... }
you could add a line that looks like this:
$(window).off('scroll');
Which would unbind the scroll handler from the window object.
You could also use .on() to reattach it again some time later. (with on() you can bind multiple events in one go, allowing you to write the same code for multiple handlers once.)
Please change your jquery code with following it will trigger event one time only and may be as per your reuirements :-
var targetOffset = $(".clients").offset().top;
var $w = $(window).scroll(function () {
if ($w.scrollTop() == 1300) {
console.log('here!');
$('.clients img').each(function (index) {
$(this).delay(5000 * index).css('opacity', '1');
});
}
});
Here i have take scroll hight to 1300 to show your opacity effect you can take it dynamically, if you want it 500 then please change the css as following also.
.scroll {
height:700px;
}
I am trying to create an animation for a button on click event. A simple function which simply consists on toggling classes and setting timeouts is used for the animation.
It works well for one button but when I have more than one button and I click two or more of them consecutively before the animation is finished, the animation stops and continues on the element which has been clicked later.
So the problem is to make the animation function to refer to the object which has triggered it, therefore creating multiple instances of it, for which I haven't been able to find a simple solution after hours of search).
Thanks in advance.
There's a simplified example (real example has more classes toggles):
$('.myButton').on('click', animateButton);
function animateButton(){
var $this = $(this);
$this.addClass('animate');
setTimeout(function(){
$this.removeClass('animate');
},2000)
}
EDIT: I've made a fiddle: https://jsfiddle.net/8ozu14am/
EDIT2: SOLVED
Using $.proxy() it is possible to maintain the context.
$('.myButton').on('click', animateButton);
function animateButton(){
$(this).addClass('animate');
setTimeout($.proxy(function(){
$(this).removeClass('animate');
},this),2000)
}
Jquery return an Event to your handler.
It have the property targetwhich is the DOM element that initiated the event.
$('.myButton').on('click', animateButton);
function animateButton(evt){
var $this = $(evt.target);
$this.addClass('animate');
setTimeout(function(){
$this.removeClass('animate');
},2000)
}
SOLVED
Using $.proxy() it is possible to maintain the context.
https://api.jquery.com/jQuery.proxy/
$('.myButton').on('click', animateButton);
function animateButton(){
$(this).addClass('animate');
setTimeout($.proxy(function(){
$(this).removeClass('animate');
},this),2000)
}
I'm using this code to stop simultaneous animations on 2 elements:
$('#container').find('*').stop(true, true);
The animation can be stopped by an end user hovering over a button, in which case the animation stops after completion (which is what I want). However, the button hover also initiates another function (removes and reloads the elements), and there's a conflict if that function runs before the animations are complete.
I was thinking that using 'after' or 'complete' with the above code might work, but I can't figure out what the syntax would be.
im not sure what you are trying to achieve, but in order to check whether or not there are running/pending animations on the object using jQuery, you can use .promise().done()
example, somehing of this sort:
var animations_running;
$('#container').promise().done(function() {
animations_running=false;
});
$('#container').on("mouseover",".SomethingInside",function(){
if(animations_running==false){
//...do animations...
animations_running=true;
}
});
you can also add a callback function to your jQuery animations as follows:
$('#container').on("mouseover",".SomethingInside",function(){
if(animations_running==false){
$(this).animate({
left:+=50
},500,function(){
//...this is the callback function...
});
animations_running=true;
}
});
[edit]
So I used one of the javascript tooltips suggested below. I got the tips to show when you stop and hide if you move. The only problem is it works when I do this:
document.onmousemove = (function() {
var onmousestop = function() {
Tip('Click to search here');
document.getElementById('MyDiv').onmousemove = function() {
UnTip();
};
}, thread;
return function() {
clearTimeout(thread);
thread = setTimeout(onmousestop, 1500);
};
})();
But I want the function to only apply to a specific div and if I change the first line to "document.getElementById('MyDiv').onmousemove = (function() {" I get a javascript error document.getElementById('MyDiv') is null What am I missing....??
[/edit]
I want to display a balloon style message when the users mouse stops on an element from more than say 1.5 seconds. And then if they move the mouse I would like to hide the balloon. I am trying to use some JavaScript code I found posted out in the wild. Here is the code I am using to detect when the mouse has stopped:
document.onmousemove = (function() {
var onmousestop = function() {
//code to show the ballon
};
}, thread;
return function() {
clearTimeout(thread);
thread = setTimeout(onmousestop, 1500);
};
})();
So I have two questions. One, does anyone have a recommended lightweight javascript balloon that will display at the cursor location. And two, the detect mouse stopped code works ok but I am stumped on how to detect that the mouse has started moving again and hide the balloon. Thanks...
A bit late to be answering this, but this will be helpful for those in need.
I needed this function to be able to detect when the mouse stopped moving for a certain time to hide an HTML/JS player controller when hovering over a video. This is the revised code for the tooltip:
document.getElementById('MyDiv').onmousemove = (function() {
var onmousestop = function() {
Tip('Click to search here');
}, thread;
return function() {
UnTip();
clearTimeout(thread);
thread = setTimeout(onmousestop, 1500);
};
})();
In my case, I used a bit of jQuery for selecting the elements for my player controller:
$('div.video')[0].onmousemove = (function() {
var onmousestop = function() {
$('div.controls').fadeOut('fast');
}, thread;
return function() {
$('div.controls').fadeIn('fast');
clearTimeout(thread);
thread = setTimeout(onmousestop, 1500);
};
})();
The jQuery plugin hoverIntent provides a similar behaviour. It determines if the user 'meant' to hover over a particular element by checking if they slow the mouse down moving into the elements and spend a certain amount of time hovering over the element.
It only fires the "out" event when the user leaves the element, which doesn't sound like exactly what you're looking for, but the code is pretty simple.
Also watch out for binding things to mousemove when you don't need to be collecting the events, mousemove fires a lot of events quickly and can have serious effects on your site performance. hoverIntent only binds mousemove when the cursor enters the active element, and unbinds it afterwards.
If you do try hoverIntent I have had some trouble with the minified version not firing "out" events, so I would recommend using the full, unminified source.
Here's a nifty jQuery plugin for a nice float over tool tip.
http://jqueryfordesigners.com/demo/coda-bubble.html
[edit]
I guess without seeing the companion HTML it's hard to say what's wrong. I'd double check that the element has the appropriate ID specified in the tag. Apart from that, unless this is an academic exercise, I would suggest using something like the jQuery plugin that I referenced above. There are certainly many other pre-built tools like that which will have already dealt with all of the minutiae you're currently addressing.
document.onmousemove = (function() {
if($('balloon').visible) {
//mouse is moving again
}....//your code follows
Using Prototype.js syntax you can determine that the mouse has moved once the balloon is visible.