Javascript page scrolls automatically up and down - javascript

I'm struggling with a challenge that is just a bit out of my skill range. I'm trying to make a page scroll (very slowly) up and down on an infinite loop. I got the code to loop once, but my challenge is to make it loop over and over again. I would love advice.
do {
$(document).ready(function(){
$('body,html').animate({scrollTop: 2650}, 57820);
});
$(document).ready(function(){
$('body,html').animate({scrollTop: 0}, 35000);
});
}
while (true === true);

Javascript code is mainly asynchronous. What this means for you is that the browser is running the "go to top" and "go to bottom" code rapidly. And thus crashes your browser. What you want, is to wait till the scroll to bottom is completed, then scroll to top. Here is an example that does what you want.
// Getting a reference to html. The way you did it in the loop
// is slow because it has to get access to it every time.
const main = $('html');
// The scrollTop function
// scrolls to the top
function scrollTop() {
console.log('scrolling to top')
main.animate({scrollTop: 0},1000,"linear",scrollBottom /* this is a callback it means when we are done scrolling to the top, scroll to the bottom */)
}
function scrollBottom() {
console.log('scrolling to bottom')
main.animate({scrollTop: document.body.offsetHeight},1000,"linear",scrollTop /* this is a callback it means when we are done scrolling to the bottom, scroll to the top */)
}
// this kicks it off
// again only running $(document).ready once to increase performance.
// Once scrollTop completes, it calls scrollBottom, which in turn calls scrollTop and so on
$(document).ready(scrollTop);

Javascript will not wait until one function is completed so You can't create such loop. But You can utilize jquery.animate complete functionality:
$(document).ready(scrollDown()); //run function first time
function scrollUp() {
$('body,html').animate({
scrollTop: 0
}, 35000, "linear",
scrollDown//we are on the top, let's go down
);
return false;
}
function scrollDown() {
$('body,html').animate({
scrollTop: $(document).height()
}, 57820, "linear",
scrollUp//scrolling down is completed, let's go up
);
}
Here is working example of this code: https://jsfiddle.net/y7fguk52/

Related

how to attach scroll event to window after scroll animation

I'm trying to display a div after scroll animation has finished and hide it when I scroll up/down the page. This is my attempt:
$('#cta').on('click', function(e) {
e.preventDefault();
$('#layer, #servicesContent').addClass('active');
var position = parseInt($('#services').offset().top);
$('html, body').animate({
scrollTop: position - 100
}, 'slow', function() {
$(window).bind('scroll', function() {
$('#layer, #servicesContent').removeClass('active');
});
});
});
it doesn't work. the active class is removed after animation has finished and not with scroll movement.
Any idea?
Thanks in advance
Not exactly sure why, but apparently it takes the window somewhere around 20 milliseconds to exit the scroll state, at least on Chrome, on Windows. Or it might be a jQuery trick to fire the animation function 20ms sooner, so it feels more natural. (Human eye and mind make connections that take tiny amounts of time and maybe they took it into account).
Anyway, in order to make sure you bind after the scroll has ended, give it a full 100ms to finish and bind afterwards:
$('#cta').on('click', function(e) {
e.preventDefault();
$('#layer, #servicesContent').addClass('active');
var position = 120;
$('html, body').animate({
scrollTop: position - 100
}, 'slow', function() {
setTimeout(function(){
$(window).bind('scroll', function() {
$('#layer, #servicesContent').removeClass('active');
});
},100)
});
});
working fiddle.
Please note I had hard-coded a value to position, as #services is not defined in my example.
Also please note that hiding events on scroll is a really bad idea in terms of usability. Users might want to scroll so they view the div better or read it in full, but they will end up hiding it, which would be annoying. I would at least check the scroll event for a minimum velocity or distance in order to hide an element from the screen.

Mousewheel and transition incompatibility

SCENARIO
I have developed a function with jQuery which listens to the user's mouse input (based on the mousewheel plugin).
I analyze the user's input with a function, and alter the default behavior of the mouse, so that it scrolls a given px value with an animation.
PROBLEM
There are div containers in the webpage that transform its size when hovered.
This causes my original mousewheel animation to delay its action for a little time (more or less, half a second). If a div is hovered, and quickly afterwards the mousewheel is rolled, the effect won't run 100% smoothly (it will cause a little lag while the scroll animation is executing, and right afterwards, it will show the animation, which was already running).
If I delete the transition in the containers, the problem is solved. However, I would like to keep the original CSS intact, and run my original animation smoothly.
How can I accomplish this?
JSFIDDLE
http://jsfiddle.net/kouk/z7p0vxpg/
JS CODE
$(function () {
function wheel($div, deltaY) {
if (deltaY == -1) {
var dest = ($(document).scrollTop()+500);
$('html,body').animate({scrollTop: dest}, 1000);
return false;
} else if (deltaY == 1) {
var dest = ($(document).scrollTop()-500);
$('html,body').animate({scrollTop: dest}, 1000);
return false;
}
}
$('html').bind('mousewheel', function (event, delta, deltaX, deltaY) {
if ($('html,body').is(":animated")){
return false;
}
if ( (delta > -2) && (delta < 2) ) {
wheel($(this), deltaY);
event.preventDefault();
console.log(delta);
}
});
});
This is a common problem with the animate() function. The previous animations are in the queue and lagging behind. You should empty the animation queue before starting the next animation to avoid the "lag" feeling.
There are two functions which let you do that : finish() and stop() . I recommend using finish as it will stop the running animation )and remove all queued animations. This was you can immediately start your latest animation.
A user doesn't necessarily want to wait for his previous animation which he has already started a new action.
Here's some sample code:
$('html,body').dequeue().animate({scrollTop: dest}, 1000);
See if the behavior is as your expected now.
And your code (updated with finish()) - http://jsfiddle.net/z7p0vxpg/15/

jQuery Animation is delayed on scroll

I have it set to a div's width increases when I scroll past it with the following code. Now I do this same thing except with .fadeIn() and it works fine. But when I use the .animate() i'll scroll to that location and nothing will happen, but like randomly 30-40 seconds later it will just decide to animate without me even touching/moving anything. Any reason why that is?
HTML
<div>
2500px of CONTENT
</div>
<div class="statbar"></div>
CSS
.statbar {
width:100px;
height:30px;
background-color:#ff4200;
}
jQuery
$(document).scroll(function () {
var y = $(this).scrollTop();
if (y > 2500) {
$('.statbar').animate({width:'200px'}, 300);
} else {
$('.statbar').animate({width:'10px'}, 300);
}
});
Here's a JSFiddle example: https://jsfiddle.net/kr4yeyw3/2/
If you wait like 30 seconds at the div, you'll see the animation will take place (need it to happen instantly like the fadeIn() does.
EDIT: It works when I change those 300 to zeros, but it doesn't animate! Just changes width instantly without "sliding" it over.
EDIT2: Finally figured it out for anyone who one day scrolls across this page looking for a similar answer.
Adding clearQueue(), stop() and easing seemed to do the trick
$('.statbar').clearQueue().stop().animate({width:'75%'}, { "duration": 400, "easing": "linear" });
clearQueue or Stop will do fix the animation, but it doesn't address the real problem with your code. In your else statement, which is hit like 2000 times as you scroll to the bottom of the page, you are starting an animation with a duration of 400 milliseconds.
jQuery animate puts all animations into a queue and calls them one after the other so it creates a huge delay before the animation you actually want to see. api.jquery.com/animate/
Here's how I think you should rework your code:
var isExpanded = false;
$(document).scroll(function () {
var y = $(this).scrollTop();
if (y > 2500) {
$('.statbar').animate({width:'200px'}, 300);
isExpanded = true;
} else if(isExpanded) {
$('.statbar').animate({width:'10px'}, 300);
isExpanded = false;
}
});
Here I use a flag to determine if the animation needs to be run and just toggle it as we switch display modes.

Scroll fires after jquery scrollTop animate completed

Why does another scroll event get called after a scrollTop animation fires its complete callback?
Click Handler:
var lock = false;
$('#id').click(function(event) {
var pos;
if (lock) {
return;
}
lock = true;
pos = 150;
console.log("jump start");
$(jQuery.browser.webkit ? "body": "html").animate({ scrollTop: pos }, 150, function () {
lock = false;
console.log("jump end");
});
});
Scroll Handler:
$(window).scroll(function (e) {
console.log("scrolling");
if (!lock){
alert('1');
}
});
Log:
jump start
scrolling
jump end
scrolling
demo on jsfiddle
Background
jQuery scrollTop() uses scrollTo() which is a fire and forget event. There is no stopped event for scrolling. The scroll events occur out of band from scrollTo. scrollTo means 'start scroll', a scroll event means 'scrolled (some position)'. scrollTo just initiates the starting of the scroll, it doesn't guarantee that scrolling finished when it returns. So, jQuery animation completes before final scroll (there could even be multiple scrolls backed up). The alternative would be for jQuery to wait for the position of the scroll to be what it requested (per my soln), but it does not do this
It would be nice if there was a specification that we could point to describing this, but it is just one of the Level 0 dom elements without a spec, see here. I think it makes sense the way that it works, which is why all browsers seem to implement it this way.
Why is this happening
The following occurs on the last scroll of the animation:
jquery: 'Window please scroll this last bit'
Window: 'I got this message from jquery to scroll I will start that now'
jquery: 'woohoo I am finished the animation, I will complete'
Your code: lock = false;console.log("jump end");
Window: 'I have scrolled' call scroll event handlers.'
Your code: $(window).scroll(function (e) { 'Why is this happening?'
As you can see jquery does not wait for the final scroll step of the animation to complete before completing the animation (going on to step 4). Partly this is because there is no stopped event for scrolling and partly this is because jquery does not wait for the scroll position to reach the position that was requested. We can detect when we have reached the destination position as described below.
Solutions
There is no stopped event for when scrolling completes. See here. It makes sense that there is no stopped event because the user could start scrolling again at any point, so there is no point where scrolling has really stopped - the user might just have paused for a fraction of a second.
User scrolling: For user scrolling, the normal approach is to wait some amount of time to see if scrolling is complete as described in the answer of the referenced question (bearing in mind that the user could start scrolling again).
scrollTop: However, since we know the position that we are scrolling to we can do better.
See this fiddle.
The crux of it is that since we know where we are scrolling to, we can store that position. When we reach that position we know that we are done.
The output is now:
jump start
scroll animation
jump end
The code is (note that this is based off your fiddle rather than the code in the edited question):
var scrollingTo = 0;
$('#id').click(function(event) {
if (scrollingTo) {
return;
}
console.log("jump start");
scrollingTo = 150;
$(jQuery.browser.webkit ? "body": "html").animate({ scrollTop: scrollingTo }, 150, function () {
});
});
function handleScroll()
{
if( scrollingTo !== 0 && $(window).scrollTop() == scrollingTo)
{
scrollingTo = 0;
console.log("jump end");
}
}
$(window).scroll(function (e) {
if (!scrollingTo){
console.log('user scroll');
} else {
console.log("scroll animation");
}
handleScroll();
});
I believe that at the time the animation ends and the callback function is called, the event has not reached the window yet, so it is not re-called, it just hasn't been fired yet.

animate() not updating fast enough

I'm making a navigation bar that remains at the top of the page. When the user scrolls down, this bar will shrink, and when the user goes back to the top of the page, the navbar returns to its original dimensions.
Problem: When the user scroll down, the navbar shrinks as expected. However if the user scrolls back to the top of the page quickly, the navbar remains shrunken, and the animate() function within the scrollTop() callback function triggers after a few seconds.
To debug this, I included console.log($(window).scrollTop()); to tell me the current position of the user on the page. I get the console.log output as quick as the user scrolls. But {console.log('animated'); which is supposed to fire when the animation is completed, does not appear till a few seconds later after console.log($(window).scrollTop()); outputs 0.
How can I get animate() to respond quickly when the user scrolls up?
JS Code
var navBar = $('#navbar-inner');
var top = navBar.css('top');
$(window).scroll(function() {
console.log($(window).scrollTop());
if($(this).scrollTop() > 50) {
navBar.animate({'marginTop':'-20', 'height':'60'}, 300);
} else {
navBar.animate({'marginTop':'0', 'height':'80'}, 300, function()
{console.log('animated');});
}
});
(Posting my comment as an answer)
Use .stop() to stop any ongoing animations before starting a new one.
I experienced this kind of issues before with animations that last longer than the user action. You just need to stop the animation, something like
navBar.stop(true, true).animate(...);
To understand stop() better here is the link http://api.jquery.com/stop/. Hope it helps

Categories