FlickrScrollr Explained: jQuery

Understanding the jQuery in FlickrScrollr

A More In-Depth Exploration of FlickrScrollr

This is a continuation of the FlickrScrollr explanation. In this post we'll explore the jQuery plugin behind the animation of the thumbnails.

Why jQuery?

I resisted the switch to jQuery for a long time, telling myself that using a JavaScript framework was some kind of copout—I was going to write my JavaScript from scratch, dammit! And, for a long time, I did exactly that. However, JavaScript is a finicky language, and it's supported differently on each browser. Testing was cumbersome, exhausting, and entirely too stressful. I felt like I was putting too much into the relationship. I lost sleep, lost my appetite, and left long, slurred messages on JavaScript's answering machine at 3AM.

"Hullo? Jahv-Scripp? I juss wann know: why you gotta make me use element.style AND element.currentStyle? You wanna know why? Iss cuz you're STUPID!"

It was at that point that I decided it was time for something new. Due to the explosion of jQuery's popularity in the design community, I decided to dive in.

Learning jQuery

Because I was already familiar with JavaScript, getting into jQuery was like learning how to crawl after walking for years. Within hours I was able to build my first site features with it, and I was cursing myself for not making the switch sooner.

Plugins in jQuery

One of the most powerful features of jQuery is the ability to quickly and easily write plugins. Plugins add an object-oriented feel to coding in JavaScript without adding much in the way of difficulty.

FlickrScrollr's jQuery Plugin

The goal of the FlickrScrollr plugin is to:

  • Add buttons to allow the user to scroll left and right
  • Resize the image wrapper div to display the appropriate number of thumbs
  • Resize the <ul> tag to accomodate all thumbs horizontally
  • Add onclick functionality to the buttons to slide the images left and right
  • Fade out the buttons if the images cannot move further in a given direction

Setting Up the Plugin

jQuery has a fairly straightforward way of setting up plugins. The format looks like this:

(function($) {
  $.fn.FlickrScrollr = function(options)
  {
    var defaults = {
      // Define default variables
    }
    var opts = $.extend(defaults, options);

    return this.each(function() {
      // Perform actions on all matched elements
    });
  };
})(jQuery);

In the first line, $.fn.FlickrScrollr, adds the "FlickrScrollr" method to the available jQuery methods. This means that the plugin can be called the same way as any other jQuery method (i.e. $('#someid').FlickrScrollr();).

Next, we set up default values for the plugin, formatted as JSON. To allow users to change default values without overwriting all defaults, we then use $.extend(defaults, options); to merge new values into the object.

Finally, we call our code using return this.each(function() { });. Because jQuery will match any number of elements depending on how it's called, we're using a loop to cycle through all matched elements. Also, notice that we're returning the whole object with the plugin, thereby maintaining the chainability of the code (one of jQuery's most powerful features).

Defining Our Defaults

For FlickrScrollr, we'll set our defaults and extend the object like so:

var defaults = {
  thumbWidth : '76',
  leftBtn : 'images/fs_leftBtn.gif',
  rightBtn : 'images/fs_rightBtn.gif',
  totalPics : '20',
  displayNum : '4'
}
var opts = $.extend(defaults, options);

Because I've already covered what these defaults are and what they mean in the overview of FlickrScrollr, I'm not going to explain them here for the sake of brevity.

Adding the Buttons

With our defaults set and user options merged into the object, we're ready to start processing the FlickrScrollr markup. To start, we'll add the left and right buttons:

return this.each(function() {
  $(this)
    .prepend('<img src="'+opts.leftBtn+'" id="fs_leftBtn" />')
    .append('<img src="'+opts.rightBtn+'" id="fs_rightBtn" />');
});

Does that seem too easy? That was my reaction, too.

Resize the Wrapper and Slider Elements

To make sure that the number of photos we want displayed actually show, and that all images are lined up horizontally, we have to do some size checking here:

return this.each(function() {
  $(this)
    .prepend('<img src="'+opts.leftBtn+'" id="fs_leftBtn" />')
    .append('<img src="'+opts.rightBtn+'" id="fs_rightBtn" />')
    .children('#fs_wrapper')
      .animate({
        'width' : opts.displayNum*opts.thumbWidth+1+'px'
      })
      .children('ul')
        .css('width', opts.totalPics+opts.thumbWidth+1+'px');
});

First, we grab the wrapper div ("fs_wrapper") using the children() method and set its width. The math we use to determine the width is to multiply the number of thumbnails we want to display by the width of each thumbnail, plus one pixel to accomodate the right border. To avoid looking choppy, we'll set this width using the incredibly handy animate() method.

To set the width of the slider (the <ul> tag), again using the children() method, this time using the total number of photos times the width of the thumbnails, plus one pixel for the right border.

We now have our wrapper <div> (set to overflow: hidden;) and our slider <ul> sized in such a way that the slider can move left or right to show off our images.

Adding Button Functionality

The whole idea behind this plugin is to animate our Flickr photo thumbnail display. Now that we've got buttons and a properly sized wrapper and slider, let's add the animation!

return this.each(function() {
  $(this)
    .prepend('<img src="'+opts.leftBtn+'" id="fs_leftBtn" />')
    .append('<img src="'+opts.rightBtn+'" id="fs_rightBtn" />')
    .children('#fs_wrapper')
      .animate({
        'width' : opts.displayNum*opts.thumbWidth+1+'px'
      })
      .children('ul')
        .css('width', opts.totalPics+opts.thumbWidth+1+'px');

  $('#fs_leftBtn').css('opacity', '0').click(function(){
    var oldLeft = parseInt($('#fs_wrapper ul').css('left'));
    var newLeft = oldLeft + opts.thumbWidth*opts.displayNum;
    if(newLeft <= 0) {
      $('#fs_wrapper ul').animate({'left' : newLeft+'px'});
      if(newLeft == 0) {
        $('#fs_leftBtn').animate({'opacity' : '0'});
        $('#fs_rightBtn').animate({'opacity' : '1'});
      } else {
        $('#fs_leftBtn').animate({'opacity' : '1'});
        $('#fs_rightBtn').animate({'opacity' : '1'});
      }
    }
  });
});

The Left Button

First, we'll focus on the left button. Since our slider starts as far left as it can go (left: 0;), we actually want to hide the left button to start, which we accomplish by setting its opacity to "0" before doing anything else.

Next, we want to tell the button what to do when a user clicks on it. Using the click() method, we create a series of actions to be executed on the click event. To start, we need to determine first, where the slider is (stored in oldLeft), and second, where it's going (stored in newLeft).

To get the value of oldLeft, we simply check its left position, using parseInt() to grab just the integer value returned (there's a "px" at the end of the returned value that would result in a "NaN" error if not removed).

Determining where the slider should go is based on the options set by the plugin. It's determined by adding the value of oldLeft to the product of how many thumbnails should be displayed (opts.displayNum) and how wide each thumbnail is (opts.thumbWidth).

With our values determined, we check to make sure that the destination is within the bounds of our slider (meaning that our images won't scroll out of view). If so, we use animate() to move the slider to the left.

Next we need to check and see if we've reached our boundary, which, on the left side, is 0px. If so, we'll fade out the button. Notice that we set the opacity of the right button to "1" in both instances, which is to make sure the button comes back into view as the slider moves left. If the boundary hasn't been reached, we just keep both buttons visible.

The Right Button

The right button is set up almost identically to the left one, with a couple minor differences:

return this.each(function() {
  $(this)
    .prepend('<img src="'+opts.leftBtn+'" id="fs_leftBtn" />')
    .append('<img src="'+opts.rightBtn+'" id="fs_rightBtn" />')
    .children('#fs_wrapper')
      .animate({
        'width' : opts.displayNum*opts.thumbWidth+1+'px'
      })
      .children('ul')
        .css('width', opts.totalPics+opts.thumbWidth+1+'px');

  $('#fs_leftBtn').css('opacity', '0').click(function(){
    var oldLeft = parseInt($('#fs_wrapper ul').css('left'));
    var newLeft = oldLeft + opts.thumbWidth*opts.displayNum;
    if(newLeft <= 0) {
      $('#fs_wrapper ul').animate({'left' : newLeft+'px'});
      if(newLeft == 0) {
        $('#fs_leftBtn').animate({'opacity' : '0'});
        $('#fs_rightBtn').animate({'opacity' : '1'});
      } else {
        $('#fs_leftBtn').animate({'opacity' : '1'});
        $('#fs_rightBtn').animate({'opacity' : '1'});
      }
    }
  });

  $('#fs_rightBtn').css('left',opts.displayNum*opts.thumbWidth+25+'px').click(function(){
    var oldLeft = parseInt($('#fs_wrapper ul').css('left'));
    var newLeft = oldLeft - opts.thumbWidth*opts.displayNum;
    var minLeft = (opts.totalPics-opts.displayNum)*opts.thumbWidth*-1;
    if(newLeft >= minLeft) {
      $('#fs_wrapper ul').animate({'left' : newLeft+'px'});
      if(newLeft == minLeft) {
        $('#fs_rightBtn').animate({'opacity' : '0'});
        $('#fs_leftBtn').animate({'opacity' : '1'});
      } else {
        $('#fs_rightBtn').animate({'opacity' : '1'});
        $('#fs_leftBtn').animate({'opacity' : '1'});
      }
    }
  });
});

The main difference to note is the use of a new variable, minLeft. To get the value of this variable, we take the total width of the slider and subtract the width of our display (the number of thumbnails we're displaying). We then use minLeft as the right-most boundary for our slider, which determines whether or not we animate the slider and also whether the button should be hidden.

Conclusion

Moving forward, I'm going to experiment with more jQuery, and I'll be sure to post what I come up with. Is there anything you'd like to see me learn and share? I'm always interested in new projects, and I'd love to share the findings with you!

Posted Mar 01, 2009 by Jason Lengstorf.
This entry is filed under plugin, jQuery, and FlickrScrollr.

Want more content like this? Subscribe for FREE!

Comments for This Entry

There are no comments on this entry yet.

Post a Comment

Want to show your face? Get a gravatar!

ALLOWED TAGS: <tt><strong><em>