$(function(){ $.extend($.easing, { def: 'easeInSine', easeInSine: function (x, t, b, c, d) { return -c * Math.cos(t/d * (Math.PI/2)) + c + b; }, easeInOutBack: function (x, t, b, c, d, s) { if (s == undefined) s = 1.70158; if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; } }); var $slider = $('.slider') , slider_width = 0 , $slider_inner = $slider.children().first() , $elements = $slider_inner.children('.element') , elements_count = $elements.length , element_width = $elements.first().width() , element_margin = 0 , elements_fit = 0 , visible_width = 0 , vertical_max = 30 // max vertical deviation function onResize() { slider_width = $slider.width() elements_fit = Math.floor(slider_width/element_width) // we have a limited number of elements if (elements_fit > elements_count) { elements_fit = elements_count } // we need only odd number if (elements_fit % 2 === 0) { elements_fit -= 1 } // find element margin for balancing element_margin = Math.ceil((slider_width - (element_width * elements_fit))/(elements_fit * 2)) // set container width * 1.5 to fit clonned elements when scroll visible_width = (element_width + element_margin * 2) * elements_fit $slider_inner.width(Math.ceil(visible_width * 1.5)) // add margins $elements.css({'margin-left': element_margin + 'px', 'margin-right': element_margin + 'px'}) // set active element $elements.removeClass('active') $elements.slice(Math.floor(elements_fit/2), Math.floor(elements_fit/2) + 1).addClass('active') } function goTo(index_to) { var index_past = Math.floor(elements_fit/2) // if active element if (index_to === index_past) { return } var index_diff = index_to - index_past , $elements_slice , left_to = 0 , i , visible_center = Math.floor((visible_width - element_width - element_margin * 2)/2) , margin_top = 0 if (index_diff > 0) { $elements_slice = $elements.slice(0, index_diff) // append diff elements $elements_slice.clone().appendTo($slider_inner) // compute left offset left_to = -((element_width + element_margin * 2) * index_diff) } else { $elements_slice = $elements.slice(index_diff) // append diff elements $elements_slice.clone().prependTo($slider_inner) // set left offset $slider_inner.css('left', (element_width + element_margin * 2) * index_diff + 'px') } // reindex elements $elements = $slider_inner.children('.element') setTimeout(function(){ $slider_inner.addClass('transition').css('left', left_to + 'px') setTimeout(function(){ $slider_inner.removeClass('transition') // remove duplicates $elements_slice.remove() // reposition slider $slider_inner.css('left', 0) // reindex elements $elements = $slider_inner.children('.element') // set active element $elements.removeClass('active') $elements.slice(Math.floor(elements_fit/2), Math.floor(elements_fit/2) + 1).addClass('active') }, 1000) }, 1) } onResize() goTo(0) // move it to align vertically $(window).on('resize', onResize) $slider .on('click', 'a.slider-control', function(ev){ ev.preventDefault() var direction = $(this).hasClass('left') ? -1 : 1 goTo(Math.floor(elements_fit/2) + direction) }) .on('click', '.element', function(ev){ ev.preventDefault() goTo($elements.index(this)) }) })