Blythe Lim Blythe Lim - 28 days ago 18
jQuery Question

Circular Content Carousel remove loop

Question regarding CIRCULAR CONTENT CAROUSEL WITH JQUERY
by tympanus

I'm implementing this to a web project, so far it works perfectly but need it to stop looping / clone left right and stops scroll while it reach the last child or at the first child. Basically is to remove the infinity circular/loop effects.

I think here is the part to change to do the trick but too bad I can't understand the logic,

please help!

and sorry for bad English, I'm from Malaysia



// clone the elements on the right / left and append / prepend them according to dir and scroll
if( dir === 1 ) {
$wrapper.find('div.ca-item:lt(' + scroll + ')').each(function(i) {
$(this).clone(true).css( 'left', ( cache.totalItems - idxClicked + i ) * cache.itemW * factor + 'px' ).appendTo( $wrapper );
});
}
else {
var $first = $wrapper.children().eq(0);

$wrapper.find('div.ca-item:gt(' + ( cache.totalItems - 1 - scroll ) + ')').each(function(i) {
// insert before $first so they stay in the right order
$(this).clone(true).css( 'left', - ( scroll - i + idxClicked ) * cache.itemW * factor + 'px' ).insertBefore( $first );
});
}

// animate the left of each item
// the calculations are dependent on dir and on the cache.expanded value
$wrapper.find('div.ca-item').each(function(i) {
var $item = $(this);
$item.stop().animate({
left : ( dir === 1 ) ? '-=' + ( cache.itemW * factor * scroll ) + 'px' : '+=' + ( cache.itemW * factor * scroll ) + 'px'
}, opts.sliderSpeed, opts.sliderEasing, function() {
if( ( dir === 1 && $item.position().left < - idxClicked * cache.itemW * factor ) || ( dir === -1 && $item.position().left > ( ( cache.totalItems - 1 - idxClicked ) * cache.itemW * factor ) ) ) {
// remove the item that was cloned
$item.remove();
}
cache.isAnimating = false;
});
});

Answer

I found the plugin wasn't too hard to read, so I wrote you a custom version with the feature you've asked for. I think. If I read this write, you want all of it's features except you don't want it to be infinite. Thus I added an option in this custom version to provide just such a feature. To turn off infinite looping, simply set it to false like so:

$('#ca-container').contentcarousel({ infinite: false });

This will cause the carousel to stop on first and last frames.

See Working Demo Here

If you don't want to make the adjustments yourself, simply copy and paste the code from the demo into you JS file. Replace the old code with this update. Otherwise, the adjustment, should you decide to do it yourself, was not hard.

  1. I simply added the option within the "init" method. This method starts on line 139. I added the option to line 149.

    methods = {
        init        : function( options ) {
    
            if( this.length ) {
    
                var settings = {
                    sliderSpeed     : 500,          // speed for the sliding animation
                    sliderEasing    : 'easeOutExpo',// easing for the sliding animation
                    itemSpeed       : 500,          // speed for the item animation (open / close)
                    itemEasing      : 'easeOutExpo',// easing for the item animation (open / close)
                    scroll          : 1,            // number of items to scroll at a time
    /*ADDED OPTION! */  infinite: true  //  tells carousel wether or not to clone items and/or continue scroll past first and last
                };
    
  2. With this option added, we now go back up to line 4, the "navigate" method. Just past the first if statement (this allows all options checked in correctly, we'll need a couple of them), I added 2 more if statements that simply "return" if all true & reset the animating variable to false (this is stored in a cache variable). These if statements check the direction and position of the first and last elements.

    • The first if statement is very easy. If the dir = -1 then we know the user clicked "prev". I then check the position().left of the first item and if = to 0, then we need not proceed.

      if (dir == -1 && !opts.infinite && $wrapper.find('div.ca-item').first().position().left == 0) { 
          cache.isAnimating = false; 
          return; 
      }
      
    • The second one is a little more tricky. It needs to know when left is exactly the same as the expected animation. Thus I borrowed the calculation found on line 36 within $wrapper.find('div.ca-item').each.

      if (dir == 1 && !opts.infinite && $wrapper.find('div.ca-item').last().position().left == (cache.itemW * factor * scroll)) {  
          cache.isAnimating = false;  
          return;  
      }
      
  3. Almost Finally, make one more simple fix. Originally on line 17 (tho, if you've followed my instruction to this point it will be a few lines down), you should find an if statement that begins if( dir === 1 ) {. This is still within the "navigate" method. Here we need to add a check to ensure this if statement is not carried out if "infinite" option is false. Why? Because this is the "evil cloning" takes place that causes items to be "moved around", however this is not where old items go to be removed. There is still one more step. For now, simply wrap the old if statement as follows:

    if (opts.infinite) {
        if( dir === 1 ) {
            $wrapper.find('div.ca-item:lt(' + scroll + ')').each(function(i) {
                $(this).clone(true).css( 'left', ( cache.totalItems - idxClicked + i ) * cache.itemW * factor + 'px' ).appendTo( $wrapper );
            });
        }
        else {
            var $first  = $wrapper.children().eq(0);
    
            $wrapper.find('div.ca-item:gt(' + ( cache.totalItems  - 1 - scroll ) + ')').each(function(i) {
                // insert before $first so they stay in the right order
                $(this).clone(true).css( 'left', - ( scroll - i + idxClicked ) * cache.itemW * factor + 'px' ).insertBefore( $first );
            });
        }
    }
    
  4. FINALLY! WOOT! The last step, an if check for that evil remove. Originally on line 40, you'll find $item.remove(); within '$wrapper.find('div.ca-item').each(function(i) {' still inside the "navigate" method. Simply change this one liner to the following:

    if (opts.infinite) $item.remove();
    

VIOLA! All done! See? Not hard at all! Hope this helps!

"All things are easy ... when you don't think about them!"

Comments