/*
* jQuery BigGallery - v2.0
* http://bigemployee.com/projects/big-gallery/
*
* A responsive jQuery slider with thumbnails
* Based on
* jQuery RefineSlide plugin v0.4.1
* http://github.com/alexdunphy/refineslide
* Requires: jQuery v1.8+
* MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
;
(function($, window, document) {
'use strict';
// Baked-in settings for extension
var defaults = {
maxWidth: 960, // Max slider width - should be set to image width
maxHeight: 640, // Max slider height - should be set to image height
transition: 'fade', // String (default 'fade'): Transition type ('custom', random', 'cubeH', 'cubeV', 'fade', 'sliceH', 'sliceV', 'slideH', 'slideV', 'scale', 'blockScale', 'kaleidoscope', 'fan', 'blindH', 'blindV')
customTransitions: [],
fallback3d: 'fade', // String (default 'fade'): Fallback for browsers that support transitions, but not 3d transforms (only used if primary transition makes use of 3d-transforms)
controls: 'dots', // String (default 'dots'): Control types ('custom', 'dots', 'thumbs', 'numbers', 'bars', 'none')
fit: 'bestfit', // String (default 'bestfit'): Display fit types ('custom', 'bestfit', 'cover', 'contain', 'original', 'none')
modal: false, // Bool (default false): Modal mode
perspective: 1000, // Perspective (used for 3d transforms)
swipe: true, // Bool (default true): Navigation type thumbnails
useArrows: false, // Bool (default false): Navigation type previous and next arrows
thumbMargin: 5, // Int (default 3): Percentage width of thumb margin
thumbWidth: 150, // Int (default 150): Width of thumbnail image
autoPlay: false, // Int (default false): Auto-cycle slider
delay: 5000, // Int (default 5000) Time between slides in ms
transitionDuration: 800, // Int (default 800): Transition length in ms
startSlide: 0, // Int (default 0): First slide
keyNav: true, // Bool (default true): Use left/right arrow keys to switch slide
captionWidth: 50, // Int (default 50): Percentage of slide taken by caption
arrowTemplate: '
', // String: The markup used for arrow controls (if arrows are used). Must use classes '.be-next' & '.be-prev'
onInit: function() {
}, // Func: User-defined, fires with slider initialisation
onChange: function() {
}, // Func: User-defined, fires with transition start
afterChange: function() {
} // Func: User-defined, fires after transition end
};
// RS (RefineSlide) object constructor
function RS(elem, settings) {
this.$slider = $(elem).addClass('be-slider'); // Elem: Slider element
this.settings = $.extend({}, defaults, settings); // Obj: Merged user settings/defaults
this.$slides = this.$slider.find('> li'); // Elem Arr: Slide elements
this.totalSlides = this.$slides.length; // Int: Number of slides
this.cssTransitions = testBrowser.cssTransitions(); // Bool: Test for CSS transition support
this.cssTransforms3d = testBrowser.cssTransforms3d(); // Bool: Test for 3D transform support
this.currentPlace = this.settings.startSlide; // Int: Index of current slide (starts at 0)
this.$currentSlide = this.$slides.eq(this.currentPlace); // Elem: Starting slide
this.inProgress = false; // Bool: Prevents overlapping transitions
this.$sliderWrap = this.$slider.wrap('').parent(); // Elem: Slider wrapper div
this.$sliderBG = this.$slider.wrap('').parent(); // Elem: Slider background (useful for styling & essential for cube transitions)
this.sliderWidth = this.settings.maxWidth; // Int: Slider Width by default is the max width
this.sliderHeight = this.settings.maxHeight; // Int: Slider Height by default is the max height
this.settings.slider = this; // Make slider object accessible to client call code with 'this.slider' (there's probably a better way to do this)
this.isInit = true;
this.init();
}
RS.prototype = {
cycling: null,
$slideImages: null,
init: function() {
// User-defined function to fire on slider initialisation
this.settings.onInit();
// Setup captions
this.captions();
if (this.settings.transition === 'custom') {
this.nextAnimIndex = -1; // Set animation index for custom animation
}
if (this.settings.useArrows) {
this.setArrows(); // Setup arrow navigation
}
if (this.settings.keyNav) {
this.setKeys(); // Setup keyboard navigation
}
for (var i = 0; i < this.totalSlides; i++) { // Add slide identifying classes
this.$slides.eq(i).addClass('be-slide-' + i);
}
if (this.settings.autoPlay) {
this.setAutoPlay();
// Listen for slider mouseover
this.$slider.on({
mouseenter: $.proxy(function() {
if (this.cycling !== null) {
clearTimeout(this.cycling);
}
}, this),
mouseleave: $.proxy(this.setAutoPlay, this) // Resume slideshow
});
}
// Get the first image in each slide
this.$slideImages = this.$slides.find('img:eq(0)').addClass('be-slide-image');
this.setup();
}
, setup: function() {
var that = this;
if (this.settings.maxWidth !== '' && !this.settings.modal)
this.$sliderWrap.css('max-width', this.settings.maxWidth);
if (this.settings.maxHeight !== '' && !this.settings.modal)
this.$sliderWrap.css({'max-height': this.settings.maxHeight, 'height': this.settings.maxHeight});
if (this.settings.fit !== 'none' && this.settings.fit !== '')
this.$sliderWrap.addClass('be-' + this.settings.fit);
if (this.settings.controls !== 'none' && this.settings.controls !== 'thumbs')
this.setControls(this.settings.controls);
if (this.settings.controls === 'thumbs')
this.setThumbs();
if (this.settings.modal){
this.$thumbModalClose = $('');
this.$thumbModalClose.appendTo(this.$sliderWrap);
this.$sliderWrap.addClass('be-modal');
this.sliderWidth = this.$slider.width();
// console.log(this.sliderWidth + 'px');
}
// Display first slide
this.$currentSlide.css({'opacity': 1, 'z-index': 2});
// Load images
// Get height and width
// If full screen mode do the window ratio calc
// add the top and left offset
if (that.settings.fit === 'cover' || that.settings.fit === 'contain')
that.fit(true);
// Add swipe events
if (this.settings.swipe) {
this.$slider.on('swipeleft', function(e) {
e.preventDefault();
that.next();
}).on('swiperight', function(e) {
e.preventDefault();
that.prev();
});
}
// Window Resize Event
$(window).on('resize', function() {
if(that.settings.controls === 'thumbs')
that.update(true, true);
if(that.settings.fit === 'cover' || that.settings.fit === 'contain')
that.fit(false);
if(that.settings.modal){
that.sliderWidth = that.$slider.width();
}
});
}
, fit: function(firstRun) {
var that = this;
var sliderAspectRatio = 1;
// @todo: can enjoy a little bit of drying over here
if(!firstRun){
var resizedSliderWidth = this.$slider.width();
this.sliderHeight = (this.settings.maxHeight === '100%') ?
$(window).height() : (resizedSliderWidth * (this.sliderHeight / this.sliderWidth));
this.sliderWidth = resizedSliderWidth;
that.$slides.css({
width: this.sliderWidth,
height: this.sliderHeight
});
sliderAspectRatio = this.sliderWidth / this.sliderHeight;
// console.log('RE Slider Width: ' + that.sliderWidth);
// console.log('RE Slider Height: ' + that.sliderHeight);
// console.log('Slider Aspect Ratio: ' + sliderAspectRatio);
}
this.$slideImages.imagesLoaded()
// .done(function(instance){
// console.log('Slider Width: ' + that.$slider.width());
// console.log('Slider Height: ' + that.$slider.height());
// console.log('all images successfully loaded');
// })
.progress(function(instance, image) {
if (firstRun) {
that.sliderWidth = that.$slider.width();
that.sliderHeight = (that.settings.maxHeight === '100%') ?
$(window).height() : that.$slider.height();
that.$slides.css({
width: that.sliderWidth,
height: that.sliderHeight
});
sliderAspectRatio = that.sliderWidth / that.sliderHeight;
firstRun = false;
that.isInit = firstRun;
// console.log('Slider Width: ' + that.sliderWidth);
// console.log('Slider Height: ' + that.sliderHeight);
// console.log('Slider Aspect Ratio: ' + sliderAspectRatio);
}
// var result = image.isLoaded ? 'loaded' : 'broken';
// console.log('image is ' + result + ' for ' + image.img.src);
// Now lets find the right fit
if (that.settings.fit === 'cover' || that.settings.fit === 'contain')
that.fitImages(that.settings.fit, sliderAspectRatio, image.img, image.img.width, image.img.height);
});
}
, fitImages: function(fit, sliderAspectRatio, image, imageWidth, imageHeight) {
var imageAspectRatio = imageWidth / imageHeight;
var newWidth = this.sliderHeight * imageAspectRatio;
var newHeight = this.sliderHeight;
var marginTop = 0;
var marginLeft = 0;
if (sliderAspectRatio > imageAspectRatio) {
if (fit === 'cover') {
newWidth = this.sliderWidth;
newHeight = this.sliderWidth * (imageHeight / imageWidth);
marginTop = ((this.sliderHeight - newHeight) / 2);
this.setImageCSS(image, newWidth, newHeight, marginTop, marginLeft);
}
else {
marginLeft = ((this.sliderWidth - newWidth) / 2);
this.setImageCSS(image, newWidth, newHeight, marginTop, marginLeft);
}
}
else {
if (fit === 'cover') {
marginLeft = ((this.sliderWidth - newWidth) / 2);
this.setImageCSS(image, newWidth, newHeight, marginTop, marginLeft);
}
else {
newWidth = this.sliderWidth;
newHeight = this.sliderWidth * (imageHeight / imageWidth);
marginTop = ((this.sliderHeight - newHeight) / 2);
this.setImageCSS(image, newWidth, newHeight, marginTop, marginLeft);
}
}
// console.log("width: " + newWidth + " height: " + newHeight + " imageWidth: " + imageWidth + " imageHeight: " + imageHeight + " this.sliderHeight: " + this.sliderHeight);
}
, setImageCSS: function(image, newWidth, newHeight, marginTop, marginLeft){
$(image).css({
width: newWidth,
height: newHeight,
marginTop: marginTop,
marginLeft: marginLeft,
'max-width': 'none',
'max-height': 'none'
});
}
, setArrows: function() {
var that = this;
// Append user-defined arrow template (elems) to '.be-wrap' elem
this.$slider.after(this.settings.arrowTemplate);
// Fire next() method when clicked
$('.be-next', this.$sliderWrap).on('click', function(e) {
e.preventDefault();
that.next();
});
// Fire prev() method when clicked
$('.be-prev', this.$sliderWrap).on('click', function(e) {
e.preventDefault();
that.prev();
});
}
, setThumbArrows: function() {
var that = this;
// Append user-defined arrow template (elems) to '.be-wrap' elem
this.$thumbWrap.append(this.settings.arrowTemplate);
// Fire next() method when clicked
this.$thumbsPrev = this.$thumbWrap.find('.be-prev');
this.$thumbsNext = this.$thumbWrap.find('.be-next');
this.$thumbsNext.on('click', function(e) {
e.preventDefault();
that.nextThumbs();
});
// Fire prev() method when clicked
this.$thumbsPrev.on('click', function(e) {
e.preventDefault();
that.prevThumbs();
});
this.update(true, true);
}
, next: function() {
if (this.settings.transition === 'custom') {
this.nextAnimIndex++;
}
// If on final slide, loop back to first slide
if (this.currentPlace === this.totalSlides - 1) {
this.transition(0, true); // Call transition
} else {
this.transition(this.currentPlace + 1, true); // Call transition
}
}
, prev: function() {
if (this.settings.transition === 'custom') {
this.nextAnimIndex--;
}
// If on first slide, loop round to final slide
if (this.currentPlace === 0) {
this.transition(this.totalSlides - 1, false); // Call transition
} else {
this.transition(this.currentPlace - 1, false); // Call transition
}
}
, setKeys: function() {
var that = this;
// Bind keyboard left/right arrows to next/prev methods
$(document).on('keydown', function(e) {
if (e.keyCode === 39) { // Right arrow key
that.next();
} else if (e.keyCode === 37) { // Left arrow key
that.prev();
}
});
}
, setAutoPlay: function() {
var that = this;
// Set timeout to object property so it can be accessed/cleared externally
this.cycling = setTimeout(function() {
that.next();
}, this.settings.delay);
}
, setThumbs: function() {
var that = this;
// Wrapper to contain thumbnails
this.$thumbWrap = $('');
this.$thumbWrap.appendTo(this.$sliderWrap);
this.$thumbs = $('');
this.$thumbs.appendTo(this.$thumbWrap);
// initialize shift left
this.shiftLeft = 0;
// thumb outer width
this.thumbOuterWidth = (this.settings.thumbWidth + this.settings.thumbMargin);
// thumbs total width, not to forget last thumb has no margin
// @todo test the margins, especially with box-sizing: border-box;
this.thumbsWidth = (this.totalSlides * this.thumbOuterWidth) - this.settings.thumbMargin;
this.getThumbWrapOffset();
// this.thumbsWidth = (this.totalSlides * this.thumbOuterWidth);
// Loop to apply thumbnail widths/margins to wraps, appending an image clone to each
for (var i = 0; i < this.totalSlides; i++) {
var $thumb = $('')
.attr('href', '#')
.data('be-num', i);
this.$slideImages.eq(i).clone()
.removeAttr('style').css({
width: this.settings.thumbWidth,
marginRight: this.settings.thumbMargin
})
.appendTo(this.$thumbs)
.wrap($thumb);
}
this.$thumbs.css({width: this.thumbsWidth});
// set thumb arrows
this.setThumbArrows();
// thumbs width
this.$controlLinks = this.$thumbs.find('a');
// Safety margin to stop IE7 wrapping the thumbnails (no visual effect in other browsers)
// this.$thumbs.children().last().css('margin-right', -10);
// Add active class to starting slide's respective thumb
this.$controlLinks.eq(this.settings.startSlide).addClass('active');
// Listen for click events on thumnails
this.$thumbs.on('click', 'a', function(e) {
e.preventDefault();
that.transition(parseInt($(this).data('be-num'))); // Call transition using identifier from thumb class
});
}
, setControls: function(controlType) {
var that = this;
// Wrapper to contain thumbnails
this.$controlWrap = $('');
this.$controlWrap.appendTo(this.$sliderWrap);
// Loop to apply thumbnail widths/margins to wraps, appending an image clone to each
for (var i = 0; i < this.totalSlides; i++) {
$('')
.attr('href', '#')
.text(i + 1)
.data('be-num', i)
.appendTo(this.$controlWrap);
}
this.$controlLinks = this.$controlWrap.find('a');
// Add active class to starting slide's respective thumb
this.$controlLinks.eq(this.settings.startSlide).addClass('active');
// Listen for click events on thumnails
this.$controlWrap.on('click', 'a', function(e) {
e.preventDefault();
that.transition(parseInt($(this).data('be-num'))); // Call transition using identifier from thumb class
});
}
, captions: function() {
var that = this,
$captions = this.$slides.find('.be-caption');
// User-defined caption width
$captions.css({
width: that.settings.captionWidth + '%',
opacity: 0
});
// Display starting slide's caption
this.$currentSlide.find('.be-caption').css('opacity', 1);
$captions.each(function() {
$(this).css({
transition: 'opacity ' + that.settings.transitionDuration + 'ms linear',
backfaceVisibility: 'hidden'
});
});
}
, transition: function(slideNum, forward) {
// If inProgress flag is not set (i.e. if not mid-transition)
if (!this.inProgress) {
// If not already on requested slide
if (slideNum !== this.currentPlace) {
// Check whether the requested slide index is ahead or behind in the array (if not passed in as param)
if (typeof forward === 'undefined') {
forward = slideNum > this.currentPlace ? true : false;
}
if (this.settings.controls !== 'none') {
// If controls exist, revise active class states
this.$controlLinks.eq(this.currentPlace).removeClass('active');
this.$controlLinks.eq(slideNum).addClass('active');
}
// Assign next slide prop (elem)
this.$nextSlide = this.$slides.eq(slideNum);
// Assign next slide index prop (int)
this.currentPlace = slideNum;
// User-defined function, fires with transition
this.settings.onChange();
// Instantiate new Transition object, passing in self (RS obj), transition type (string), direction (bool)
new Transition(this, this.settings.transition, forward);
if (this.settings.controls === 'thumbs' && this.isOverflowThumb(forward)) {
if (forward) {
(this.isFirstThumb()) ? this.shiftToFirstThumb() : this.nextThumbs();
}
else {
(this.isLastThumb()) ? this.shiftToLastThumb() : this.prevThumbs();
}
// console.log("this.isLastThumb() " + this.isLastThumb() + " Or this.isFirstThumb() " + this.isFirstThumb());
}
}
}
}
, getMaxShiftLeft: function() {
// @todo: test this.settings.thumbMargin when padding for .be-thumb-wrap is 0, or when box-sizing is not border-box
// return this.maxShiftLeft = -(this.thumbsWidth - this.thumbWrapWidth + this.settings.thumbMargin);
return this.maxShiftLeft = -(this.thumbsWidth - this.thumbWrapWidth);
}
, getThumbWrapWidth: function() {
// thumb wrapper width
return this.thumbWrapWidth = this.$thumbWrap.outerWidth(true);
}
, getThumbsVisible: function() {
// number of visible thumbs
return this.thumbsVisible = Math.floor(this.thumbWrapWidth / this.thumbOuterWidth);
}
, nextThumbs: function() {
this.shiftLeft = this.shiftLeft - (this.thumbsVisible * this.thumbOuterWidth);
if (this.shiftLeft < this.maxShiftLeft)
this.shiftLeft = this.maxShiftLeft;
this.$thumbs.stop().css({
transform: 'translate3d(' + this.shiftLeft +'px, 0, 0)'
});
this.update(false, true);
}
, prevThumbs: function() {
this.shiftLeft = this.shiftLeft + (this.thumbsVisible * this.thumbOuterWidth);
if (this.shiftLeft > 0)
this.shiftLeft = 0;
this.$thumbs.stop().css({
transform: 'translate3d(' + this.shiftLeft +'px, 0, 0)'
});
this.update(false, true);
}
, isFirstThumb: function() {
return (this.currentPlace === 0) ? true : false;
}
, isLastThumb: function() {
return (this.currentPlace === this.totalSlides - 1) ? true : false;
}
, getThumbWrapOffset: function() {
this.thumbWrapLeftOffset = this.$thumbWrap.offset().left;
this.thumbWrapRightOffset = this.thumbWrapLeftOffset + this.thumbWrapWidth + this.settings.thumbMargin;
}
, isOverflowThumb: function(forward) {
this.activeLeftOffset = this.$controlLinks.eq(this.currentPlace).offset().left;
this.activeRightOffset = this.activeLeftOffset + this.thumbOuterWidth;
// console.log("this.activeLeftOffset: " + this.activeLeftOffset);
// console.log("this.activeRightOffset: " + this.activeRightOffset);
if ((this.thumbWrapLeftOffset - this.settings.thumbMargin <= this.activeLeftOffset) && (this.activeRightOffset <= this.thumbWrapRightOffset + this.settings.thumbMargin)) {
return false;
}
else if ((this.thumbWrapRightOffset + this.settings.thumbMargin < this.activeRightOffset) && forward) {
return true;
}
else if ((this.activeLeftOffset < this.thumbWrapLeftOffset - this.settings.thumbMargin) && !forward) {
return true;
}
else if (((this.thumbWrapRightOffset + this.settings.thumbMargin <= this.activeLeftOffset) && !forward && this.isLastThumb()) || ((this.activeRightOffset <= this.thumbWrapLeftOffset + this.settings.thumbMargin) && forward && this.isFirstThumb())) {
return true;
}
return false;
}
, shiftToFirstThumb: function() {
this.shiftLeft = 0;
this.$thumbs.stop().css({
transform: 'translate3d(' + this.shiftLeft +'px, 0, 0)'
});
this.update(false, true);
}
, shiftToLastThumb: function() {
this.shiftLeft = this.maxShiftLeft;
this.$thumbs.stop().css({
transform: 'translate3d(' + this.shiftLeft +'px, 0, 0)'
});
this.update(false, true);
}
, adjustToFirstThumb: function() {
this.shiftLeft = 0;
this.$thumbs.css({
marginLeft: this.shiftLeft + 'px'
});
}
, adjustToLastThumb: function() {
this.shiftLeft = this.maxShiftLeft;
this.$thumbs.css({
marginLeft: this.shiftLeft + 'px'
});
}
, adjustThumbControls: function() {
if (this.$thumbs.offset().left + this.$thumbs.width() < (this.thumbWrapRightOffset)) {
this.adjustToLastThumb();
}
if (this.$thumbs.width() < this.$thumbWrap.width()) {
this.adjustToFirstThumb();
this.hideThumbControls();
}
else {
this.toggleThumbControls();
}
}
, toggleThumbControls: function() {
this.showThumbControls();
(this.shiftLeft === 0) ? this.$thumbsPrev.hide() : this.$thumbsPrev.show();
(this.shiftLeft !== 0 && this.shiftLeft <= this.maxShiftLeft) ? this.$thumbsNext.hide() : this.$thumbsNext.show();
}
, showThumbControls: function() {
this.$thumbsPrev.show();
this.$thumbsNext.show();
}
, hideThumbControls: function() {
this.$thumbsPrev.hide();
this.$thumbsNext.hide();
}
, update: function(calculations, transitions) {
if (calculations) {
this.getThumbWrapWidth();
this.getThumbWrapOffset();
this.getThumbsVisible();
this.adjustThumbControls();
}
if (transitions) {
this.getMaxShiftLeft();
this.toggleThumbControls();
}
//
// console.log("=========================================");
// console.log("thumbWrapWidth: " + this.thumbWrapWidth);
// console.log("thumbsVisible: " + this.thumbsVisible);
// console.log("thumbsWidth: " + this.thumbsWidth);
// console.log("shift left: " + this.shiftLeft);
// console.log("max shift left: " + this.maxShiftLeft);
// console.log("this.$thumbs.offset().left:" + this.$thumbs.offset().left);
// console.log("this.thumbWrapRightOffset: " + this.thumbWrapRightOffset);
}
};
// Transition object constructor
function Transition(RS, transition, forward) {
this.RS = RS; // RS (RefineSlide) object
this.RS.inProgress = true; // Set RS inProgress flag to prevent additional Transition objects being instantiated until transition end
this.forward = forward; // Bool: true for forward, false for backward
this.transition = transition; // String: name of transition requested
if (this.transition === 'custom') {
this.customAnims = this.RS.settings.customTransitions;
this.isCustomTransition = true;
}
// Remove incorrect specified elements from customAnims array.
if (this.transition === 'custom') {
var that = this;
$.each(this.customAnims, function(i, obj) {
if ($.inArray(obj, that.anims) === -1) {
that.customAnims.splice(i, 1);
}
});
}
this.fallback3d = this.RS.settings.fallback3d; // String: fallback to use when 3D transforms aren't supported
this.init(); // Call Transition initialisation method
}
// Transition object Prototype
Transition.prototype = {
// Fallback to use if CSS transitions are unsupported
fallback: 'fade'
// Array of possible animations
, anims: ['cubeH', 'cubeV', 'fade', 'sliceH', 'sliceV', 'slideH', 'slideV', 'scale', 'blockScale', 'kaleidoscope', 'fan', 'blindH', 'blindV']
, customAnims: []
, init: function() {
// Call requested transition method
this[this.transition]();
}
, before: function(callback) {
var that = this;
// Prepare slide opacity & z-index
this.RS.$currentSlide.css('z-index', 2);
this.RS.$nextSlide.css({'opacity': 1, 'z-index': 1});
// Fade out/in captions with CSS/JS depending on browser capability
if (this.RS.cssTransitions) {
this.RS.$currentSlide.find('.be-caption').css('opacity', 0);
this.RS.$nextSlide.find('.be-caption').css('opacity', 1);
} else {
this.RS.$currentSlide.find('.be-caption').animate({'opacity': 0}, that.RS.settings.transitionDuration);
this.RS.$nextSlide.find('.be-caption').animate({'opacity': 1}, that.RS.settings.transitionDuration);
}
// Check if transition describes a setup method
if (typeof this.setup === 'function') {
// Setup required by transition
var transition = this.setup();
setTimeout(function() {
callback(transition);
}, 20);
} else {
// Transition execution
this.execute();
}
// Listen for CSS transition end on elem (set by transition)
if (this.RS.cssTransitions) {
$(this.listenTo).one('webkitTransitionEnd transitionend otransitionend oTransitionEnd mstransitionend', $.proxy(this.after, this));
}
}
, after: function() {
// Reset transition CSS
this.RS.$sliderBG.removeAttr('style');
this.RS.$slider.removeAttr('style');
/* @todo: known issue - removing these 2 lines messes up our 3d transitions. To be fixed later */
/* removed for cover fill mode */
this.RS.$currentSlide.removeAttr('style');
this.RS.$nextSlide.removeAttr('style');
this.RS.$currentSlide.css({
zIndex: 1,
opacity: 0
});
this.RS.$nextSlide.css({
zIndex: 2,
opacity: 1
});
// Additional reset steps required by transition (if any exist)
if (typeof this.reset === 'function') {
this.reset();
}
// If slideshow is active, reset the timeout
if (this.RS.settings.autoPlay) {
clearTimeout(this.RS.cycling);
this.RS.setAutoPlay();
}
// Assign new slide position
this.RS.$currentSlide = this.RS.$nextSlide;
// Remove RS obj inProgress flag (i.e. allow new Transition to be instantiated)
this.RS.inProgress = false;
// User-defined function, fires after transition has ended
this.RS.settings.afterChange();
}
, fade: function() {
var that = this;
// If CSS transitions are supported by browser
if (this.RS.cssTransitions) {
// Setup steps
this.setup = function() {
// Set event listener to next slide elem
that.listenTo = that.RS.$currentSlide;
that.RS.$currentSlide.css('transition', 'opacity ' + that.RS.settings.transitionDuration + 'ms linear');
};
// Execution steps
this.execute = function() {
// Display next slide over current slide
that.RS.$currentSlide.css('opacity', 0);
};
} else { // JS animation fallback
this.execute = function() {
that.RS.$currentSlide.animate({'opacity': 0}, that.RS.settings.transitionDuration, function() {
// Reset steps
that.after();
});
};
}
this.before($.proxy(this.execute, this));
}
// cube() method is used by cubeH() & cubeV() - not for calling directly
, cube: function(tz, ntx, nty, nrx, nry, wrx, wry) { // Args: translateZ, (next slide) translateX, (next slide) translateY, (next slide) rotateX, (next slide) rotateY, (wrap) rotateX, (wrap) rotateY
// Fallback if browser does not support 3d transforms/CSS transitions
if (!this.RS.cssTransitions || !this.RS.cssTransforms3d) {
return this[this['fallback3d']](); // User-defined transition
}
var that = this;
// Setup steps
this.setup = function() {
// Set event listener to '.be-slider'
that.listenTo = that.RS.$slider;
this.RS.$sliderBG.css('perspective', 1000);
// props for slide - s
that.RS.$currentSlide.css({
transform: 'translateZ(' + tz + 'px)',
backfaceVisibility: 'hidden'
});
// props for next slide
-
that.RS.$nextSlide.css({
opacity: 1,
backfaceVisibility: 'hidden',
transform: 'translateY(' + nty + 'px) translateX(' + ntx + 'px) rotateY(' + nry + 'deg) rotateX(' + nrx + 'deg)'
});
// props for slider
that.RS.$slider.css({
transform: 'translateZ(-' + tz + 'px)',
transformStyle: 'preserve-3d'
});
};
// Execution steps
this.execute = function() {
that.RS.$slider.css({
transition: 'all ' + that.RS.settings.transitionDuration + 'ms ease-in-out',
transform: 'translateZ(-' + tz + 'px) rotateX(' + wrx + 'deg) rotateY(' + wry + 'deg)'
});
};
this.before($.proxy(this.execute, this));
}
, cubeH: function() {
// Set to half of slide width
var dimension = $(this.RS.$slides).width() / 2;
// If next slide is ahead in array
if (this.forward) {
this.cube(dimension, dimension, 0, 0, 90, 0, -90);
} else {
this.cube(dimension, -dimension, 0, 0, -90, 0, 90);
}
}
, cubeV: function() {
// Set to half of slide height
var dimension = $(this.RS.$slides).height() / 2;
// If next slide is ahead in array
if (this.forward) {
this.cube(dimension, 0, -dimension, 90, 0, -90, 0);
} else {
this.cube(dimension, 0, dimension, -90, 0, 90, 0);
}
}
// grid() method is used by many transitions - not for calling directly
// Grid calculations are based on those in the awesome flux slider (joelambert.co.uk/flux)
, grid: function(cols, rows, ro, tx, ty, sc, op) { // Args: columns, rows, rotate, translateX, translateY, scale, opacity
// Fallback if browser does not support CSS transitions
if (!this.RS.cssTransitions) {
return this[this['fallback']]();
}
var that = this;
// Setup steps
this.setup = function() {
// The time (in ms) added to/subtracted from the delay total for each new gridlet
var count = (that.RS.settings.transitionDuration) / (cols + rows);
// Gridlet creator (divisions of the image grid, positioned with background-images to replicate the look of an entire slide image when assembled)
function gridlet(width, height, top, left, src, imgWidth, imgHeight, c, r) {
var delay = (c + r) * count;
// Return a gridlet elem with styles for specific transition
return $('').css({
// width: that.RS.sliderWidth,
// height: that.RS.sliderHeight,
width: '100%',
height: '100%',
top: top,
left: left,
backgroundImage: 'url(' + src + ')',
// backgroundPosition: '-' + left + 'px -' + top + 'px',
backgroundPosition: '50% 50%',
backgroundSize: imgWidth + 'px ' + imgHeight + 'px',
backgroundRepeat: 'no-repeat',
transition: 'all ' + that.RS.settings.transitionDuration + 'ms ease-in-out ' + delay + 'ms',
transform: 'none'
});
}
// Get the next slide's image
that.$img = that.RS.$currentSlide.find('img.be-slide-image');
// Create a grid to hold the gridlets
that.$grid = $('').addClass('be-grid');
// Prepend the grid to the next slide (i.e. so it's above the slide image)
that.RS.$currentSlide.prepend(that.$grid);
// vars to calculate positioning/size of gridlets
var imgWidth = that.$img.width(),
imgHeight = that.$img.height(),
imgSrc = that.$img.attr('src'),
colWidth = Math.floor(imgWidth / cols),
rowHeight = Math.floor(imgHeight / rows),
colRemainder = imgWidth - (cols * colWidth),
colAdd = Math.ceil(colRemainder / cols),
rowRemainder = imgHeight - (rows * rowHeight),
rowAdd = Math.ceil(rowRemainder / rows),
leftDist = 0;
// tx/ty args can be passed as 'auto'/'min-auto' (meaning use slide width/height or negative slide width/height)
tx = tx === 'auto' ? imgWidth : tx;
tx = tx === 'min-auto' ? -imgWidth : tx;
ty = ty === 'auto' ? imgHeight : ty;
ty = ty === 'min-auto' ? -imgHeight : ty;
// Loop through cols
for (var i = 0; i < cols; i++) {
var topDist = 0,
newColWidth = colWidth;
// If imgWidth (px) does not divide cleanly into the specified number of cols, adjust individual col widths to create correct total
if (colRemainder > 0) {
var add = colRemainder >= colAdd ? colAdd : colRemainder;
newColWidth += add;
colRemainder -= add;
}
// Nested loop to create row gridlets for each col
for (var j = 0; j < rows; j++) {
var newRowHeight = rowHeight,
newRowRemainder = rowRemainder;
// If imgHeight (px) does not divide cleanly into the specified number of rows, adjust individual row heights to create correct total
if (newRowRemainder > 0) {
add = newRowRemainder >= rowAdd ? rowAdd : rowRemainder;
newRowHeight += add;
newRowRemainder -= add;
}
// Create & append gridlet to grid
that.$grid.append(gridlet(newColWidth, newRowHeight, topDist, leftDist, imgSrc, imgWidth, imgHeight, i, j));
topDist += newRowHeight;
}
leftDist += newColWidth;
}
// Set event listener on last gridlet to finish transitioning
that.listenTo = that.$grid.children().last();
// Show grid & hide the image it replaces
that.$grid.show();
that.$img.css('opacity', 0);
// Add identifying classes to corner gridlets (useful if applying border radius)
that.$grid.children().first().addClass('be-top-left');
that.$grid.children().last().addClass('be-bottom-right');
that.$grid.children().eq(rows - 1).addClass('be-bottom-left');
that.$grid.children().eq(-rows).addClass('be-top-right');
};
// Execution steps
this.execute = function() {
that.$grid.children().css({
opacity: op,
transform: 'rotate(' + ro + 'deg) translateX(' + tx + 'px) translateY(' + ty + 'px) scale(' + sc + ')'
});
};
this.before($.proxy(this.execute, this));
// Reset steps
this.reset = function() {
that.$img.css('opacity', 1);
that.$grid.remove();
};
}
, sliceH: function() {
this.grid(1, 8, 0, 'min-auto', 0, 1, 0);
}
, sliceV: function() {
this.grid(10, 1, 0, 0, 'auto', 1, 0);
}
, slideV: function() {
var dir = this.forward ?
'min-auto' :
'auto';
this.grid(1, 1, 0, 0, dir, 1, 1);
}
, slideH: function() {
var dir = this.forward ?
'min-auto' :
'auto';
// this.grid(1, 1, 0, dir, 0, 1, 1);
var tx = dir;
var that = this;
tx = tx === 'auto' ? that.RS.sliderWidth : tx;
tx = tx === 'min-auto' ? -that.RS.sliderWidth : tx;
console.log(that.RS.sliderWidth);
// If CSS transitions are supported by browser
if (this.RS.cssTransitions) {
// Setup steps
this.setup = function() {
// Set event listener to next slide elem
that.listenTo = that.RS.$currentSlide;
that.RS.$currentSlide.css('transition', 'all ' + that.RS.settings.transitionDuration + 'ms linear');
};
// Execution steps
this.execute = function() {
// Display next slide over current slide
that.RS.$currentSlide.css({
// 'opacity': 0,
transform: 'translate3d(' + tx +'px, 0, 0)'});
// console.log('translate3d(' + tx +'px, 0, 0)');
};
} else { // JS animation fallback
this.execute = function() {
that.RS.$currentSlide.animate({'opacity': 0}, that.RS.settings.transitionDuration, function(){
// Reset steps
that.after();
});
};
}
this.before($.proxy(this.execute, this));
}
, scale: function() {
this.grid(1, 1, 0, 0, 0, 1.5, 0);
}
, blockScale: function() {
this.grid(8, 6, 0, 0, 0, .6, 0);
}
, kaleidoscope: function() {
this.grid(10, 8, 0, 0, 0, 1, 0);
}
, fan: function() {
this.grid(1, 10, 45, 100, 0, 1, 0);
}
, blindV: function() {
this.grid(1, 8, 0, 0, 0, .7, 0);
}
, blindH: function() {
this.grid(10, 1, 0, 0, 0, .7, 0);
}
, random: function() {
// Pick a random transition from the anims array (obj prop)
this[this.anims[Math.floor(Math.random() * this.anims.length)]]();
}
, custom: function() {
if (this.RS.nextAnimIndex < 0) {
this.RS.nextAnimIndex = this.customAnims.length - 1;
}
if (this.RS.nextAnimIndex === this.customAnims.length) {
this.RS.nextAnimIndex = 0;
}
// Pick the next item in the list of transitions provided by user.
this[this.customAnims[this.RS.nextAnimIndex]]();
}
};
// Obj to check browser capabilities
var testBrowser = {
// Browser vendor CSS prefixes
browserVendors: ['', '-webkit-', '-moz-', '-ms-', '-o-', '-khtml-']
// Browser vendor DOM prefixes
, domPrefixes: ['', 'Webkit', 'Moz', 'ms', 'O', 'Khtml']
// Method to iterate over a property (using all DOM prefixes)
// Returns true if prop is recognised by browser (else returns false)
, testDom: function(prop) {
var i = this.domPrefixes.length;
while (i--) {
if (typeof document.body.style[this.domPrefixes[i] + prop] !== 'undefined') {
return true;
}
}
return false;
}
, cssTransitions: function() {
// Use Modernizr if available & implements csstransitions test
if (typeof window.Modernizr !== 'undefined' && Modernizr.csstransitions !== 'undefined') {
return Modernizr.csstransitions;
}
// Use testDom method to check prop (returns bool)
return this.testDom('Transition');
}
, cssTransforms3d: function() {
// Use Modernizr if available & implements csstransforms3d test
if (typeof window.Modernizr !== 'undefined' && Modernizr.csstransforms3d !== 'undefined') {
return Modernizr.csstransforms3d;
}
// Check for vendor-less prop
if (typeof document.body.style['perspectiveProperty'] !== 'undefined') {
return true;
}
// Use testDom method to check prop (returns bool)
return this.testDom('Perspective');
}
};
// jQuery plugin wrapper
$.fn['bigGallery'] = function(settings) {
return this.each(function() {
// Check if already instantiated on this elem
if (!$.data(this, 'bigGallery')) {
// Instantiate & store elem + string
$.data(this, 'bigGallery', new RS(this, settings));
}
});
};
})(window.jQuery, window, window.document);