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; } });
Creating a news carousel with jQuery
Last week I had to do a news carousel for a project I’m developing. It had been a while since I had the chance to do something interesting with jQuery, so I wanted to share the experience of how easily you can build similar widgets for your site.
So first let’s take a look at what we want to build.
Now, I know that there are a few plugins out there for jQuery that probably can do this, but the point of this post is to show how simple it is to create something like this with a few lines of jQuery and CSS.
Let’s begin by defining how we will organize the content. Being a list of news, we can either use an ordered or an unordered list.
1 2 3 4 5 6 7 8 9 | <div id="news_carousel"> <ul class="news"> <li> <img src="" alt="" /> <strong><a href="#">Title</a></strong> <span>Description</span> </li> </ul> </div> |
Now that we have our content, we have to style it. The keys here are to:
- Align the list elements one next to the other.
- Make #news_carousel just show one list element at a time
- Use relative and absolute positioning to show the titles and descriptions over each image
Here’s the CSS used in the sample with some comments:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #news_carousel { width: 444px; height: 333px; margin: 0; padding: 0; overflow: hidden; /* this will make only show 1 li */ position: relative; } #news_carousel ul.news { list-style-type: none; margin: 0; padding: 0; position: relative; } #news_carousel ul li { margin: 0; padding: 0; position: relative; /* so that we can do absolute positioning of the paragraph inside of it */ float: left; /* align one next to the other */ } #news_carousel ul.news li p { position: absolute; bottom: 10px; left: 0; margin: 5px; } #news_carousel ul.news li p strong { display: block; padding: 5px; margin: 0; font-size: 20px; background: #444; } #news_carousel ul.news li p span { padding: 2px 5px; color: #000; background: #fff; } #news_carousel ul.controls { position: absolute; top: 0px; right: 20px; list-style-type: none; } #news_carousel ul.controls li a { float: left; font-size: 15px; margin: 5px; padding: 2px 7px; background: #000; text-decoration: none; outline: none; } #news_carousel ul.controls li a.active { border: 2px solid #ccc; } |
The Javascript code is pretty self-explanatory:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | var news_carousel = function() { var items_size = $('#news_carousel ul li').length; if (items_size == 0) return; // Calculate the total width and set that value to the ul.news width // Store each item width var width = 0; var widths = []; $('#news_carousel ul.news li img').each(function(i, e) { widths[i] = $(e).width(); width += widths[i]; }); $("#news_carousel ul.news").width(width); // Append the controls controls = '<ul class="controls"><li><a class="active" href="#">1</a>'; for ( var i = 2; i <= items_size; i++) { controls += '</li><li><a href="#">' + i + '</a></li>'; } controls += '</ul>'; $('#news_carousel').append(controls); $('#news_carousel ul.controls li a').click(function(event) { // if the ul is already moving, then do nothing if ($("#news_carousel ul.news:animated").length > 0) return false; var clicked_item = $(event.target); var current_active = $("#news_carousel ul.controls li a.active"); var current_index = parseInt(current_active.text()); var new_index = parseInt(clicked_item.text()); var move = new_index - current_index; // get how many items it should be moved if (move != 0) { direction = (move > 0)? "-=": "+="; $('#news_carousel ul.news').animate({marginLeft: direction + widths[new_index-1] }, 300); clicked_item.addClass("active"); current_active.removeClass("active"); } return false; }); }(); |
And that’s it! Around 100 lines of code and you have your own home-made news carousel. Hope you found it useful!
(Pictures taken from: http://www.flickr.com/photos/christing/268490607/ and http://www.flickr.com/photos/11717181@N02/1170861540/.)