Search

Automatic Infinite Carousel

Posted on 13th August 2009 — Following on from the infinite carousel, there have been a number of requests asking how to make the scrolling action automatic, so I’ve gone ahead to explain how to achieve this.

Watch

Watch jQuery Automatic Infinite Carousel screencast (Alternative flash version)

QuickTime version is approximately 8Mb, flash version is streaming.

View the demo used in the screencast

The Changes

To make the carousel automatically loop round by itself is pretty easy. In addition to automatic scrolling, I wanted to add the ability to make the scrolling pause when the mouse was over the carousel. To do this we need:

  1. An event we can trigger to go to the next panel
  2. A timer to keep firing the new custom event
  3. Mouseover and mouseout events to pause the timer

New Custom Event

As you’ll see from the original code we have the next and previous arrows. We could just trigger the next arrow click, but this feels a bit clunky.

So I’ve created a new event called “next” which is very similar to the next arrow being clicked:

$(this).bind('next', function () {
  gotoPage(currentPage + 1);
});

This code goes directly after our events inside the plugin, since it needs to access the currentPage variable and the gotoPage function.

We can test this custom event by calling the following in Firebug:

>>> $('.infiniteCarousel').trigger('next');

Next we need to make this call automatic.

Using Timers

There are two types of time:

  • setTimeout - runs a function in n milliseconds once
  • setInterval - runs a function every n milliseconds

We’ll use setInterval to trigger the next call every 2 seconds. Inside the $(document).ready() function we add the following after we attach the plugin:

setInterval(function () {
  $('.infiniteCarousel').trigger('next');
}, 2000);

Now the scrolling is automatic. Finally we need to only run this if the mouse isn’t over the infiniteCarousel element.

Using Mouse Events

We’ll create a flag variable to track whether we should be automatically scrolling or not. When the mouse goes over the infiniteCarousel, it will be false otherwise true. Then within the setInterval, we’ll only trigger the next event if we’re supposed to be scrolling:

var autoscrolling = true;

$('.infiniteCarousel').infiniteCarousel().mouseover(function () {
  autoscrolling = false;
}).mouseout(function () {
  autoscrolling = true;
});

setInterval(function () {
  if (autoscrolling) {
    $('.infiniteCarousel').trigger('next');
  }
}, 2000);

And that’s it. All we need to change to make the infinite carousel to run automatically.

Related posts

Demo

If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.

Source Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Automatic Infinite Carousel</title>
<style type="text/css" media="screen">
<!--
body { font: 1em "Trebuchet MS", verdana, arial, sans-serif; font-size: 100%; }
input, textarea { font-family: Arial; font-size: 125%; padding: 7px; }
label { display: block; } 

.infiniteCarousel {
  width: 395px;
  position: relative;
}

.infiniteCarousel .wrapper {
  width: 315px; /* .infiniteCarousel width - (.wrapper margin-left + .wrapper margin-right) */
  overflow: auto;
  height: 105px;
  margin: 0 40px;
  position: absolute;
  top: 0;
}

.infiniteCarousel ul a img {
  border: 5px solid #000;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
}

.infiniteCarousel .wrapper ul {
  width: 840px; /* single item * n */
  list-style-image:none;
  list-style-position:outside;
  list-style-type:none;
  margin:0;
  padding:0;
  position: absolute;
  top: 0;
}

.infiniteCarousel ul li {
  display:block;
  float:left;
  padding: 10px;
  height: 85px;
  width: 85px;
}

.infiniteCarousel ul li img {
    -webkit-transition: border-color 400ms;
}

.infiniteCarousel ul:hover li img {
  border-color: #000;
}

.infiniteCarousel ul:hover li:hover img {
  border-color: #333;
}

.infiniteCarousel ul li a img {
  display:block;
}

.infiniteCarousel .arrow {
  display: block;
  height: 36px;
  width: 37px;
  background: url(images/arrow.png) no-repeat 0 0;
  text-indent: -999px;
  position: absolute;
  top: 37px;
  cursor: pointer;
  outline: 0;
}

.infiniteCarousel .forward {
  background-position: 0 0;
  right: 0;
}

.infiniteCarousel .back {
  background-position: 0 -72px;
  left: 0;
}

.infiniteCarousel .forward:hover {
  background-position: 0 -36px;
}

.infiniteCarousel .back:hover {
  background-position: 0 -108px;
}



-->
</style>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">

(function () {
    $.fn.infiniteCarousel = function () {
        function repeat(str, n) {
            return new Array( n + 1 ).join(str);
        }
        
        return this.each(function () {
            // magic!
            var $wrapper = $('> div', this).css('overflow', 'hidden'),
                $slider = $wrapper.find('> ul').width(9999),
                $items = $slider.find('> li'),
                $single = $items.filter(':first')
                
                singleWidth = $single.outerWidth(),
                visible = Math.ceil($wrapper.innerWidth() / singleWidth),
                currentPage = 1,
                pages = Math.ceil($items.length / visible);
                
            /* TASKS */
            
            // 1. pad the pages with empty element if required
            if ($items.length % visible != 0) {
                // pad
                $slider.append(repeat('<li class="empty" />', visible - ($items.length % visible)));
                $items = $slider.find('> li');
            }
            
            // 2. create the carousel padding on left and right (cloned)
            $items.filter(':first').before($items.slice(-visible).clone().addClass('cloned'));
            $items.filter(':last').after($items.slice(0, visible).clone().addClass('cloned'));
            $items = $slider.find('> li');
            
            // 3. reset scroll
            $wrapper.scrollLeft(singleWidth * visible);
            
            // 4. paging function
            function gotoPage(page) {
                var dir = page < currentPage ? -1 : 1,
                    n = Math.abs(currentPage - page),
                    left = singleWidth * dir * visible * n;
                
                $wrapper.filter(':not(:animated)').animate({
                    scrollLeft : '+=' + left
                }, 500, function () {
                    // if page == last page - then reset position
                    if (page > pages) {
                        $wrapper.scrollLeft(singleWidth * visible);
                        page = 1;
                    } else if (page == 0) {
                        page = pages;
                        $wrapper.scrollLeft(singleWidth * visible * pages);
                    }
                    
                    currentPage = page;
                });
            }
            
            // 5. insert the back and forward link
            $wrapper.after('<a href="#" class="arrow back">&lt;</a><a href="#" class="arrow forward">&gt;</a>');
            
            // 6. bind the back and forward links
            $('a.back', this).click(function () {
                gotoPage(currentPage - 1);
                return false;
            });
            
            $('a.forward', this).click(function () {
                gotoPage(currentPage + 1);
                return false;
            });
            
            $(this).bind('goto', function (event, page) {
                gotoPage(page);
            });
            
            // THIS IS NEW CODE FOR THE AUTOMATIC INFINITE CAROUSEL
            $(this).bind('next', function () {
                gotoPage(currentPage + 1);
            });
        });
    };
})(jQuery);

$(document).ready(function () {
    // THIS IS NEW CODE FOR THE AUTOMATIC INFINITE CAROUSEL
    var autoscrolling = true;
    
    $('.infiniteCarousel').infiniteCarousel().mouseover(function () {
        autoscrolling = false;
    }).mouseout(function () {
        autoscrolling = true;
    });
    
    setInterval(function () {
        if (autoscrolling) {
            $('.infiniteCarousel').trigger('next');
        }
    }, 2000);
});


</script>

</head>
<body>

    <h1>Automatic Infinite Carousel</h1>
    
    <div class="infiniteCarousel">
      <div class="wrapper">
        <ul>
          <li><a href="http://www.flickr.com/photos/remysharp/3047035327/" title="Tall Glow"><img src="http://farm4.static.flickr.com/3011/3047035327_ca12fb2397_s.jpg" height="75" width="75" alt="Tall Glow" /></a></li>
          <li><a href="http://www.flickr.com/photos/remysharp/3047872076/" title="Wet Cab"><img src="http://farm4.static.flickr.com/3184/3047872076_61a511a04b_s.jpg" height="75" width="75" alt="Wet Cab" /></a></li>
          <li><a href="http://www.flickr.com/photos/remysharp/3047871878/" title="Rockefella"><img src="http://farm4.static.flickr.com/3048/3047871878_84bfacbd35_s.jpg" height="75" width="75" alt="Rockefella" /></a></li>
          <li><a href="http://www.flickr.com/photos/remysharp/3047034929/" title="Chrysler Reflect"><img src="http://farm4.static.flickr.com/3220/3047034929_97eaf50ea3_s.jpg" height="75" width="75" alt="Chrysler Reflect" /></a></li>

          <li><a href="http://www.flickr.com/photos/remysharp/3047871624/" title="Chrysler Up"><img src="http://farm4.static.flickr.com/3164/3047871624_2cacca4684_s.jpg" height="75" width="75" alt="Chrysler Up" /></a></li>
          <li><a href="http://www.flickr.com/photos/remysharp/3047034661/" title="Time Square Awe"><img src="http://farm4.static.flickr.com/3212/3047034661_f96548965e_s.jpg" height="75" width="75" alt="Time Square Awe" /></a></li>
          <li><a href="http://www.flickr.com/photos/remysharp/3047034531/" title="Wonky Buildings"><img src="http://farm4.static.flickr.com/3022/3047034531_9c74359401_s.jpg" height="75" width="75" alt="Wonky Buildings" /></a></li>
          <li><a href="http://www.flickr.com/photos/remysharp/3047034451/" title="Leaves of Fall"><img src="http://farm4.static.flickr.com/3199/3047034451_121c93386f_s.jpg" height="75" width="75" alt="Leaves of Fall" /></a></li>
        </ul>        
      </div>
    </div>
</body>
</html>

Comments

  1. kdorg On 13th August 2009 at 20:08

    cool, but, why has a blank space between the first anda the last picture?

  2. Remy On 13th August 2009 at 23:08

    @kdog - see the original post for the explanation: http://jqueryfordesigners.com/jquery-infinite-carousel/

  3. Jesper Andersson On 15th August 2009 at 01:08

    This is awesome ;)

    Am i alowed to use this in any way? On my own website, wordpress themes and so on?

    I really understand if you dont want it to be used in this way!

  4. Rohan On 15th August 2009 at 04:08

    I have to say, J4D is the best resource I can find on the web for jQuery stuff. I always look here first before anything else!

  5. didxga On 21st August 2009 at 20:08

    Thanks for sharing your skill. your tuts is just excellent!

  6. Tristen On 23rd August 2009 at 21:08

    This was a great tutorial. Thank you.
    I’m wondering if there is a way for the slider to only target parent list items.

    I tried using the slider on a list of divs with nested lists within them and it tried putting all lists (parent or otherwise) in an infinite scroll.

  7. Evan Skuthorpe On 24th August 2009 at 09:08

    Cheers for this, very useful.

  8. Simon On 31st August 2009 at 22:08

    Love it, this is awesome…

    One question though: Is it possible to add an index (something along the lines of those little dots you often see in/below carousels) to indicate which part of the carousel is currently in the view port? I find with infinate carousels that it is often confusing whether you’re seeing new content Vs. having looped back to the beginning.

    I had a tinker but my limited jQuery skills didn’t get me very far :-)

  9. bill On 1st September 2009 at 00:09

    I like the one at http://www.catchmyfame.com/2009/08/27/jquery-infinite-carousel-plugin-1-2-released/ better. It’s more fluid and has options that are more useful to me. You should also see their before/after plugin.

  10. joe On 3rd September 2009 at 01:09

    nice and thanks for sharing! i have a question, I been looking for something similar to http://www.harvest.org (the big sliding banner in the middle of the page) instead of multiple images on one Automatic Infinite Carousel, how would i just make it one whole banner slide and clickable too when mouse is over or similar to a rotation banner without using flash? thanks a million! - joe

  11. Josh On 3rd September 2009 at 11:09

    Very Very nice auto scroller, thankyou very much for making this Remy!

  12. Mattias On 9th September 2009 at 23:09

    This doesn’t show up in the iTunes Podcast feed: http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=281057468

    The newest episode there is Play School: Broken Repeating Animations which was posted 2009-07-23.

    I love love love your podcast! I also love jquery, so please keep this up, I learn something new pretty much every episode.

  13. el deste On 14th September 2009 at 02:09

    This code is incompatible with Lightview http://www.nickstakenburg.com/projects/lightview/, is there a way to fix this and make it functional?

  14. Juan On 26th September 2009 at 05:09

    it works on ie8, chrome,ff,opera

    any fix for IE7?

    Thanks great work

  15. Juan On 1st October 2009 at 01:10

    the fix is add left: -4px; inside of .infiniteCarousel .wrapper

    looks like this: .infiniteCarousel .wrapper { left: -4px; }

    kutgw

  16. Steven On 1st October 2009 at 17:10

    When defining the variables you need to add a comma at the end of the line defining $single to keep from the currentPage variable becoming a global variable and causing problems if you’d like to use multiple carousels on the same page.

    $single = $items.filter(’:first’),

    Steven

  17. Molly On 1st October 2009 at 17:10

    Thanks a lot! This was very easy to use and worked perfectly. I really appreciate it.

  18. cateye On 4th October 2009 at 18:10

    The order (sorting) of the images is different on IE7.

    .infiniteCarousel .wrapper { left: -0px; } fixes the lay out issue but the first item of the list is not the first image in the carousel (only in IE7). This bug drives me crazy!

    Any one a solution?

  19. bogyvet On 22nd October 2009 at 01:10

    Just one thing I notice. I am working one site and have bug with Firefox 3.014. After refreshing page all images lost. Same thing is happening with Safari 4.0. If you press click on address bar and press enter all images are there. I do not know if someone notice this. I’m not too good with JavaScript basic I work PHP, but I like this I and I wanted to implement. But ….

    Thanks in advace

  20. marujo On 26th October 2009 at 17:10

    hi. nice tut. and what i need to do, to slider contains the top links, like in the image. an. eg: 2006 | 2007 | 2008 | 2009 < slide 2006 > if i click on 2009, shows the 2009 slider… how can i do it? can you help me , please? its nice to do ‘timeline histories’. thanks and sorry for my english.

  21. lincoln On 29th October 2009 at 12:10

    Hi, is it possible to link the thumbnails to a bigger image with captio, remaining on the same page?

  22. Pedro Costa Neves On 8th November 2009 at 05:11

    and if we just want to show 2 itens? :S

  23. Ramsey On 15th November 2009 at 20:11

    Great tut! Is there any way to create an effect that sort of zooms or enlarges the ‘active’ image? Something similar to the effect of the Moving Boxes script on CSS-tricks.com - http://css-tricks.com/examples/MovingBoxes/ … that would be completely awesome if possible. Thanks!

  24. Chon On 20th November 2009 at 15:11

    What about being able to add new items dynamically through AJAX without having to refresh the page? Like from a live RSS feed.

  25. kimberly On 29th December 2009 at 01:12

    Hi! Thanks for your awesome website. Great tutotials and explaination…. you’ve done a great job with this site. Thanks! One question, I would like to use this carousel. Although I noticed in the screencast you mentioned a size limit. Is this the best size (in the demo), Do you not recommend to use it if I was going to make it larger… Thank you. Kimberly

Leave your own comment
  • http://