Efficient use jquery scroll function - javascript

I want to check if the scrollTop is greater than 1. But when I use the following code, the scroll event keeps firing when the user scrolls which leads to bad performance.
$(window).on('scroll', function(){
var scrollTop = $(this).scrollTop();
if(scrollTop > 1){
$('.header').addClass('active');
} else{
$('.header').removeClass('active');
}
});
Is there a more efficient way to do this, so performance stays in check?

For optimisations sake, stop requesting the header dynamically each time.
Store a reference to the header in the window object.
$(document).ready(function() {
window.headerObject = $('.header');
window.jQueryWindow = $(window);
});
$(window).on('scroll', function(){
var scrollTop = jQueryWindow.scrollTop();
if(scrollTop > 1){
window.headerObject.addClass('active');
} else{
window.headerObject.removeClass('active');
}
});
Instead of having to traverse the DOM to find .header multiple times each request and making a new jquery object of the window object each time, you simply store them, negating the initialisation cost improving speed.
if you want to comporare speeds:
$(document).ready(function() {
window.headerObject = $('.header');
window.jQueryWindow = $(window);
});
$(window).on('scroll', function(){
starttime = performance.now();
var scrollTop = jQueryWindow.scrollTop();
if(scrollTop > 1){
window.headerObject.addClass('active');
} else{
window.headerObject.removeClass('active');
}
console.log('scroll optimised took' + (performance.now() - starttime) + " milliseconds");
});
$(window).on('scroll', function(){
starttime = performance.now();
var scrollTop = $(this).scrollTop();
if(scrollTop > 1){
$('.header').addClass('active');
} else{
$('.header').removeClass('active');
}
console.log('scroll dynamic took' + (performance.now() - starttime) + " milliseconds");
});
scroll optimised took 0.060999998822808266 milliseconds
scroll dynamic took 0.26700000125856604 milliseconds
As you can see, the optimised code takes on average 0.06 milliseconds whilst the full dynamic selector takes 0.26 milliseconds.
Quite the performance gain.
The delay might come more though from the calculations needed for restyling active than the cost of this loop.

Related

Cannot get onScroll function to fire only once

I'm pretty new to JavaScript and found myself a little stuck on one seemingly super simple task with an onScroll function.
I have the following code (see below) which is working great. However, it currently fires every time the user scrolls up or down, returning to that particular vertical location on the page. I only want it to fire the first time it is scrolled to after a page load.
Please help!
Big respect and many thanks in advance!
$(window).scroll(function () {
$('#pro1').each(function () {
var topOfWindow = $(window).scrollTop(),
bottomOfWindow = topOfWindow + $(window).height();
var imagePos = $(this).offset().top;
if(imagePos < bottomOfWindow-200 && imagePos >= topOfWindow-500){
$(this).addClass('bigEntrance2');
}else{
$(this).removeClass('bigEntrance2');
}
});
});
You can use the one method. It is the same as the on method, but only fires once per page load. So for your example, it would look like this:
$(window).one("scroll", function()
{
# Scroll code here
});
Edit: I think I understand your question better. You want the code to check when you're in that scroll region, but only execute once. So to do that, you first should designate a custom event:
$(window).one("customEvent", function()
{
$(this).addClass('bigEntrance2');
});
And then trigger that event when you want:
if(imagePos < bottomOfWindow-200 && imagePos >= topOfWindow-500)
{
$(this).trigger("customEvent");
}
That way, the class 'bigEntrance2' is only applied once, which is what I think you want.
Well you can use a variable and use it as a flag. The first time the user scrolls once the page loads, you set it to true. After that, you check that variable to avoid doing always the same code.
var alreadyScrolled = false;
$(window).scroll(function () {
if(!alreadyScrolled) {
$('#pro1').each(function () {
var topOfWindow = $(window).scrollTop(),
bottomOfWindow = topOfWindow + $(window).height();
var imagePos = $(this).offset().top;
if(imagePos < bottomOfWindow-200 && imagePos >= topOfWindow-500){
$(this).addClass('bigEntrance2');
}else{
$(this).removeClass('bigEntrance2');
}
});
alreadyScrolled = true;
}
});

Infinite auto scroll top-to-bottom and back, how to control/configure speed, time of pause at end?

I'm trying to make a long page of images scroll up and down infinitely (for an exhibition).
This is what I've been working with (code I found here, so helpful!):
https://jsfiddle.net/p7r73tke/
It's mostly working ok for what I want, but I need more control over speed and pause.
How can I make the pause at the top longer?
is there a way to make it pause randomly for ~1 second ?
does anyone know of an easier way to do what I'm thinking of? maybe as samuel-liew suggests, javascript is not the best solution for the problem
thank u thank u!
function scrollpage() {
function f() {
window.scrollTo(0, i); //idk
if (status == 0) {
i = i + 50; //scroll speed top to bottom?
if (i >= Height) {
status = 30; //idk?
}
} else {
i = i - 10; //scroll speed bottom to top?
if (i <= 1) { // if you don't want continue scroll then remove this if condition
status = 0; //idk
}
}
setTimeout(f, 0.01); //idk
}
f();
}
var Height = 15000; //doc height input manually
var i = 1, //idk
j = Height,
status = 0; //idk
scrollpage();
(I'm new and tender to JavaScript, as you can see in the comments)
Thanks for any help!
jQuery solution:
var speed = 10000; // 10000 = 10 seconds
var doScroll = function() {
var direction = $(window).scrollTop() != 0 ? 0 : $(document).height() - $(window).height();
$('html, body').animate({ scrollTop: direction }, speed, 'linear');
}
doScroll(); // once on page load
setInterval(doScroll, speed + 10); // once every X ms
DEMO: http://jsfiddle.net/samliew/k35tbgau/
JavaScript:
Sorry, I do not recommend pure JavaScript for this as you have to take into account:
Cross-browser issues with getting window height, document height, and current scroll position
Recalculating the scroll speed based on content height every time the browser is resized
Programming an animation function
Keeping track of intervals and timeouts, and when you need to clear them
Direction/state of scroll
Taking into consideration if user manually scrolls the scrollbar
Probably lots more...

Why are my animations delayed in Firefox? How can I improve this scroll script?

I'm having troubles getting this code to execute in a timely manner in Firefox. It seems to work just fine in Chrome.
JSFiddle here: http://jsfiddle.net/EXDhb/
Real live example page I'm working with here: http://mindevo.com/tests/tacos.html
I'm not sure if I'm leaving something out. I kind of hacked this together from reading a bunch of page-scroll scripts other people have put together. Not sure if this is even the best way for me to do what I'm trying to accomplish (which is to darken the next area until it's somewhat revealed. (I used halfway for this).
Here's my javascript:
$(document).ready(function(){
$(window).scroll(function(){
$('.dark').each(function(i){
var half_object = $(this).position().top + ($(this).outerHeight()/2);
var bottom_window = $(window).scrollTop() + $(window).height();
var bottom_object = $(this).position().top + $(this).outerHeight();
if(bottom_window > half_object){
$(this).animate({'opacity':'1'},200);
}
else if(bottom_object > $(window).scrollTop()) {
$(this).animate({'opacity':'.5'},200);
}
});
});
});
Is there a better way to do this? I tried adding/removing css classes but it invoked some crazy Chrome bug I was not pleased about.
Why does it work so slowly in Firefox?
Start by not having 6 separate jQuery $(this) operations and multiple $(window)! Use temp variables whenever you can to avoid requerying.
JSFIddle: http://jsfiddle.net/TrueBlueAussie/EXDhb/9/
$(document).ready(function () {
// window never changes
var $window = $(window);
$window.scroll(function () {
// Window height may have changed between scrolls
var windowHeight = $window.height();
var scrollTop = $window.scrollTop();
$('.dark').each(function (i) {
var $this = $(this);
var top = $this.position().top;
var outerH = $this.outerHeight();
var half_object = top + (outerH / 2);
var bottom_window = scrollTop + windowHeight;
var bottom_object = top + outerH;
console.log(half_object);
if (bottom_window > half_object) {
$this.stop().animate({
'opacity': '1'
}, 200);
} else if (bottom_object > scrollTop) {
$this.stop().animate({
'opacity': '.5'
}, 200);
}
});
});
});
And so on until you do not do anything twice that has an overhead that you do not need to have.
Update: Stop previous animations
The pause was not caused by the speed of the code above, but by not stopping multiple animations. The problem is that scroll fires frequently, so without .stop() animations get queued up and fire one after the other. This made it look much slower that it actually was.
Further optimizations might involve only processing elements that are actually onscreen, but that is pretty pointless given the apparent speed now.
You can cache your variables, which should help slightly:
$(document).ready(function(){
var $window = $(window);
$window.scroll( function(){
$('.dark').each(function(i){
var $this = $(this);
var outerHeight = $this.outerHeight();
var positionTop = $this.position().top;
var half_object = positionTop + (outerHeight/2);
var bottom_window = window.scrollTop() + window.height();
var bottom_object = positionTop + outerHeight;
if(bottom_window > half_object){
$this.animate({'opacity':'1'}, 200);
} else if(bottom_object > window.scrollTop()) {
$this.animate({'opacity':'.5'}, 200);
}
});
});
});
I realize there is already an accepted answer, but many times it is useful to do something only after the user has stopped scrolling, and not each time the "scroll" event fires. This event can can fire upwards of 50 times per second, leaving you with ~20ms to do what you need to do. This other StackOverflow question shows you how to do something only after scrolling has stopped. As #TrueBlueAussie mentioned in his answer, you would still want to stop any animations that were currently running.

How to reverse a css transistion on scroll for fly in / fly out effect

I am trying to get an fly-in / fly- out effect happening
Scroll down - animate in
Scroll-up animate out
To get a similar effect to the nizo website
http://nizoapp.com/
I have used this code I found on Stackoverflow "Fade in element on scroll down using css"
to determine whether the element is on screen, in the viewport, and then animate it.
$(window).scroll(function () {
/* Check the location of each desired element */
$('.article').each(function (i) {
var bottom_of_object = $(this).position().top + $(this).outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
/* If the object is completely visible in the window, fade it it */
if (bottom_of_window > bottom_of_object) {
$(this).animate({
'opacity': '1'
}, 500);
}
});
});
Which works quite well.
I have added it to this demo page, and modified it.
http://saigonhousefinder.com/potteryone/fadinonscroll.html
(probably not live for long)
I have used css transitions to get the effect I am looking for. FLy-in Fly-out etc etc
And then I found..... this function which does the same thing
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
Anyway.......
I cant get the animations to work when scrolling down, fly-in.
But I cannot get the animations to go in reverse when they fly out on scroll up
I thought the easiest way would be to detect if you are scrolling down of up, so I found this method / function
(function () {
var previousScroll = 0;
$(window).scroll(function () {
var currentScroll = $(this).scrollTop();
if (currentScroll > previousScroll){
$("#div").fadeIn("slow");
}
else {
$("#div").fadeOut("slow");
}
previousScroll = currentScroll;
});
}());
Which works well, but I cannot get it working.
At this point I can detect when an element is visible on the screen then add an effect to it.
What I need it to detect when that same element is beginning to go off the screen and apply another effect to it.
Any help on how to get this working would be great
Have a nice day
That's a really neat demo and a great concept! I played around with some code and it seems that you are almost there. You need to detect when the top of the screen meets the top of the element, so only calculate the offset once when the page is loaded. I added a 20px threshold so it kicks in a bit early. Let me know if this helps, it can be tweaked depending on how and when you want to call it. Here is a simple js fiddle demo
http://jsfiddle.net/XhAhR/23/
(function () {
var previousScroll = 0;
var elemTop = $("#div").offset().top;
$("#div").fadeOut();
$(window).scroll(function () {
var currentScroll = $(this).scrollTop();
if (currentScroll > previousScroll){
if(elemTop -20 > currentScroll){
$("#div").fadeIn("slow");
}
}
else {
if(elemTop - 20 > currentScroll){
$("#div").fadeOut("slow");
}
}
previousScroll = currentScroll;
});
}());

reduce number of calls for .resize and .scroll methods

I'm using the following code to find out which part of the page the viewer is visiting (something like google books, to find out the page that's being viewed) :
$("#main-content").scroll(function () {
Nx.curPage = (Math.round($(this).scrollTop()/620)+1);
window.location.hash = "#"+Nx.curPage;
Nx.select(undefined);
});
also in another part I use $(window).resize( ... ) to fit my content in current window size, which is called for every single resize . as you can imagine this slows down the page alot, specially on older hardwares. Is there any way to realise when scrolling or resizing is stopped and then start doing the stuff, so number of processes is reduced ? something like $("#main-content").scrollStop ???
You can do two things.
1.) Set up a timeout so that resize/scroll only happens after some idle state:
var timeout;
$("#main-content").scroll(function () {
clearTimeout(timeout);
timeout = setTimeout(function(){
Nx.curPage = (Math.round($(this).scrollTop()/620)+1);
window.location.hash = "#"+Nx.curPage;
Nx.select(); // note: undefined is passed by default
}, 200);
});
2.) Limit the number of calls / sec:
var lastScroll = 0;
$("#main-content").scroll(function () {
var now = +new Date;
if (now - lastScroll > 100) { // only execute if (elapsed > 100ms)
Nx.curPage = (Math.round($(this).scrollTop()/620)+1);
window.location.hash = "#"+Nx.curPage;
Nx.select();
lastScroll = now;
}
});
​
Try the function below. It checks if the user has scrolled past a certain no. of pixels, but the function only fires at set intervals (5 times a second in the example below) rather than continuously during scrolling.
var scrollCheck;
$(window).on('scroll', function() {
clearInterval(scrollCheck);
scrollCheck = setInterval(function(){
clearInterval(scrollCheck);
scrollPosition = $(this).scrollTop();
scrollAmount = 150 // no. of pixels that have been scrolled from top
if(scrollPosition > scrollAmount){
alert('scrolled past point')
}else{
alert('not scrolled past point')
}
},200);
});

Categories

Resources