The problem:
I have a fancy looping image carousel that needs to start—from a specific first slide—when the user scrolls to a certain div. It should NEVER restart if the user scrolls up/down and back to that div.
I can only currently get it to start when the user scrolls to the div—and then it gets screwed up when you scroll away and back to it, which I assume is because the function starts running again.
What I'm trying to achieve:
- User scrolls to certain div
- Fancy image carousel animation function runs
- If user scrolls up/down and back to the div, the animation function never starts again.
My (anonymized, sorry guys!) code:
/
HTML
<p class="scroll_down">Scroll down...</p>
<div class="animation_container">You should get an alert only once here—the first time you scroll to this div.</div>
CSS
.scroll_down {
margin-bottom: 1000px;
}
.animation_container {
width: 300px;
height: 200px;
background-color: red;
padding: 30px;
color: white;
margin-bottom: 1000px;
}
jQuery
// The fancy function for my animations
function doSomeComplicatedStuff() {
alert("...and here's where the plicated animations happen!");
}
// The function to check if div.animation_container is scrolled into view
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
// If div.animation_container is scrolled into view, run the fancy function
$(window).on('scroll', function() {
if (isScrolledIntoView('.animation_container')) {
run_once(function() {
doSomeComplicatedStuff();
});
}
});
// The function that's supposed to make sure my fancy function will only run ONCE, EVER
function run_once( callback ) {
var done = false;
return function() {
if ( !done ) {
done = true;
return callback.apply( this, arguments );
}
};
}
Apologies for the script clearly written by a visual designer. Let me know if the question isn't clear enough from the anonymized code.
The problem:
I have a fancy looping image carousel that needs to start—from a specific first slide—when the user scrolls to a certain div. It should NEVER restart if the user scrolls up/down and back to that div.
I can only currently get it to start when the user scrolls to the div—and then it gets screwed up when you scroll away and back to it, which I assume is because the function starts running again.
What I'm trying to achieve:
- User scrolls to certain div
- Fancy image carousel animation function runs
- If user scrolls up/down and back to the div, the animation function never starts again.
My (anonymized, sorry guys!) code:
http://jsfiddle/annablabber/h8pqW/
HTML
<p class="scroll_down">Scroll down...</p>
<div class="animation_container">You should get an alert only once here—the first time you scroll to this div.</div>
CSS
.scroll_down {
margin-bottom: 1000px;
}
.animation_container {
width: 300px;
height: 200px;
background-color: red;
padding: 30px;
color: white;
margin-bottom: 1000px;
}
jQuery
// The fancy function for my animations
function doSomeComplicatedStuff() {
alert("...and here's where the plicated animations happen!");
}
// The function to check if div.animation_container is scrolled into view
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
// If div.animation_container is scrolled into view, run the fancy function
$(window).on('scroll', function() {
if (isScrolledIntoView('.animation_container')) {
run_once(function() {
doSomeComplicatedStuff();
});
}
});
// The function that's supposed to make sure my fancy function will only run ONCE, EVER
function run_once( callback ) {
var done = false;
return function() {
if ( !done ) {
done = true;
return callback.apply( this, arguments );
}
};
}
Apologies for the script clearly written by a visual designer. Let me know if the question isn't clear enough from the anonymized code.
Share Improve this question asked Jul 16, 2014 at 21:45 AnnaBlabberAnnaBlabber 4421 gold badge7 silver badges21 bronze badges 2- Your fiddle seems to not be working – Justin C Commented Jul 16, 2014 at 21:54
- Sorry, I was trying so many different things to achieve what I wanted that I left some broken code in there. I guess it didn't match up to what I described. – AnnaBlabber Commented Jul 16, 2014 at 22:10
4 Answers
Reset to default 5Move that done
variable into a global?
var firstScroll = false;
$(window).on('scroll', function() {
if (isScrolledIntoView('.animation_container') && !firstScroll) {
doSomeComplicatedStuff();
}
});
function doSomeComplicatedStuff() {
firstScroll = true;
// Your code here
}
This way, the first time isScrolledIntoView
returns true, the doComplicatedStuff
function immediately flips the boolean firstScroll
that stops subsequent calls.
You can have something like this
// The fancy function for my animations
var alreadyRun = false;
function doSomeComplicatedStuff() {
alert("...and here's where the plicated animations happen!");
}
// The function to check if div.animation_container is scrolled into view
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
// If div.animation_container is scrolled into view, run the fancy function
$(window).on('scroll', function() {
if (isScrolledIntoView('.animation_container') && !alreadyRun) {
doSomeComplicatedStuff();
alreadyRun = true;
}
});
Working jsfiddle
- Put that done variable into the global scope. Else it is redefined again and again every time that
run_once()
is called. A better approach would be adding a first parameter to that function to identify which action is ran or not (function run_once(identifier,callback) { if(!done[identifier]) { run function and set done[identifier] to true; }
) - Remove that
return function()
fromrun_once()
- See Fiddle
Here is an updated solution: http://jsfiddle/h8pqW/2/
Basically, you were running run_once
every time the condition was met, so it was creating a new done
variable. I moved the run_once
call out into the doSomeComplicatedStuff
declaration, converting that to a method that will only run once.
// The fancy function for my animations
var doSomeComplicatedStuff = run_once(function () {
alert("...and here's where the plicated animations happen!");
});
Here is a more performant alternative that does not require the use of a run_once
helper: http://jsfiddle/h8pqW/3/
In this example, I simply unbind the scroll
event as soon as the function is called. This will prevent the page from continuing to try to run the function each time the user scrolls.
// If div.animation_container is scrolled into view, run the fancy function
$(window).on('scroll', function() {
if (isScrolledIntoView('.animation_container')) {
doSomeComplicatedStuff();
$(window).unbind('scroll');
}
});