5

I created an image slider that ends on one image, but now I'd like to take it a step further and make it loop.

Here is my code in the head tag

<style>
#picOne, #picTwo, #picThree, #picFour, #picFive{
position:absolute;
display: none;
}

#pics {
width:500px;
height:332px;
}
</style>

<script src="http://code.jquery.com/jquery-1.4.4.min.js" type="text/javascript"></script>

<script type="text/javascript">
$(document).ready(function() { 
    $('#picOne').fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picTwo').delay(5000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picThree').delay(10000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picFour').delay(15000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picFive').delay(20000).fadeIn(1500).delay(3500);
});
</script>

and here is where it is implemented in the body code

<div id="pics">
<center>
<img src="img/dolllay.jpg" width="500" height="332" id="picFive" />
<img src="img/dye.jpg" width="500" height="332" id="picTwo" />
<img src="img/dollsit.jpg" width="500" height="332" id="picThree" />
<img src="img/heirloom.jpg" width="500" height="332" id="picFour" />
<img src="img/heritage.jpg" width="500" height="332" id="picOne" />
</center>
</div>

Could I turn it into a function and then loop it? Can I get any guidance on that? Thank you very much

SheetJS
  • 22,470
  • 12
  • 65
  • 75

8 Answers8

3

Everyone's answering the question, but not solving the problem.

Sure, you can just put a loop wrapper around it (preferably one that doesn't terminate), but why not just program it right? Why have all the hardcoded times, and why not make it more robust?

Try rewriting your code like this. It makes it much easier to modify the pictures you loop through:

var pictures = ["picOne", "picTwo", "picThree", "picFour", "picFive"];
var index = 0;

var displayImage = function() {
    if (index == pictures.length) { return; }

    $("#" + pictures[index++]).fadeIn(1500).delay(3500).fadeOut(1500, displayImage);
};

displayImage();

Then, if you want to loop back, you simply tweak the displayImage function:

var displayImage = function() {
    if (index == pictures.length) { index = 0; }
    $("#" + pictures[index++]).fadeIn(1500).delay(3500).fadeOut(1500, displayImage);
};

TRY IT at jsfiddle

EDIT

On more careful reading of your question, I see that my original answer didn't do exactly what you needed. You have it set so that every five seconds, one will have faded out and the other one will have faded in. Currently, mine takes 6.5 seconds, since mine is all operating sequentially instead of concurrently. To make it come close to matching yours, just change the 1500s to 750s:

    $("#" + pictures[index++]).fadeIn(750).delay(3500).fadeOut(750, displayImage);

This will take the right amount of time. It's slightly different from yours, in that one fades out all the way before the other fades in. The alternative is to actually skip the fadeIn and keep the fadeout. This is a lot closer to the way yours looks.

    $("#" + pictures[index++]).show().delay(3500).fadeOut(1500, displayImage);

Or, make a very small fadein, to help reduce the flash of the new image:

    $("#" + pictures[index++]).fadeIn(100).delay(3500).fadeOut(1400, displayImage);

Final Edit (really!)

Ok, to get the fadeIn and fadeOut to work reliably at the same time, the solution was to use neither. I went back to using animate, instead. As a result, I had to completely rewrite the displayImage function, but this is exactly what you need:

var displayImage = function () {
    if (index == pictures.length) {
        index = 0;
    }

    $("#" + pictures[index]).show().delay(3500).animate({
        opacity: 0.2
    }, {
        step: function (now) {
            var idx = (index + 1) % pictures.length;
            var val = 1.2 - now;
            $("#" + pictures[idx]).show().css("opacity", val);
        },
        complete: function () {
            $("#" + pictures[index++]).hide();
            displayImage();
        }
    });
};

What this does is move the sequence to "show->fadeIn and Out" instead of "fade in -> show -> fade out". To make your transition smooth, I only fade it out to 0.2 instead of 0. The step function is what fades the other one in at the same time. Once the new pic is visible, I completely hide the old pic.

Here's the working fiddle for it.

Scott Mermelstein
  • 15,174
  • 4
  • 48
  • 76
  • 1
    +1 This is good as it guarantees you're never going to go out of sync and get two pics showing together. I didn't really read the first sentence of the OP's question! – El Ronnoco Jun 17 '13 at 15:05
  • WoW! Thank you so much for all of your edits. I am really excited to implement this. – user2252457 Jun 18 '13 at 01:56
  • How can I take this a step further and add a clickable on/off? – user2252457 Jun 18 '13 at 02:09
  • Check out the latest fiddle: http://jsfiddle.net/HKLGJ/2/ . Basically, add a checkbox, and check the status of the checkbox inside the `if (index == pictures.length)` clause. I also updated your jquery version sufficiently to let it use jqueryUI, and made the checkbox look like a pretty toggle box. – Scott Mermelstein Jun 18 '13 at 05:22
2

You can use setInterval to loop it forever, or setTimeout to loop it for a specific duration.

<script type="text/javascript">

$(document).ready(function() { 
     setInterval(ImageSlider, 1000);
});

 function ImageSlider() {
    $('#picOne').fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picTwo').delay(5000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picThree').delay(10000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picFour').delay(15000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picFive').delay(20000).fadeIn(1500).delay(3500);
 }

</script>
Darren
  • 68,902
  • 24
  • 138
  • 144
  • 1
    also you can use ClearTimeout or ClearInterval to finish loops. http://www.w3schools.com/jsref/met_win_cleartimeout.asp http://www.w3schools.com/jsref/met_win_clearinterval.asp – Arda Jun 17 '13 at 14:34
  • 1
    Where do I implement this exactly? Underneath document.ready? – user2252457 Jun 17 '13 at 14:46
  • 1
    @user2252457 - add setInterval in the document.ready - the function declaration (ImageSlider) should be outside of the document.ready() function – Darren Jun 17 '13 at 14:49
  • Am I doing this right? – user2252457 Jun 17 '13 at 14:55
  • @user2252457 - you've missed the annoymous function for document ready. I have edited my answer to include exactly what you need, copy and paste that. – Darren Jun 17 '13 at 14:58
  • Thanks. It works great except for at some point there are two sets of images. one fades, and one is stuck on the last image – user2252457 Jun 17 '13 at 15:03
2
$(document).ready(function() { 
   setInterval(example, 10000); // repeat every 10 seconds
});

function example() {
    $('#picOne').fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picTwo').delay(5000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picThree').delay(10000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picFour').delay(15000).fadeIn(1500).delay(3500).fadeOut(1500);
    $('#picFive').delay(20000).fadeIn(1500).delay(3500);
}
Gabe
  • 49,577
  • 28
  • 142
  • 181
2

A better way would be to give each pic the same class such as 'fadeinout'. This will mean you don't have to re-write your code when you add/remove more pics.

eg

<img id="picFive" class="fadeinout" ....  
/* not sure if they are even <img>s but whatever they are*/

Then do

$(document).ready(function() { 
    beginFades();
});

function beginFades() {
    $('.fadeinout').each( function(i,el) {  // find all elements with fadeinout
        //for each one, trigger the start of the fading after i*5000 milliseconds
        //i is the index of the element as it was found by jQuery - this will be in
        //document order (which actually may not be what you have but I'm guessing        
        //it is)
        setTimeout(function(){
            makeImgFadeInOut($(el))
        }, i*5000);
    });
}


function makeImgFadeInOut(el) {
    //trigger a single fadeIn, fadeOut.
    //But add a callback function to the end of fadeOut which retriggers the whole        
    //thing
    el.fadeIn(1500).delay(3500).fadeOut(1500, function(){makeImgFadeInOut(el);});
}

WORKING DEMO (WITH DIVS)

El Ronnoco
  • 11,753
  • 5
  • 38
  • 65
  • 1
    Thank you! This seems much simpler than what I had, but when I implement it on my site, nothing shows up – user2252457 Jun 17 '13 at 14:50
  • I am getting a similar problem with another set of code above. – user2252457 Jun 17 '13 at 15:10
  • hmm My answer isn't really concerned with you wanting to display only one image at a time. Scott's answer it probably best as it guarantees 1 at a time. – El Ronnoco Jun 17 '13 at 15:46
  • @user2252457 Please check out my latest update to my answer. It should give you exactly what you need - an image that displays for five seconds then fades out smoothly while the second image fades in. – Scott Mermelstein Jun 17 '13 at 16:57
1

If you want to have total control upon your elements you can use this:

 var elements = [{
   el: '#pic1',
   delay: 3500,
   fadeIn: 1500,
   fadeOut: 1500
},
{
  el: '#pic2',
  delay: 3500,
  fadeIn: 1500,
  fadeOut: 1500
 }
 //... other elements
]
var index = null;
(function loop(){
  index = index || 0;
  index = index % elements.length();
      $(elements[index].el).fadeIn(elements[index].fadeIn, function(){
      $(this).delay(elements[index].delay)
             .fadeOut(elements[index].fadeOut, function(){
                  index++;
                  window.setTimeout(loop, 5000);
              });
   })();

Edit : forgot to execute the first iteration of the loop function and removing the useless call for index inside the loop

The good thing about how this loop works is that it doesn't use the SetInterval function. and the code inside the loop need to finish what it does inside before iterating again. (you won't have this hideous bug if you click an other tab and go back to your carousel) @ElRoconno answer is pretty good too if you require less configuration

Abdoul Sy
  • 580
  • 3
  • 10
  • I like the idea of configuring each delay, fadeIn, and fadeOut, but why do you have the setTimeout? And index isn't necessary as a function argument. – Scott Mermelstein Jun 17 '13 at 15:03
  • The set timeout is for looping through the same function it's basically a "better setInterval" And you're right, the index was useless as it could be created inside the loop function. and as the images in the the example stay 5 secondes on the screen before changing I thought it was relevant I could have put a (function(){ window.setTimeout(arguments.callee, 5000); })(); instead of window.setInterval(function(){},5000); – Abdoul Sy Jun 17 '13 at 15:33
  • Sorry, to clarify, I meant "why have a setTimeout"? Why add the 5 second delay? That line could just be `loop()`, right? The 5 second delays in the OP is because everything automatically fired at the same time. By using the second argument to fadeOut, you don't need it. – Scott Mermelstein Jun 17 '13 at 15:45
  • To clarify what's been asked by @user2252457 looks like he wants this: "fading in first image" > "delay for 3.5 seconds" > "fadeout" > "wait for 5 seconds" > redo the sequence. i did a setTimeout for the 5 seconds wait because it's faster than calling yet an other delay as delaying only works for already queued elements and putting a delay before the first fadeIn would have forced me to manage the initialisation first and delay uses setTimeout inside. thought it was relevant :) – Abdoul Sy Jun 17 '13 at 15:57
0

Use any of this-

setInterval() - executes a function, over and over again, at specified time intervals

setInterval(function(){alert("Hello")},3000);

setTimeout() - executes a function, once, after waiting a specified number of milliseconds.

setTimeout(function(){alert("Hello")},3000);

What is the difference between both setInterval and setTimeout

for you may be the setTimeout will not work as it will run only once after a delay and setInterval will go on to make continuous repetitive call until the window.clearInterval(intervalVariable) is been called

Community
  • 1
  • 1
NetStarter
  • 3,189
  • 7
  • 37
  • 48
0

I have created an example on jsfiddler here. Basically you don't have to do this one at a time. Just get the whole collection of images as an array and loop over them. Hope this helps

$(document).ready(function () {
var arr = $('.pics')
arr.hide();

$(arr[0]).fadeIn(1500).delay(3500).fadeOut(1500);

var index = 1;
var maxIndex = arr.length - 1;

setInterval(function () {
    /*arr.hide();
     var pic = $(arr[index]);
     pic.show();
     */
    var pic = $(arr[index]);
    pic.fadeIn(1500).delay(3500).fadeOut(1500);


    index++;
    if (index >= maxIndex) {
        index = 0;
    }
}, 6500);

});

shake
  • 1,752
  • 4
  • 18
  • 22
0

There's really no need for setInterval here since you can use the callback built-into .fadeOut(), nor having to enumerate an array of images. You can do something as simple as:

var idx = 0;
fade();
function fade() {
    if (idx >= $('img').length) idx = 0;
    $('img').eq(idx).fadeIn(1500).delay(3500).fadeOut(1500, fade);
    idx++;
}

jsFiddle example

j08691
  • 204,283
  • 31
  • 260
  • 272