Current File : /var/www/html/js/vtp-vm-carousel.js |
/* ========================================================================= *\
vmcarousel plugin by Vedmant
\* ========================================================================= */
(function ($, window, document, undefined) {
"use strict";
var pluginName = 'vmcarousel';
/**
* Defaults
*
* @type {}
*/
var defaults = {
delay: 4000,
speed: 500,
autoplay: true,
items_to_show: 0, // 0 for auto calc
min_items_to_show: 2,
items_to_slide: 1,
dont_cut: true,
centered: false,
start_item: 0,
start_item_centered: false,
infinite: false,
changed_slide: $.noop()
};
/**
* Plugin constructor
*
* @param element
* @param options
* @constructor
*/
function Plugin(element, options)
{
this._name = pluginName;
this.element = element;
this.$element = $(element);
var data_options = parse_data_options(this.$element.data('options'));
this.options = $.extend({}, defaults, options);
this.options = $.extend({}, this.options, data_options);
this.init();
}
/**
* Parse data-options attribute options
*
* @param data_options_raw
* @returns {Array}
*/
function parse_data_options(data_options_raw)
{
if(data_options_raw === undefined) return [];
var options = [];
data_options_raw.split(';').forEach(function(el){
var pair = el.split(':');
if(pair.length == 2) options[pair[0].trim()] = pair[1].trim();
});
return options;
}
/**
* Plugin functions
*/
Plugin.prototype = {
/**
* Plugin init
*/
init: function ()
{
var that = this;
// Add class
this.$element.addClass('vmcarousel');
// Wrap
this.$viewport = this.$element.wrap('<div class="vmc-viewport"></div>').parent();
this.$container = this.$viewport.wrap('<div class="vmc-container"></div>').parent();
// Some initial procedures with slides
this.init_slides();
// Items vars
this.$orig_items = this.$element.find('>li');
this.$items = this.$orig_items;
this.orig_items_count = this.$orig_items.length;
this.items_count = this.$items.length;
this.orig_item_width = this.$items.outerWidth(true);
this.item_width = this.orig_item_width;
// Other vars
this.current_position = 0;
// Init functions
this.calc_variables();
this.init_infinite(this.options.start_item);
this.init_controls();
this.update_state();
// Reorder slides to make start item at the center
if(this.options.start_item_centered)
this.reorder_to_center(this.options.start_item);
// Initial set slide
if( ! this.options.infinite)
this.set_slide(this.options.start_item);
else
this.set_active_infinite(this.options.start_item);
// Start timer
if (this.options.autoplay) this.start_timer();
// Window resize event
$(window).resize(function () { that.resize() });
},
/**
* Calculate all needed variables
*/
calc_variables: function()
{
this.viewport_width = this.$viewport.width();
// Calc items to show
this.items_to_show = this.options.items_to_show;
if( ! this.options.items_to_show || (this.orig_item_width * this.items_to_show) > this.viewport_width) {
this.items_to_show = Math.floor(this.viewport_width / this.orig_item_width);
}
// Set odd number for centered type for not to cut items
if(this.options.centered && this.options.dont_cut) {
this.items_to_show = this.items_to_show % 2 ? this.items_to_show : this.items_to_show - 1;
}
// Min items to show
if(this.items_to_show < this.options.min_items_to_show) this.items_to_show = this.options.min_items_to_show;
// Calc item width for centered or dont_cut
if(this.options.centered || this.options.dont_cut) {
this.item_width = Math.floor(this.viewport_width / this.items_to_show);
if(this.item_width < this.orig_item_width) this.item_width = this.orig_item_width;
this.$items.width(this.item_width);
this.full_items_width = this.item_width * this.items_count;
this.$element.css({width: this.full_items_width + 'px'});
}
// Calc items to slide
this.items_to_slide = this.options.items_to_slide;
if( ! this.options.items_to_slide)
this.items_to_slide = Math.floor(this.viewport_width / this.item_width);
if(this.items_to_slide > this.items_to_show) this.items_to_slide = this.items_to_show;
if(this.items_to_slide <= 0) this.items_to_slide = 1;
this.hide_controls = this.items_count <= this.items_to_show;
this.infinite_initial_margin = - this.item_width;
if(this.items_to_show % 2 == 0) this.infinite_initial_margin += this.item_width / 2;
},
/**
* Update carousel state (clases, so on)
*/
update_state: function()
{
this.$element.css({transition: 'transform ' + this.options.speed / 1000 + 's'});
if(this.hide_controls) this.$container.addClass('hide-controls');
else this.$container.removeClass('hide-controls');
},
/**
* Set slides properties
*/
init_slides: function()
{
this.$element.find('>li').each(function(i){
$(this).attr('data-slide', i);
});
},
/**
* Init controls
*/
init_controls: function()
{
var that = this;
// Controls
this.$btn_left = this.$container.append('<a href="" class="vmc-arrow-left"></a>').find('.vmc-arrow-left');
this.$btn_right = this.$container.append('<a href="" class="vmc-arrow-right"></a>').find('.vmc-arrow-right');
// Bind controls
this.$btn_left.click(function (e) {
e.preventDefault();
that.slide_relative(-1);
});
this.$btn_right.click(function (e) {
e.preventDefault();
that.slide_relative(1);
});
},
/**
* Reorder slider to place item at the center
*
* @param position
*/
reorder_to_center: function(position)
{
// Dont reorder if 2 or less items
if(this.orig_items_count < 3) return;
// Calc shift times and direction
var shift_count = Math.floor(this.orig_items_count / 2) - position;
var dir = shift_count > 0 ? -1 : 1;
// Shift items
shift_count = Math.abs(shift_count);
for(var i = 0; i < shift_count; i++) this.switch_slides(dir);
},
/**
* Move to exact slide
*
* @param slide
*/
set_slide: function(slide)
{
var position = this.$element.find('>[data-slide="'+slide+'"]').index();
this.slide_relative(position);
},
/**
* Slide n items forth or back
*
* @param offset
*/
slide_relative: function (offset)
{
if(this.options.centered && this.options.infinite)
this.slide_relative_centered_infinite(offset);
else if(this.options.centered)
this.slide_relative_centered(offset);
else
this.slide_relative_left(offset);
},
/**
* Slide n items forth or back for left mode
*
* @param offset
*/
slide_relative_left: function (offset)
{
var new_position = this.current_position + (offset * this.items_to_slide);
// If now is ribbon tail on go back reverse to slide_count step
if (this.current_position == this.items_count && offset < 0) {
new_position = (Math.floor(this.items_count / this.items_to_slide) + offset) * this.items_to_slide;
// Show ribbon tail (last slide to right border)
} else if (new_position < 0 || (this.items_to_slide > (this.items_count - new_position) && new_position < this.items_count)) {
new_position = this.items_count - this.items_to_show;
// Scroll to beggining
} else if (new_position > (this.items_count - this.items_to_show)) {
new_position = 0;
}
var margin_left = - this.item_width * new_position;
// Animate slide
this.animate_slide(margin_left);
this.change_slide(new_position, new_position);
},
/**
* Slide n items forth or back for centered mode
*
* @param offset
*/
slide_relative_centered: function (offset)
{
var new_position = this.current_position + (offset * this.items_to_slide);
if (new_position < 0) {
new_position = this.items_count - 1;
// Scroll to beggining
} else if (new_position >= this.items_count) {
new_position = 0;
}
var margin_left = this.viewport_width / 2 - (this.item_width * (new_position + 1) - this.item_width / 2);
// Animate slide
this.animate_slide(margin_left);
var new_active_slide = this.$items.eq(new_position).attr('data-slide');
this.change_slide(new_position, new_active_slide);
},
/**
* Init infinite carousel feature
*/
init_infinite: function (start_item)
{
if( ! this.options.infinite) return;
this.make_clones();
this.calc_variables();
this.$element.css("margin-left", this.infinite_initial_margin + "px");
},
/**
* Make clones for infinite carousel
*/
make_clones: function ()
{
var times = 1;
if(this.items_count < this.items_to_show)
times = Math.ceil(this.items_to_show / this.items_count);
for(var i = 0; i < times; i++) {
this.$element.prepend(this.$orig_items.clone().addClass('vmc-clone'));
}
this.$items = this.$element.find('>li');
this.items_count = this.$items.length;
},
/**
* Slide n items forth or back for centered mode with infinite mode
*
* @param offset
*/
slide_relative_centered_infinite: function (offset)
{
var that = this;
// Only one item to slide
offset = offset < 0 ? -1 : 1;
var margin_left = this.infinite_initial_margin - this.item_width * offset;
//if(this.items_to_show % 2 == 0) margin_left += this.item_width / 2;
var new_position = Math.ceil(this.items_to_show / 2) + offset;
var new_active_slide = this.$items.eq(new_position).attr('data-slide');
this.animate_slide(margin_left, function(e){
that.switch_slides(offset);
that.$element.css("margin-left", that.infinite_initial_margin + "px");
}, 'margin');
this.change_slide(new_position, new_active_slide);
},
/**
* Place first slide at the end or last slide before first
*
* @param dir
*/
switch_slides: function(dir)
{
var that = this;
// Switch last or first item
if(dir > 0) {
that.$items.last().after(that.$items.first());
} else {
that.$items.first().before(that.$items.last());
}
// Reload elements
that.$items = that.$element.find('>li');
},
/**
* Set first active slide for infinite carousel
*
*/
set_active_infinite: function(position)
{
var center_position = Math.ceil(this.items_to_show / 2);
for(var i = 0; i < this.orig_items_count; i++) {
this.switch_slides(1);
if(this.$items.eq(center_position).attr('data-slide') == position) {
this.$items.eq(center_position).addClass('vmc_active');
return true;
}
}
return false;
},
/**
* Change slide
*
* @param new_position
* @param margin_left
*/
change_slide: function (new_position, new_active_slide)
{
var that = this;
// Update current position
this.current_position = new_position;
// Add active class
this.$items.removeClass('vmc_active').eq(this.current_position).addClass('vmc_active');
// Restart timer
if (this.options.autoplay) this.start_timer();
// Call callback
if (typeof this.options.changed_slide === "function") {
this.options.changed_slide.call(this, new_active_slide);
}
},
/**
* Slide animation
*
* @param margin_left
*/
animate_slide: function (margin_left, complete, type)
{
var that = this;
if(type == undefined) type = 'css3';
if(complete == undefined) complete = $.noop();
if (Modernizr.csstransitions && type == 'css3') {
this.$element.css("transform", "translate3d(" + margin_left + "px,0px,0px)");
this.$element.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', complete);
} else {
this.$element.stop(true).animate({'margin-left': margin_left + 'px'}, this.options.speed, 'swing', complete);
}
},
/**
* Resize event
*/
resize: function ()
{
this.calc_variables();
this.update_state();
// Update slider position
this.slide_relative(0);
},
/**
* Start timer
*/
start_timer: function ()
{
var that = this;
if (this.timer_id != 0) clearTimeout(this.timer_id);
this.timer_id = setTimeout(function () {
that.slide_relative(1);
}, this.options.delay);
},
/**
* Stop timer
*/
stop_timer: function ()
{
clearTimeout(this.timer_id);
this.timer_id = 0;
}
} // Plugin.prototype
/**
* Attach to Jquery
*
* @param options
* @returns {*}
*/
$.fn[pluginName] = function (options) {
var args = [].slice.call(arguments, 1);
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName))
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
else if ($.isFunction(Plugin.prototype[options]))
$.data(this, 'plugin_' + pluginName)[options].apply($.data(this, 'plugin_' + pluginName), args);
});
}
// Auto init for tags with data-vmcarousel attribute
$('[data-vmcarousel]').vmcarousel();
})(jQuery, window, document);