I have a div container which sticks to the bottom of the page. When the mouse moves out of the div, I want the div to sink after 3 seconds. When the mouse moves over the div, I want the div to rise to its original position. The problem is when the mouse moves over and out of the div very quickly, the div keeps moving up towards the top of the page.
var timer = null;
var moving_distance = $("#scroller").height()-($(window).height()-$("#slideshow").height());
$("#scroller").mouseenter(function(event){
if(timer)
{
clearTimeout(timer);
$("#scroller").animate({top:'-='+moving_distance},1000);
}
}).mouseleave(function(event){
if(!timer){
timer = setTimeout(function(){
$("#scroller").animate({top:'+='+moving_distance},1000);
},3000);
}
});
I have had success stacking a null animation in front of the animation I want rather than using setTimeout.
For instance,
var moving_distance = $("#scroller").height()-($(window).height()-$("#slideshow").height());
var firstEnter = true;
$("#scroller").mouseenter(function(event){
if (firstEnter)
firstEnter = false;
else {
$("#scroller").stop();
$("#scroller").animate({top:'+=0', 3000);
$('#scroller').animate({top:'-='+$('#scroller').top()), 1000);
}
}).mouseleave(function(event){
$('#scroller').stop();
$("#scroller").animate({top:'+=0', 3000);
$('#scroller').animate({top:'+='+moving_distance), 1000);
});
I am guessing from your description that you want the div to stand still until the mouse is moved into the div. Then when the mouse leaves for the first time it should sink. After that, when the mouse comes back again, it should return to its original position. I think this will be close to doing that.
HTH
Related
So I made an animation where a div called "slider" appears from the left side of the screen, expands to the right and then disappears on the right side of the screen. What I have done is start with width: 0; then transform to the full width, change position to right and have the width go back to 0 and change display to none. The animation works fine, but probably with excessive use of the setTimeout. Is there a better way to write this piece of JavaScript and have one animation start when the previous has finished without the use of setTimout?
window.addEventListener("DOMContentLoaded", function(){
slider.style.width = "60%";
slider.style.position = "absolute";
setTimeout(function(){
slider.style.right = "25%";
slider.style.width = "0px";}, 750);
setTimeout(function(){
slider.style.display = "none";}, 1500);
});
This is pretty much what I'm working on: https://jsfiddle.net/atg5m6ym/2625/
I'm animating a div with jQuery to move left, then logging to the console when I hover over the div and when I move my mouse away from it:
$("div").animate({left: '250px'}, 6000);
$('div').hover(function() {
console.log("Mouse hovered on div!");
}).mouseleave(function() {
console.log("Mouse left div!");
})
Naturally, the program will run console.log("Mouse hovered on div!"); once I put my mouse on the element.
However, if I leave my mouse idle and the animated element moves onto it, nothing in $('div').hover(function(){}) will run. I have to move my mouse onto the element for the code to run, not let the element come to the mouse.
The same thing also happens if I hover onto the element, and then leave my mouse idle. Nothing in $('div').mouseleave(function(){}) will run after the element leaves, until I move my mouse from its position.
Is there any way to work around this? I am working with animated divs and I need code to run even if the mouse is idle and the divs pass through it.
Manually take the mouse's last known position and compare it to the position of the circle. This is kind of extensive but it should get you the right results.
Here is a JSFiddle:
https://jsfiddle.net/3vpaoj59/
$("div").animate({left: '250px'}, 6000);
$(document).ready(function() {
// record down the position of the cursor
var cursorX;
var cursorY;
document.onmousemove = function(e){
cursorX = e.pageX;
cursorY = e.pageY;
}
// boolean to know if hovered or not, and to know whether to report in console.log
var hover = false;
// function to call by setinterval to check if mouse is within radius
function checkMouse(){
// find the centerpoint of the circle by taking its position then adding half its width/height to each coordinate
var left = $("#foo").offset().left+$("#foo").width()/2;
var top = $("#foo").offset().top+$("#foo").height()/2;
// use pythagorean theorem to find distance between two points
var xdist = Math.pow(Math.abs(cursorX - left),2);
var ydist = Math.pow(Math.abs(cursorY - top),2);
var hypotenuse = Math.round(Math.sqrt(xdist+ydist));
// check if the distance is less than radius
if(hypotenuse <= $("#foo").width()/2 && !hover){
// if true and not already reported true, report then fix
console.log("mouse hovered on div!");
hover = true;
} else if (hypotenuse > $("#foo").width()/2 && hover){
// if false and not already reported false, report then fix
console.log("mouse left div!");
hover = false;
}
}
// repeatedly call this
setInterval(checkMouse, 100);
});
I changed the div's ID to "foo" for convenience. Make sure to do this as well so that the code works for your project, or modify the JS to not use "foo".
Explanation:
The reason why your problem was occurring was because your mouse's coords are only updated every time you move your cursor, and that's when hover states are checked by .hover. As such, we need to emulate the event that determines hover and call it repeatedly even when the cursor hasn't moved to make sure the hover state is updated.
I am trying to create a very simple slideshow.
I would like the slideshow to pause on hover and resume when the user moves their mouse off the slideshow (#slide_container). While the slideshow works fine, and so does the hover (to an extent), if I flick my mouse on and off the slideshow repeatedly, it completely messes the slide and starts animating sporadically (check the fiddle below to see what I mean).
I tried adding promise, so that before animating it completes any queued animation, but despite this, the behaviour remains.
How should I go about fixing this?
Here is the fiddle: http://jsfiddle.net/hR6wZ/
my js code:
$(document).ready(function() {
//get variables
var slide_width = $('.slider_container').width();
var number_of_slides = $('.slider_container .slide').length;
var slider_width = slide_width*number_of_slides;
//set element dimensions
$('.slide').width(slide_width);
$('.slider').width(slider_width);
var i = 0;
var hover_switch = 0;
$('.slider_container').hover(function() {
//Hover mode on
hover_switch = 1;
}, function() {
//Hover mode off
hover_switch = 0;
sliderLoop()
});
function animateSlider() {
$(":animated").promise().done(function() {
$('.slider').finish().animate({ marginLeft: -(slide_width * i) });
});
}
function sliderLoop() {
setTimeout(function(){
//Only runs if hover mode is off;
if(i < number_of_slides-1 && !hover_switch) {
i++;
animateSlider();
sliderLoop();
}
else if (!hover_switch)
{
i = 0;
animateSlider();
sliderLoop()
}
},4000);
}
sliderLoop();
});
EDIT: also I did try using stop instead of finish() but this didn't fix the issue..
Becuase your calling the slider loop each time you hover out everytime even if you hover back and forth like ten times it tells it and queus it up to animate the x amount of times you did that.
What you can try is Only have the slider loop check right then and their when it's about to animate if it is being hovered or not and don't call the slider loop from the every time that it hovers out.
Another way is right before it begins animating set a variable for the duration of the animation to tell it not to call the animateSlider function if Currently_animating
so add && !currently_animating to each if statement within the sliderloop function.
That method however will help but probably the first way would be better as then it will never animate more then every x miliseconds or however long you set it to be.
But in General you probably should not call the sliderloop function if hover_switch = 0 becuase then it will just queue up the slider loop each time you hover out.
On my page, when the user gets to say 1000 pixels scrolled down the page, my navigation fades out, when i scroll back up the navigation fades in. Im using the following which works perfectly...
// Fade Navigation
if(!$('nav ul').is(':visible')) {
$('nav ul').stop().fadeIn(500);
} else {
$('nav ul').stop().fadeOut(500);
}
My only problem is that if you scroll really quickly, the animation doesnt know if its visible or not, is there a way to stop this?
If you pass in true as a second parameter to .stop(), it'll stop the animation and jump the element to the state it should be in if the animation actually finished.
i.e. if you call $('nav ul').stop(true, true).fadeIn(500) while an element is fading out, it will stop the fade out, and make it jump to it's logical end (which is completely faded out) before starting the .fadeIn() animation.
Using that, you should be able to get away with the following instead of your code block above:
$('nav ul').stop(true, true).fadeToggle(500);
It'll look a little jerky though, but you can work around it with a bit more complicated logic.
I've been playing around with this. See comments in code.
<nav class="main">
<ul>
<li>One</li>
<li>Two</li>
</ul>
</nav>
<script type="text/javascript">
// Do this outside of the onscroll handler. onscroll is fired a lot,
// so performance will slow if you're having to create jq instances
// or navigate the dom several times
var $wnd = $(window);
var $nav = $('nav.main');
// Added this to block the main handler from executing
// while we are fading in or out...in attempt
// to smooth the animation
var blockHandler = false;
window.onscroll = function () {
if (!blockHandler) {
blockHandler = true;
// I've used 50 here, but calc the offset of your nav
// and add the height to it. Or, maybe just half the
// height to it so you can see the animation.
if ($wnd.scrollTop() < 50) {
$nav.fadeIn(500, function () {
blockHandler = false;
});
} else {
$nav.fadeOut(500, function () {
blockHandler = false;
});
}
}
};
</script>
I'm using a nicescroll a plugin that I use to create scrollbars on divs.
$('#postscroller').niceScroll();
var nice = $("#postscroller").getNiceScroll()[0];
$('#postscroller').bind("scroll",function()
{
if(nice.scrollvaluemax==nice.scroll.y)
{
alert('bottom');
}
alert(nice.scroll.y);
});
First I activate the div to be scrolled.
Then I save the nicescroll instance to the nice variable.
When I test the scroll event to see wether the scroll.y is being fired when I scroll to the bottom I get some numbers but not 134 which is nice.scrollvaluemax in the div I'm testing.
I do get however 134 when I'm at the bottom and I scroll upwards.
Any idea on how can I get 134 when scrolling to the bottom?
Thanks
you get other numbers because you are not at the bottom when you scroll down...
probably related to your current position when the scroll is fired.
post more code.
I fixed it by calling this at the scroll event
var postscrollertimer = (function() {
var timer;
return function() {
clearTimeout(timer);
timer = setTimeout(function()
{
if(postscroller.scrollvaluemax==postscroller.scroll.y)
{
//do stuff
}
}, 1000);
};
})();