Update: Creating a news carousel with jQuery, now with time based switching

This is just a simple and quick update on the Creating a news carousel with jQuery post.

After reading this comment, and going through the code, I decided to implement the time-based switching functionality and also clean up the code a little bit (check it out here).

The additions made (along with some code cleaning) were:

  • Append a simple div that will shrink while the picture is shown and reinitialized when the picture is switched.
  • Add a setInterval call that will do the picture switching (and the new div’s animation).

Update 01/12: I added some fixes to the code

  • Use the image’s load event to calculate each individual width. When all images are loaded, then the carousel is initiated.
  • The animate_timer function now stops all animations on the timer div before reinitializing the animation

Update 01/27: Even more fixes :)

  • Work with cases were images are already in cache and load event is fired before we attach to it.
  • Fixed the way the news animation was calculated.
  • Added 2 more news to help test it better.

So here’s the new javascript that will do this:

$(function() {
    var carousel   = $('#news_carousel');
    var news       = carousel.find('ul.news');
    var controls   = null; // Will hold the ul with the controls
    var timer      = null; // Will hold the timer div
    var wait       = 5000; // Milliseconds to wait for auto-switching
    var widths     = [];   // Will hold the widths of each image
    var items_size = news.find('li').length;
    var initialized = false;
 
    if (!items_size) { return; }
 
    // Controls html to append
    var controls_str = '<ul class="controls">';
    for ( var i = 1; i <= items_size; i++) {
       controls_str += '<li><a href="#">' + i + '</a></li>';
    }
    controls_str += '</ul>';
 
    // Cache the controls list
    controls = carousel.append(controls_str).find('ul.controls');
 
    // Make the first button in controls active
    controls.find('li:first a').addClass('active');
 
    // Hook to the controls' click events
    controls.find('li a').click(function(event) {
      move_news( $(this) );
      return false;
    });
 
    // Append the timer and cache it
    timer = carousel.append('<div class="timer"></div>').find('div.timer');
 
    // Store each item's width and calculate the total width
    news.find('li img')
        .each(function(i, e) {
            widths[i] = $(e).width();          
            if ( all_images_loaded() ) { init_carousel(); }
        })        
        .load(function(e) {
            var i = news.find('li img').index(this);
            widths[i] = $(this).width();
            if ( all_images_loaded() ) { init_carousel(); }
        });
 
 
    function all_images_loaded() {
      return (items_size == widths.length) && (jQuery.inArray(0, widths) < 0);
    }
 
 
    function move_news( new_active ) {
 
      // Move unless it is already moving
      if ( $('#news_carousel ul.news:animated').length > 1 ) {
        return false;
      }    
 
      var current_active = controls.find('li a.active');
 
      if (new_active == 'next') {
        var next = current_active.parent().next().find('a');
 
        if ( !next.length ) { next = controls.find('li:first a'); }
 
        new_active = next;
      }
 
      var current_index = parseInt(current_active.text(), 10) - 1;
      var new_index     = parseInt(new_active.text(), 10) - 1;
      var move_to       = new_index - current_index;
 
 
      if (!move_to) { return false; }
 
      var direction = (move_to > 0)? '-=': '+=';
 
      var move   = 0;
      var bottom = Math.min(current_index, new_index);
      var top    = Math.max(current_index, new_index);
 
      while (bottom < top) {
        move += widths[bottom];
        bottom++;
      }
 
      news.animate({marginLeft: direction + move }, 500);
      new_active.addClass('active');
      current_active.removeClass('active');
    }
 
    function animate_timer() {
      timer.stop().css({width: '100px'}).animate({width: '1px'}, wait);
    }
 
    // Initializer, called when all images are loaded
    function init_carousel() {
      if (initialized) { return false; }
 
      // Set the news ul total width
      var width = 0;
      for( var i = 0; i < widths.length; i++) { width += widths[i]; }
      news.width(width);
 
      // Make the news change every X seconds
      setInterval(function() { move_news('next'); animate_timer(); }, wait);
      animate_timer();
 
      initialized = true;
    }
});

comments

11 Responses to “Update: Creating a news carousel with jQuery, now with time based switching”

  1. Miguel on January 22nd, 2009

    Hello is a great script!! but if you press the last number and after press the first number (total numbers: 5) this show the 4th element… (the element previous to the last element).

  2. luciano.panaro on January 27th, 2009

    @Miguel: thanks for your comments. As you noted, there were a few more bugs left in the code since I last updated. Everything should be working now. I will be probably explaining in more detail the code in a future post and do some more cleaning.

  3. israel vasquez on January 27th, 2009

    hi, what is the format for the widths array for the images, i can’t seem to customize the images width to show them.

  4. luciano.panaro on January 28th, 2009

    The box’s size is set in the css:

    #news_carousel { width: 444px; height: 333px; }

    The images however can have any width (though only the box’s size will be shown). To achieve this the script stores every image’s width in widths

    var widths = []; // Will hold the widths of each image

    Let me know if this clears your doubt.

  5. Fabio on January 29th, 2009

    Precisaly what i was looking for, a well functional and light jquery gallery to implement in my website.

    The only problme is that i want something more like http://www.msn.com.br main headlines style, instead of a button over the picture i would like it in the left side, working like a navigator with thumbnails.

    I will try to work out on it however, see if i can do it with this script.

  6. Peter on June 1st, 2009

    Hi guys.

    I am currently implementing this carousel and it works fine under IE7/8.
    We have problems however under FF. For some bizarre reason it will not load up random number of pictures from the script. No regularity in this action.

    Does it happen to you as well ?

    Cheers,
    Peter

  7. luciano.panaro on June 1st, 2009

    Hi @Peter. I haven’t experienced that, do you have a public server where I can see it?

  8. dan on July 4th, 2009

    Hi,

    Great script, I was wondering is there anyway to reset the timer when someone clicks on a link in the corner? I’m having a problem when I select another news item it only seems to show for the remainder of the timer before it jumps to the next news.

    I guess it just needs a line adding in to stop this but my javascript/jquery isn’t up to much!

  9. luciano.panaro on July 4th, 2009

    @dan: You can use the clearInteval function (https://developer.mozilla.org/en/window.clearInterval). To use this, you will have to get the intervalId that is returned by the setInterval function, so that you can then use it to clear the interval.

    Here’s an example of how to use the clearInterval function: https://developer.mozilla.org/en/DOM/window.setInterval#Example

    Let me know if that helps :)

  10. Josh on February 18th, 2010

    I’m implementing this on a site my company is creating. Generally speaking, it works great – however, it doesn’t scale to different zoom-levels in Chrome. Anyone have any idea why this would be, or a fix to stop it?

  11. Jesus on March 4th, 2010

    Hi,

    Great script, however I’m getting a behaviour similar to the one mentioned above for FF, but in my case with IE7, for some reason very often it won’t load the second and third images of a total of three, It always loads the first one without problem. I’ve I forze the reload of the page, usually all images come through. In Chrome works fine all the time with all images. Any idea why this may be happening?

    Thanks

    Jesús

Leave a Reply




  • About

    I'm a 22 years old web developer from Buenos Aires, Argentina. I am currently not available for freelance work, but feel free to get in touch with me, below are some ways to do it.

  • Contact me

    • e-mail:
    • skype: lucianopanaro
    • messenger: