Skip to content

Instantly share code, notes, and snippets.

@dongyuwei
Created June 26, 2013 04:03
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save dongyuwei/5864686 to your computer and use it in GitHub Desktop.
Save dongyuwei/5864686 to your computer and use it in GitHub Desktop.
infinite loop carousel(vertical or horizontal)
/**
* infinite loop carousel
* @author newdongyuwei@gmail.com
* @param {Object} config
* @return {Object} this
*/
$.fn.infiniteCarousel = function(config){
config = $.extend({
itemsPerMove : 2,
duration : 1000,
vertical : false
},config);
var viewportEl = this.find('.viewport'), listEl = viewportEl.find('.list');
var first = listEl.children(":first"), last = listEl.children(":last");
var distance, prevProp, nextProp;
if(config.vertical){
distance = Math.max(first.outerHeight(true),last.outerHeight(true)) * config.itemsPerMove;
prevProp = { 'scrollTop' : "-=" + distance };
nextProp = { 'scrollTop' : distance };
}else{
distance = Math.max(first.outerWidth(true),last.outerWidth(true)) * config.itemsPerMove;
prevProp = { 'scrollLeft' : "-=" + distance };
nextProp = { 'scrollLeft' : '+=' + distance };
}
function move(config) {
if (config.dir === 'next') {
viewportEl.stop().animate(nextProp,{
duration : config.duration,
complete : function() {
config.vertical ? viewportEl.scrollTop(0) : viewportEl.scrollLeft(0);
repeatRun(function(){
listEl.children(":last").after(listEl.children(":first"));
},config.itemsPerMove);
}
});
}
if (config.dir === 'pre') {
for(var i = 0; i < config.itemsPerMove; i++){
listEl.prepend(listEl.children(":last"));
}
viewportEl[config.vertical ? 'scrollTop' : 'scrollLeft'](distance)
.stop().animate(prevProp, {
duration : config.duration
});
}
}
function repeatRun(func,times){
for(var i = 0; i < times; i++){
func();
}
}
this.find('.pre').click(function() {
move($.extend(config,{
dir: "pre"
}));
});
this.find('.next').click(function() {
move($.extend(config,{
dir: "next"
}));
});
return this;
};
@YayaBln
Copy link

YayaBln commented Aug 21, 2015

Hi,
Thanks for this super & clear code. I was just wondering if it's possible to stop the infinite loop? If yes, what's your recommandation?

Regards,

Yannick

@kanchansingh1123
Copy link

Thanks a ton!

@PrabhuKathiresan
Copy link

PrabhuKathiresan commented Feb 16, 2017

hi @YayaBln

I just modified the above code to stop infinte loop , please refer the code below,

/**
 * infinite loop carousel
 * @author newdongyuwei@gmail.com
 * @param  {Object} config 
 * @return {Object} this
 */
$.fn.infiniteCarousel = function (config) {
    config = $.extend({
        itemsPerMove: 2,
        duration: 1000,
        vertical: false
    }, config);
    var isLast = false,
        isFirst = true;
    var divElement = this;
    var viewportEl = this.find('.viewport'),
        listEl = viewportEl.find('.list');
    var first = listEl.children(":first"),
        last = listEl.children(":last"),
        lastButOne = listEl.children(":nth-last-child(2)");
    disablePrevious(divElement);
    var distance, prevProp, nextProp;
    if (config.vertical) {
        distance = Math.max(first.outerHeight(true), last.outerHeight(true)) * config.itemsPerMove;
        prevProp = {
            'scrollTop': "-=" + distance
        };
        nextProp = {
            'scrollTop': distance
        };
    } else {
        distance = Math.max(first.outerWidth(true), last.outerWidth(true)) * config.itemsPerMove;
        prevProp = {
            'scrollLeft': "-=" + distance
        };
        nextProp = {
            'scrollLeft': '+=' + distance
        };
    }

    function move(config) {
        if (config.dir === 'next') {
            viewportEl.stop().animate(nextProp, {
                duration: config.duration,
                complete: function () {
                    config.vertical ? viewportEl.scrollTop(0) : viewportEl.scrollLeft(0);
                    repeatRun(function () {
                        var lastEle = listEl.children(":last");
                        var firstEle = listEl.children(":first");
                        if (!isLast) {
                            lastEle.after(firstEle);
                            var afterChangeFirstEle = listEl.children(":first");
                            if (afterChangeFirstEle[0] == lastButOne[0]) {
                                isLast = true;
                                disableNext(divElement);
                                enablePrevious(divElement);
                            } else {
                                isFirst = false;
                                enableNext(divElement);
                                enablePrevious(divElement);
                            }
                        }
                    }, config.itemsPerMove);
                }
            });
        }

        if (config.dir === 'pre') {
            for (var i = 0; i < config.itemsPerMove; i++) {
                var lastEle = listEl.children(":last");
                if (!isFirst) {
                    listEl.prepend(listEl.children(":last"));
                    var afterChangelastEle = listEl.children(":last")
                    if (afterChangelastEle[0] == last[0]) {
                        isFirst = true;
                        enableNext(divElement);
                        disablePrevious(divElement);
                    } else {
                        isLast = false;
                        enableNext(divElement);
                        enablePrevious(divElement);
                    }
                }
            }
            viewportEl[config.vertical ? 'scrollTop' : 'scrollLeft'](distance)
                .stop().animate(prevProp, {
                    duration: config.duration
                });
        }
    }

    function repeatRun(func, times) {
        for (var i = 0; i < times; i++) {
            func();
        }
    }

    function disablePrevious(ele) {
        var previousBtn = ele.find('.pre');
        previousBtn.prop('disabled', true);
    };

    function enablePrevious(ele) {
        ele.find('.pre').prop('disabled', false);
    };

    function disableNext(ele) {
        ele.find('.next').prop('disabled', true);
    };

    function enableNext(ele) {
        ele.find('.next').prop('disabled', false);
    };

    this.find('.pre').click(function () {
        move($.extend(config, {
            dir: "pre"
        }));
    });

    this.find('.next').click(function () {
        move($.extend(config, {
            dir: "next"
        }));
    });

    return this;
};

@emilyloumiller
Copy link

Hi, thanks for this! How would I enable scrolling vertically? .viewport and .infinite-carousel are not responding to overflow-y:scroll.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment