Rotating Banner Images with Views and jQuery

Rotating banner images is a simple way to spice up most sites. It adds something shiny that can hook people in. If you use jQuery, like I often do, then a simple way to do the rotating banner images is using the jQuery cycle plugin. This plugin can even be used along with drupals views module to create dynamic lists of rotating images.

But, there are some downfalls with this approach. For example, if you create a list of images for the jQuery cycle plugin to rotate through you need to set all but one of them not to display with css. Even though most of the images are not initially displaying they are still downloaded in many browsers. If you have a bunch of images loading that have any size this has a potential to waste a lot of bandwidth if those images aren't viewed.

This was a problem that I ran into working on a few sites. Here's a solution I use that solves this problem while working well with Views, jQuery, and any content Views can create.

Note: This explanation applies to drupal 5.

The Views

The first thing I do is create 2 views. One that contains only one image, to be used for the initial display, and a second that loads all of the images to rotate through. The view that loads only one image gets embedded into a template file, like my page-front.tpl.php file.

The second view I'll setup to return as an array in JavaScript. The return method to use in this example is "return drupal_to_js($items);", but that's not the only way that will work.

In both cases I'll use template files that are called from custom theme functions that are called by template.php. The Views Theme Wizard modules, that comes with views, can help you create those functions. In the theme file for the single image I'll put in something like:

<div id="some-unique-id">
<!-- Insert my content here -->
</div>

While the template file for the view containing the content to rotate through would look like:

<!-- Insert my content here -->

In both cases the "Insert my content here" should be the same.

Note: If you are a theming ninja you can accomplish this with just one view and one template file.

The JavaScript

Here is a bit of JavaScript containing an example of an external file that does the heavy lifting. You'll notice that it contains a jQuery preloader function that I've previously written about. The different parts of the javascript file are explained with comments.

// Create the namespace for the functions to work out of.
Drupal.themename = {};

// The function that gets called to do the replacement
Drupal.themename.replaceimage = function () {
 
  // Replace the content inside #some-unique-id
  $('#some-unique-id').html(themename_rotating_images[themename_rotating_pointer]);;
 
  // Increase the pointer
  themename_rotating_pointer++;

  // Reset the pointer and turn off image preloading.
  // Note the number 10. This needs to be set the total number of items
  // in your view minus 1. This can be stored in a setting and passed in.
  if (themename_rotating_pointer == 10) {
    themename_rotating_pointer = 0;
    themename_rotating_switch = 0;
  }
 
  // Preload the content item after the next one. I load 2 ahead to
  // give the preloading more time for bigger files
  if (themename_rotating_switch == 1) {
    $.preloaddivs(themename_rotating_images[themename_rotating_pointer + 1]);
  }
}

// This is a content preloader function.
jQuery.preloaddivs = function(){
  for(var i = 0; i<arguments.length; i++)
  {
    jQuery("<div>").html(arguments[i]);
  }
}

$(document).ready(function() {
  // Preload the first 2 pieces of content.
  jQuery.preloaddivs(themename_rotating_images[themename_rotating_pointer], themename_rotating_images[themename_rotating_pointer + 1]);
 
  // Setup the content replacer to run every 7 seconds. This number can
  // be changed and even setup via a setting.
  setInterval("Drupal.themename.replaceimage()", 7000);
});

This is just a basic example of how to do this. On sites I build, like MuddyRivermedia.org, I've put in fade in and fade out effects. All of the hard set variables in this example can be passed in with settings and variables so they can be made entirely dynamic and this can be made to be more flexible. I've hard coded them for simplicity.

The Theme

The final step is to include all of this stuff into the theme so that it all comes together. The views theming functions should already be included in the template.php file so I won't include them here. Here are the other things to put in the template.php file:

<?php
function _phptemplate_variables($hook, $variables = array()) {
 
 
// Add out stuff to the page
 
if ($hook == 'page') {
   
   
// This logic will do our work on just the site homepage.
    // This logic can be changed to occur on other pages
   
if (request_uri() == '/' || request_uri() == '/'. variable_get('site_frontpage', NULL)) {
     
// Load the scripts.js file described above.
     
drupal_add_js(path_to_theme() .'/scripts.js', 'theme');

     
// Load the variable with the rotating images. Notice the
      // str_replace and substr functions used to remove the wrapper
      // divs placed in by views. Change the class names to the ones
      // from your view.
     
drupal_add_js('var themename_rotating_images = '. substr(str_replace("<div class='view view-my-example'><div class='view-content view-content-my-example'>", '', theme('view', 'home_image_random', 10, FALSE, 'block')), 0, -13) .';', 'inline');
     
drupal_add_js("var themename_rotating_pointer = 0;", 'inline');
     
drupal_add_js("var themename_rotating_switch = 1;", 'inline');
    }
   
   
// Rebuild the phptemplate page variable $scripts with new content
   
$variables['scripts'] = drupal_get_js();
  }
}
?>

This example shows the basic idea for using Views, image preloading, and jQuery to create a dynamic content rotation on a site with drupal.

There is a bit of room for optimization and quite a bit of flexibility and eye candy (like fading and other animations) that can be built in and on top of what is included here.

Agaric did this with Innerfade and made a wrapper module

Nice how-to! Agaric cheated when we did this and used the InnerFade JQuery plugin, and even made a wrapper module around it, but we can't figure out what the license is.

http://medienfreunde.com/deutsch/weblog/aus_der_praxis.html?nid=162

If we can GPL it we'll put the module up on Drupal.org (and make a user interface for it...)

benjamin

benjamin, Agaric Design Collective

Thanks for posting this

Hi Matt - thanks for posting this; I will now do my best to wrap my head around it!

FYI I understand that the Jcycle plugin (latest version) now allows you to add additional images to a slideshow after it has started so this means that you could start off with only (say) one or two images, and then add additional images (even in several stages)...

Easier Way

I have been searching for a freeware method of making a nice rotating banner (or slideshow, etc.) to put on the front page of a site, I have searched the drupal repository and couldn't find a nice means of implementing this into drupal (no module); do you guys know of a better way of doing this than hard-coding it in; in my opinion less hackery the better (leaves room for dynamic pages to breathe).

Banner Rotor Module

There is a Banner Rotor Module.

In some cases something like this will work. In other cases you might want to craft your own solution.

Rotating banner using nothing but jQuery

Hey,

Just a quick comment.
It's also possible to just use jQuery (native and timer plugin) either for changing text or images.

Check this solution:
http://blog.maaloe.com/2008/08/creating-jquery-banner-with-timer-and.htm...

It maintains a list of texts that the banner will select from. There's also an example if you want to add a random generator or place the texts vertically in the banner.

Views Slideshow

I would look into the views slideshow module as well. http://drupal.org/node/264145. Check out that link for a short description/how-to.

Views Rotator

Thanks for the heads up about Views Slideshow. Since I wrote this post I created the Views Rotator module which can do what I'm talking about here fairly well.