<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<ul class="my-carousel">
<li><img src="https://raw.githubusercontent.com/Kunano/js-carousel/master/img/coffee-1.png"/></li>
<li><img src="https://raw.githubusercontent.com/Kunano/js-carousel/master/img/coffee-2.png"/></li>
<li> <img src="https://raw.githubusercontent.com/Kunano/js-carousel/master/img/coffee-3.png"/> </li>
</ul>
<script>
/**
* Simple Encapsulation Class template
*/
(function (root) {
"use strict";
/**
* Common object params
* @type {Object}
*/
var common = {
publicMethods: ['next', 'prev', 'goTo', 'setOptions', 'play', 'stop', 'getEffectsList', 'setEffect'],
className: 'JsCarousel'
},
/**
* Main constructor
* @return {Object} - this handle
*/
Protected = function (handle, options) {
//main settings
this.settings = {
effect: 'carousel',
timeFunction: 'easeOutQuart',
easeInOut: true,
duration: 1000,
autoplay: false,
autoplayTimeout: 1000,
bullets: true,
controls: true,
onload: null
/*,stopOnHover: true*/
};
//main handle
this.handle = handle;
this.handle.classList.add('js-carousel');
//items array
this.items = this.handle.children;
//set options
this.setOptions(options);
this.preloadImages(function () {
this.init();
});
return this;
};
/**
* Main prototype
* @type {Object}
*/
Protected.prototype = {
preloadImages: function (callback) {
var self = this,
images,
preloadFn,
counter,
l,
i;
images = this.handle.querySelectorAll('img');
if (images) {
l = images.length;
counter = l;
preloadFn = function (imgElem) {
var img = document.createElement('img');
img.onload = function () {
counter -= 1;
if (counter === 0) {
callback.call(self);
}
};
img.src = imgElem.src;
img = null;
};
for (i = 0; i < l; i += 1) {
preloadFn(images[i]);
}
}
},
init: function () {
var self = this;
//create wrapper
this.wrapper = document.createElement('div');
this.wrapper.setAttribute('class', 'js-carousel-wrapper');
//create main container
this.container = document.createElement('div');
this.container.setAttribute('class', 'js-carousel-container');
//insert container before handle
this.handle.parentNode.insertBefore(this.container, this.handle.parentNode.firstChild);
//create effect container
this.effectContainer = document.createElement('div');
this.effectContainer.setAttribute('class', 'effect-container');
this.container.appendChild(this.effectContainer);
//create handle wrapper
this.wrapper = document.createElement('div');
this.wrapper.setAttribute('class', 'js-carousel-wrapper');
this.container.appendChild(this.wrapper);
// create nav container
if (this.settings.controls) {
this.navContainer = document.createElement('div');
this.navContainer.setAttribute('class', 'js-carousel-nav-container');
// crate prev button
this.prevButton = document.createElement('div');
this.prevButton.setAttribute('class', 'js-carousel-prev-button');
// create next button
this.nextButton = document.createElement('div');
this.nextButton.setAttribute('class', 'js-carousel-next-button');
// put buttons into nav container
this.navContainer.appendChild(this.prevButton);
this.navContainer.appendChild(this.nextButton);
// put nav container into main container
this.container.appendChild(this.navContainer);
}
//put handle into the wrapper
this.wrapper.appendChild(this.handle);
//set current slide number
this.currentSlide = 1;
//in action status flag
this.inaction = true;
//abort status flag
this.abortStatus = false;
//set events to prev button
this.settings.controls && this.prevButton.addEventListener('click', (this.prev).bind(this));
//set events to next button
this.settings.controls && this.nextButton.addEventListener('click', (this.next).bind(this));
//autoplay timer ID
this.autoplayTimeoutId = null;
this.itemWidth = this.items[0].querySelector('img').clientWidth;
this.itemHeight = this.items[0].querySelector('img').clientHeight;
Array.prototype.forEach.call(this.items, function (item) {
self.applyStyles(item, {
width: self.itemWidth + 'px',
height: self.itemHeight + 'px'
});
});
//clone last slide to first
this.handle.insertBefore(this.items[this.items.length - 1].cloneNode(true), this.handle.firstChild);
//clone first slide to last
this.handle.appendChild(this.items[1].cloneNode(true));
//set carousel full width
this.handle.style.width = (this.itemWidth * this.items.length) + 'px';
//set carousel start left position
this.handle.style.left = -this.itemWidth + 'px';
//set styles to main container
this.applyStyles(this.container, {
width: this.itemWidth + 'px',
height: this.itemHeight + 'px',
position: 'relative'
});
//set styles to wrapper
this.applyStyles(this.wrapper, {
width: this.itemWidth + 'px',
height: this.itemHeight + 'px',
position: 'relative',
overflow: 'hidden'
});
//set styles to effect container
this.applyStyles(this.effectContainer, {
width: this.itemWidth + 'px',
height: this.itemHeight + 'px',
position: 'absolute',
overflow: 'hidden',
left: 0,
top: 0,
zIndex: 1,
display: 'none'
});
if (this.settings.bullets) {
// create bullets wrapper
this.bulletsWrapper = document.createElement('div');
this.bulletsWrapper.setAttribute('class', 'js-carousel-bullets-wrapper');
// create bullets container
this.bulletsContainer = document.createElement('div');
this.bulletsContainer.setAttribute('class', 'js-carousel-bullets-container');
this.bulletsWrapper.appendChild(this.bulletsContainer);
}
Array.prototype.forEach.call(this.items, function (item, index) {
var img = item.querySelector('img'),
fakeImg = document.createElement('div'),
bullet;
self.applyStyles(fakeImg, {
backgroundImage: 'url("' + img.src + '")',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
width: '100%',
height: '100%',
position: 'relative'
});
self.applyStyles(img, {
display: 'none'
});
item.appendChild(fakeImg);
if (self.settings.bullets && !!index && (index < (self.items.length - 1))) {
bullet = document.createElement('div');
bullet.setAttribute('class', 'bullet');
(index === 1) && bullet.classList.add('active');
bullet.addEventListener('click', function () {
self.goTo(index);
});
self.bulletsContainer.appendChild(bullet);
}
});
if (this.settings.bullets) {
this.container.appendChild(this.bulletsWrapper);
this.bullets = this.bulletsContainer.childNodes;
}
this.inaction = false;
this.handle.classList.add('loaded');
(function (space) {
var autoplay = space.settings.autoplay;
//stop on hover
space.container.addEventListener('mouseover', function () {
autoplay && space.stop();
});
space.container.addEventListener('mouseout', function () {
autoplay && space.play();
});
}(this));
//start autoplay
this.settings.autoplay && this.play(this.settings.autoplayTimeout);
//callback
(this.settings.onload && typeof this.settings.onload === 'function') && this.settings.onload.call(this);
},
/**
* Conserve aspect ratio of the orignal region. Useful when shrinking/enlarging
* images to fit into a certain area.
*
* @param {Number} srcWidth Source area width
* @param {Number} srcHeight Source area height
* @param {Number} maxWidth Fittable area maximum available width
* @param {Number} maxHeight Fittable area maximum available height
* @return {Object} { width, heigth }
*/
calculateAspectRatioFit: function (srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
return {
width: srcWidth * ratio,
height: srcHeight * ratio
};
},
setOptions : function (options) {
var n,
i,
l,
autoplay;
this.stop();
//apply options
for (n in options) {
this.settings[n] = options[n];
}
autoplay = this.settings.autoplay;
//set animation function
if (typeof this.settings.effect === 'string' && this.animationFunctions[this.settings.effect]) {
this.settings.effect = this.animationFunctions[this.settings.effect];
}
//set time function
if (typeof this.settings.timeFunction === 'string' && this.timeFunctions[this.settings.timeFunction]) {
this.settings.timeFunction = this.timeFunctions[this.settings.timeFunction];
} else if (typeof this.settings.timeFunction === 'string' && this.settings.timeFunction.match(/^cubic-bezier\(/gi)) {
n = this.settings.timeFunction.match(/(\(.+\))/gi)[0].replace(/[\(\)\s]/gi, '').split(',');
this.settings.timeFunction = function (progress) {
return new this.Bezier(n[0], n[1], n[2], n[3])(progress);
}
}
//clear items styles
l = this.items.length;
for (i = 0; i < l; i += 1) {
this.items[i].setAttribute('style', '');
}
//if (autoplay) {
// this.play();
//}
},
delay: function (timeMs, callback) {
var self = this;
return setTimeout(function () {
callback.call(self);
}, timeMs);
},
goTo: function (action) {
if (this.inaction) {
return false;
}
var slideNumber = 1,
xEnd = 0;
//check the slide number type
switch (typeof action) {
case 'number':
action = (action > this.items.length - 1) ? this.items.length - 1 : Math.abs(action);
xEnd = - ((action - 1) * this.itemWidth) - this.itemWidth;
slideNumber = action;
break;
case 'string':
switch (action) {
case 'next':
xEnd = this.handle.offsetLeft - this.itemWidth;
slideNumber = Math.abs(xEnd / this.itemWidth);
break;
case 'prev':
xEnd = this.handle.offsetLeft + this.itemWidth;
slideNumber = Math.abs(xEnd / this.itemWidth);
break;
default:
action = parseInt(action, 10);
return (isNaN(action)) ? this.goTo(1) : this.goTo(action);
break;
}
break;
}
slideNumber = (slideNumber > this.items.length - 2) ? 1 : slideNumber;
slideNumber = (slideNumber < 1) ? this.items.length - 2 : slideNumber;
//get current slide
this.currentSlide = (Math.abs(this.handle.offsetLeft / this.itemWidth));
this.settings.bullets && Array.prototype.forEach.call(this.bullets, function (bullet, index) {
((index + 1) === slideNumber) ? bullet.classList.add('active') : bullet.classList.remove('active');
});
//call animation function
this.settings.effect.call(this, slideNumber);
},
next: function (e) {
e && e.preventDefault && e.preventDefault();
return this.goTo('next');
},
prev: function (e) {
e && e.preventDefault && e.preventDefault();
return this.goTo('prev');
},
play: function (timeWait) {
timeWait = timeWait || 10;
this.settings.autoplay = true;
this.autoplayTimeoutId = this.delay(timeWait, function () {
//go next
if (!this.inaction) {
this.next();
}
});
},
stop: function () {
this.settings.autoplay = false;
clearTimeout(this.autoplayTimeoutId);
},
abort: function () {
this.stop();
this.abortStatus = true;
},
animate: function (element, property, value, units, callback, duration) {
callback = callback || function () {};
duration = duration || this.settings.duration;
var self = this,
startValue = parseInt(root.getComputedStyle(element)[property], 10),
currentPos,
delta = this.settings.timeFunction,
startTime = new Date,
timeProgress,
timeIntId;
timeIntId = setInterval(function() {
if (self.abortStatus) {
clearInterval(timeIntId);
return;
}
timeProgress = (new Date - startTime) / duration;
if (timeProgress > 1) {
timeProgress = 1;
}
(function (delta) {
//console.log(startValue);
currentPos = startValue + (value - startValue) * delta;
element.style[property] = currentPos + units;
}(delta.call(self, timeProgress)));
if (timeProgress == 1) {
clearInterval(timeIntId);
callback();
}
}, 10);
},
showSlide: function (slideNumber) {
//set position to realy slide
this.handle.style.left = - (this.itemWidth * (slideNumber)) + 'px';
},
animationBlock: function () {
this.effectContainer.style.display = 'block';
this.inaction = true;
clearTimeout(this.autoplayTimeoutId);
},
animationUnblock: function () {
this.inaction = false;
this.effectContainer.style.display = 'none';
if (this.settings.autoplay) {
this.play(this.settings.autoplayTimeout);
}
},
applyStyles: function (elem, styleObj) {
var n;
for (n in styleObj) {
if (styleObj.hasOwnProperty(n)) {
elem.style[n] = styleObj[n];
}
}
},
getEffectsList: function () {
var n,
i = 0,
listArray = [];
for (n in this.animationFunctions) {
if (this.animationFunctions.hasOwnProperty(n)) {
listArray[i] = n.toString();
i += 1;
}
}
return listArray;
},
setEffect: function (effectName, effectFunction) {
this.animationFunctions[effectName] = (effectFunction.bind(this));
},
isNextSlide: function (slideNumber) {
return ((this.currentSlide === this.items.length - 2 && slideNumber === 1) || slideNumber - this.currentSlide === 1);
},
isPrevSlide: function (slideNumber) {
return !this.isNextSlide(slideNumber);
},
isFirstSlide: function (slideNumber) {
return (this.currentSlide === this.items.length - 2 && slideNumber === 1);
},
isLastSlide: function (slideNumber) {
return !this.isFirstSlide(slideNumber);
},
animationFunctions: {
random: function (slideNumber) {
var effList = this.getEffectsList(),
rand = Math.floor(Math.random() * (effList.length - 1)) + 1;
return this.animationFunctions[effList[rand]].call(this, slideNumber);
},
/*cube: function (slideNumber, horizontal) {
horizontal = horizontal || false;
var self = this,
cubeContainer,
cubicBezier = 'cubic-bezier(.58,.18,.4,.93)',
perspective = 1000,
cube,
cubeSideFront,
cubeSideBack,
frontShadow,
backShadow,
frontSideStyles,
backSideStyles,
tmp = self.effectContainer.style.overflow,
tmp2 = self.handle.style.opacity;
//block animation
self.animationBlock();
//set reset overflow to main container
self.effectContainer.style.overflow = 'visible';
self.handle.style.opacity = 0;
//clear effect container
self.effectContainer.innerHTML = '';
//create cube container
cubeContainer = document.createElement('div');
//create cube
cube = document.createElement('div');
//create sides
cubeSideFront = document.createElement('div');
cubeSideBack = document.createElement('div');
//create shadows
frontShadow = document.createElement('div');
backShadow = document.createElement('div');
self.applyStyles(cubeContainer, {
width: self.itemWidth + 'px',
height: self.itemHeight + 'px',
position: 'absolute',
perspective: perspective + 'px'
});
//apply styles to cube
self.applyStyles(cube, {
width: self.itemWidth + 'px',
height: self.itemHeight + 'px',
position: 'absolute',
transform: 'translateZ(-136px)'
});
if (horizontal) {
cube.style.transform = 'translateZ(-667px)';
}
frontSideStyles = {
display: 'block',
position: 'absolute',
left: 0,
top: 0,
width: self.itemWidth + 'px',
height: self.itemHeight + 'px',
transition: 'transform ' + self.settings.duration + 'ms',
boxSizing: 'border-box',
backfaceVisibility: 'hidden',
transform: 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemHeight / 2) + 'px)'
};
backSideStyles = {
display: 'block',
position: 'absolute',
left: 0,
top: 0,
width: self.itemWidth + 'px',
height: self.itemHeight + 'px',
transition: 'transform ' + self.settings.duration + 'ms',
boxSizing: 'border-box',
backfaceVisibility: 'hidden',
transform: 'perspective(' + perspective + 'px) rotateX(' + (this.isNextSlide(slideNumber) ? '' : '-') + '90deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemHeight / 2) + 'px)'
};
if (horizontal) {
frontSideStyles.transform = 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemWidth / 2) + 'px) translateX(0px)';
backSideStyles.transform = 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(' + (this.isNextSlide(slideNumber) ? '-' : '') + '90deg) translateZ(' + (self.itemWidth / 2) + 'px) translateX(0px)';
}
//apply styles to side front
self.applyStyles(cubeSideFront, frontSideStyles);
//apply styles to side top
self.applyStyles(cubeSideBack, backSideStyles);
//apply style styles to shadow front
self.applyStyles(frontShadow, frontSideStyles);
self.applyStyles(frontShadow, {
background: 'linear-gradient' + (this.isNextSlide(slideNumber) ? '(to bottom, rgba(0,0,0,0.41) 0%,rgba(0,0,0,0.77) 60%,rgba(0,0,0,1) 100%)' : '(to bottom, #000 0%, rgba(0, 0, 0, 0.7) 60%, rgba(0, 0, 0, 0.5) 100%)'),
transition: 'opacity ' + (self.settings.duration / 2) + 'ms, transform ' + self.settings.duration + 'ms',
opacity: 0,
zIndex: 1
});
//apply style styles to shadow top
self.applyStyles(backShadow, backSideStyles);
self.applyStyles(backShadow, {
background: 'linear-gradient' + (this.isNextSlide(slideNumber) ? '(to bottom, rgba(0,0,0,1) 0%,rgba(0,0,0,0.75) 60%,rgba(0,0,0,0.80) 100%)' : '(to bottom, rgba(0,0,0,0.7) 0%,rgba(0,0,0,0.8) 60%,rgba(0,0,0,1) 100%)'),
transition: 'opacity ' + self.settings.duration + 'ms, transform ' + self.settings.duration + 'ms',
opacity: 1,
zIndex: 1
});
if (horizontal) {
if (this.isNextSlide(slideNumber)) {
frontShadow.style.background = 'linear-gradient(to right, rgba(0, 0, 0, 0.41) 0%, rgba(0, 0, 0, 0.77) 60%, #000 100%)';
backShadow.style.background = 'linear-gradient(to right, #000 0%, rgba(0, 0, 0, 0.73) 60%, rgba(0, 0, 0, 0.22) 100%)';
} else {
frontShadow.style.background = 'linear-gradient(to right, #000 0%, rgba(0, 0, 0, 0.73) 60%, rgba(0, 0, 0, 0.22) 100%)';
backShadow.style.background = 'linear-gradient(to right, rgba(0,0,0,0.41) 0%, rgba(0,0,0,0.77) 60%, rgba(0,0,0,1) 100%)';
}
}
//put slides into the sides
cubeSideFront.appendChild(this.items[self.currentSlide].childNodes[0].cloneNode(true));
cubeSideBack.appendChild(this.items[slideNumber].childNodes[0].cloneNode(true));
self.applyStyles(cubeSideFront.querySelector('img'), {
width: self.itemWidth + 'px',
height: self.itemHeight + 'px',
});
self.applyStyles(cubeSideBack.querySelector('img'), {
width: self.itemWidth + 'px',
height: self.itemHeight + 'px',
});
//put shadows
cube.appendChild(frontShadow);
cube.appendChild(backShadow);
//put sides into the cube
cube.appendChild(cubeSideFront);
cube.appendChild(cubeSideBack);
//append cube into the cube container
cubeContainer.appendChild(cube);
//append cube contaiber into the effect container
self.effectContainer.appendChild(cubeContainer);
//start the animation
self.delay(100, function () {
//cube animation
if (horizontal) {
self.applyStyles(cubeSideFront, {
transform: 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(' + (this.isNextSlide(slideNumber) ? '' : '-') + '90deg) translateZ(' + (self.itemWidth / 2) + 'px) translateX(0px)'
});
self.applyStyles(cubeSideBack, {
transform: 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemWidth / 2) + 'px) translateX(0px)'
});
} else {
self.applyStyles(cubeSideFront, {
transform: 'perspective(' + perspective + 'px) rotateX(' + (this.isNextSlide(slideNumber) ? '-' : '') + '90deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemHeight / 2) + 'px)'
});
self.applyStyles(cubeSideBack, {
transform: 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemHeight / 2) + 'px)'
});
}
//shadow animation
if (horizontal) {
self.applyStyles(frontShadow, {
transform: 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(' + (this.isNextSlide(slideNumber) ? '' : '-') + '90deg) translateZ(' + (self.itemWidth / 2) + 'px) translateX(0px)',
opacity: 1
});
self.applyStyles(backShadow, {
transform: 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemWidth / 2) + 'px) translateX(0px)',
opacity: 0
});
} else {
self.applyStyles(frontShadow, {
transform: 'perspective(' + perspective + 'px) rotateX(' + (this.isNextSlide(slideNumber) ? '-' : '') + '90deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemHeight / 2) + 'px)',
opacity: 1
});
self.applyStyles(backShadow, {
transform: 'perspective(' + perspective + 'px) rotateX(0deg) rotateZ(0deg) rotateY(0deg) translateZ(' + (self.itemHeight / 2) + 'px)',
opacity: 0
});
}
});
//return;
self.delay(self.settings.duration, function () {
//back old style values to main container
self.effectContainer.style.overflow = tmp;
self.handle.style.opacity = tmp2;
//set position to realy slide
self.showSlide(slideNumber);
//clear effect container
self.effectContainer.innerHTML = '';
//unblock animation
self.animationUnblock();
});
},
cubeHorizontal: function (slideNumber) {
return this.animationFunctions.cube.apply(this, [slideNumber, true]);
},*/
briks: function (slideNumber) {
var self = this,
brickPersentHeight = 20,
bricksCountInRow = Math.ceil(100 / brickPersentHeight),
brickHeight = self.itemHeight / bricksCountInRow,
bricksCountInColumn = Math.ceil(100 / brickPersentHeight),
brickWidth = self.itemWidth / bricksCountInColumn,
childNodes = self.items[slideNumber].childNodes,
elem,
imageHandle,
durationTime = self.settings.duration / (bricksCountInRow * bricksCountInColumn),
bricksElems,
imageSrc,
row,
coll,
i,
l;
//check to child elements
if (!childNodes) {
return self.animationFunctions.carousel.call(self, slideNumber);
}
/*l = childNodes.length;
for (i = 0; i < l; i += 1) {
if (childNodes[i].tagName !== 'IMG') {
return self.animationFunctions.carousel.call(self, slideNumber);
}
}*/
//block animation
self.animationBlock();
//clear effect container
self.effectContainer.innerHTML = '';
//get image handle
imageHandle = self.items[slideNumber].querySelector('img');
imageHandle.style.width = self.itemWidth + 'px';
imageHandle.style.height = self.itemHeight + 'px';
//get image src
imageSrc = imageHandle.getAttribute('src');
//create bricks
for (row = 0; row < bricksCountInRow; row += 1) {
for (coll = 0; coll < bricksCountInColumn; coll += 1) {
//create brick
elem = document.createElement('div');
//apply styles
self.applyStyles(elem, {
backgroundImage: 'url(' + imageSrc + ')',
backgroundPosition: '-' + (brickWidth * coll) + 'px -' + (brickHeight * row) + 'px',
backgroundSize: self.itemWidth + 'px ' + self.itemHeight + 'px',
top: (brickHeight * row) + 'px',
left: (brickWidth * coll) + 'px',
width: brickWidth + 'px',
height: brickHeight + 'px',
position: 'absolute',
opacity: 0
});
//append into the effect container
self.effectContainer.appendChild(elem);
}
}
//start animation
bricksElems = self.effectContainer.querySelectorAll('div');
l = bricksElems.length;
for (i = 0; i < l; i += 1) {
(function (brick, index, allCount) {
var delayTime = index * durationTime;
self.delay(delayTime, function () {
self.animate(brick, 'opacity', 1, '', function () {
if (index === allCount) {
//set position to realy slide
self.showSlide(slideNumber);
//clear effect container
self.effectContainer.innerHTML = '';
//unblock animation
self.animationUnblock();
}
}, durationTime * (index + 2));
});
}(bricksElems[i], i, l - 1));
}
},
carousel: function (slideNumber) {
var self = this;
this.animationBlock();
//if slide to next
if (this.isNextSlide(slideNumber)) {
//animation slide to right
this.animate(this.handle, 'left', this.handle.offsetLeft - this.itemWidth, 'px', function () {
//if is pseudo first slide
if (self.isFirstSlide(slideNumber)) {
self.handle.style.left = - self.itemWidth + 'px';
}
self.animationUnblock();
});
//if slide to prev
} else {
//animation slide to left
this.animate(this.handle, 'left', this.handle.offsetLeft + this.itemWidth, 'px', function () {
//if is pseudo last slide
if (self.currentSlide === 1 && slideNumber === self.items.length - 2) {
self.handle.style.left = - (self.itemWidth * (self.items.length - 2)) + 'px';
}
self.animationUnblock();
});
}
},
slideHorizontal: function (slideNumber) {
var self = this;
self.animationBlock();
self.animate(self.handle, 'left', -(self.itemWidth * slideNumber), 'px', function () {
self.animationUnblock();
});
},
parallax: function (slideNumber) {
var self = this,
fakeSlide1,
fakeSlide2,
filterProps = ['webkitFilter', 'mozFilter', 'msFilter', 'oFilter', 'filter'],
l = filterProps.length,
i,
fakeSlideEndPos = (self.currentSlide < slideNumber) ? -self.itemWidth : self.itemWidth,
originalDuration = self.settings.duration;
self.animationBlock();
var createFakeSlide = function () {
var rand = Math.floor(Math.random() * ((self.items.length - 2))) + 1,
elem = self.items[rand].cloneNode(true);
//set styles for fake slide
self.applyStyles(elem, {
position: 'absolute',
left: ((self.currentSlide < slideNumber) ? self.itemWidth : -self.itemWidth) + 'px',
top: 0,
listStyle: 'none',
margin: 0,
padding: 0,
overflow: 'hidden'
});
//put fake slide to viewport
self.effectContainer.appendChild(elem);
//set the blur effect
for (i = 0; i < l; i += 1) {
if (typeof elem.style[filterProps[i]]) {
elem.style[filterProps[i]] = 'blur(1px)';
}
}
return elem;
};
fakeSlide1 = createFakeSlide();
fakeSlide2 = createFakeSlide();
//set new duration value
self.settings.duration = originalDuration * 2;
//call carousel effect
self.animationFunctions.carousel.call(self, slideNumber);
//set original duration value
self.settings.duration = originalDuration;
//animate fake slide 1
self.animate(fakeSlide1, 'left', fakeSlideEndPos, 'px', function () {
//set position to realy slide
self.showSlide(slideNumber);
//remove fake slide
fakeSlide1.parentNode.removeChild(fakeSlide1);
}, self.settings.duration * 2);
},
fade: function (slideNumber) {
var self = this,
fakeSlide = self.items[slideNumber].cloneNode(true);
self.animationBlock();
//half duration on every slide
self.settings.duration = self.settings.duration;
//set styles for fake slide
self.applyStyles(fakeSlide, {
opacity: 0,
position: 'absolute',
left: self.items[self.currentSlide].offsetLeft + 'px'
});
//put fake slide to viewport
self.handle.appendChild(fakeSlide);
//animate to show fake slide
self.animate(fakeSlide, 'opacity', 1, '', function () {
//set position to realy slide
self.showSlide(slideNumber);
//remove fake slide
fakeSlide.parentNode.removeChild(fakeSlide);
//unblock animation
self.animationUnblock();
});
},
flash: function (slideNumber) {
var self = this;
self.animationBlock();
//half duration on every slide
self.settings.duration = self.settings.duration / 2;
self.items[slideNumber].style.opacity = 0;
self.animate(self.items[self.currentSlide], 'opacity', 0, '', function () {
//set position to new slide
self.showSlide(slideNumber);
//show new slide
self.animate(self.items[slideNumber], 'opacity', 1, '', function () {
//unblock animation
self.animationUnblock();
});
//show hidden slide
self.items[self.currentSlide].style.opacity = 1;
//return duration
self.settings.duration = self.settings.duration * 2;
});
},
list: function (slideNumber) {
var self = this,
fakeSlide = self.items[slideNumber].cloneNode(true);
self.animationBlock();
//half duration on every slide
self.settings.duration = self.settings.duration;
//set styles for fake slide
fakeSlide.style.width = 0;
fakeSlide.style.overflow = 'hidden';
fakeSlide.style.position = 'absolute';
fakeSlide.style.left = self.items[self.currentSlide].offsetLeft + 'px';
//put fake slide to viewport
self.handle.appendChild(fakeSlide);
//animate to show fake slide
self.animate(fakeSlide, 'width', self.itemWidth, 'px', function () {
//set position to realy slide
self.showSlide(slideNumber);
//remove fake slide
fakeSlide.parentNode.removeChild(fakeSlide);
//unblock animation
self.animationUnblock();
});
},
slice: function (slideNumber, direction, slicePersentHeight) {
direction = direction || 'left';
slicePersentHeight = slicePersentHeight || 20;
var self = this,
sliceCout = Math.ceil(100 / slicePersentHeight),
sliceWidth = self.itemWidth,
sliceHeight = self.itemHeight / sliceCout,
elem,
childNodes = self.items[slideNumber].childNodes,
imageHandle,
imageSrc,
i,
l,
slicesElems,
slideElem;
//check to child elements
if (!childNodes) {
return self.animationFunctions.carousel.call(self, slideNumber);
}
/*l = childNodes.length;
for (i = 0; i < l; i += 1) {
if (childNodes[i].tagName !== 'IMG') {
return self.animationFunctions.carousel.call(self, slideNumber);
}
}*/
//block animation
this.animationBlock();
//clear effect container
self.effectContainer.innerHTML = '';
//get image handle
imageHandle = self.items[slideNumber].querySelector('img');
imageHandle.style.width = self.itemWidth + 'px';
imageHandle.style.height = self.itemHeight + 'px';
//get image src
imageSrc = imageHandle.getAttribute('src');
//create slice blocks
for (i = 0; i < sliceCout; i += 1) {
//create slice
elem = document.createElement('div');
elem.style.backgroundSize = self.itemWidth + 'px ' + self.itemHeight + 'px';
if (direction === 'top' || direction === 'bottom') {
sliceWidth = self.itemWidth / sliceCout;
sliceHeight = self.itemHeight;
elem.style.backgroundPosition = '-' + (sliceWidth * i) + 'px 0';
elem.style[direction] = (-sliceHeight) + 'px';
elem.style.left = (sliceWidth * i) + 'px';
} else {
elem.style.backgroundPosition = '0 -' + (sliceHeight * i) + 'px';
elem.style.top = (sliceHeight * i) + 'px';
elem.style[direction] = -sliceWidth + 'px';
}
elem.style.width = sliceWidth + 'px';
elem.style.height = sliceHeight + 'px';
elem.style.backgroundImage = 'url(' + imageSrc + ')';
elem.style.position = 'absolute';
//set positions
elem.style.opacity = 0;
//append into the effect container
self.effectContainer.appendChild(elem);
}
//start animation
slicesElems = self.effectContainer.querySelectorAll('div');
l = slicesElems.length;
for (i = 0; i < l; i += 1) {
(function (slice, index, allCount) {
var delayTime = index * 100;
self.delay(delayTime, function () {
self.animate(slice, direction, 0, 'px');
self.animate(slice, 'opacity', 1, '', function () {
if (index === allCount) {
//set position to realy slide
self.showSlide(slideNumber);
//clear effect container
self.effectContainer.innerHTML = '';
//unblock animation
self.animationUnblock();
}
});
});
}(slicesElems[i], i, l - 1));
}
},
slicePrizma: function (slideNumber, useDelay) {
var self = this,
slicePersentWidth = 6,
sliceCout = Math.ceil(100 / slicePersentWidth),
sliceHeight = self.itemHeight,
sliceWidth = self.itemWidth / sliceCout,
elem,
childNodes = self.items[slideNumber].childNodes,
imageHandle,
imageSrc,
durationTime = self.settings.duration / sliceCout,
i,
l,
slicesElems,
direction;
//check to child elements
if (!childNodes) {
return self.animationFunctions.carousel.call(self, slideNumber);
}
//block animation
this.animationBlock();
//clear effect container
self.effectContainer.innerHTML = '';
//get image handle
imageHandle = self.items[slideNumber].querySelector('img');
imageHandle.style.width = self.itemWidth + 'px';
imageHandle.style.height = self.itemHeight + 'px';
//get image src
imageSrc = imageHandle.getAttribute('src');
//create slice blocks
for (i = 0; i < sliceCout; i += 1) {
//create slice
elem = document.createElement('div');
self.applyStyles(elem, {
backgroundSize: self.itemWidth + 'px ' + self.itemHeight + 'px',
width: 0,
height: sliceHeight + 'px',
backgroundImage: 'url(' + imageSrc + ')',
position: 'absolute',
opacity: 0
});
sliceWidth = self.itemWidth / sliceCout;
sliceHeight = self.itemHeight;
self.applyStyles(elem, {
backgroundPosition: '-' + (sliceWidth * i) + 'px 0',
top: 0,
left: (sliceWidth * i) + 'px'
});
//append into the effect container
self.effectContainer.appendChild(elem);
}
//start animation
slicesElems = self.effectContainer.querySelectorAll('div');
l = slicesElems.length;
for (i = 0; i < l; i += 1) {
(function (slice, index, allCount) {
var delayTime = useDelay ? index * durationTime : 0,
delayTime2 = useDelay ? durationTime * index : self.settings.duration;
self.delay(delayTime, function () {
self.animate(slice, 'width', sliceWidth, 'px');
self.animate(slice, 'opacity', 1, '', function () {
if (index === allCount) {
//set position to realy slide
self.showSlide(slideNumber);
//clear effect container
self.effectContainer.innerHTML = '';
//unblock animation
self.animationUnblock();
}
}, delayTime2);
});
}(slicesElems[i], i, l - 1));
}
},
slicePrizmaUseDelay: function (slideNumber) {
return this.animationFunctions.slicePrizma.apply(this, [slideNumber, true]);
},
sliceTopBottom: function (slideNumber, useDelay) {
var self = this,
slicePersentWidth = 6,
sliceCout = 100 / slicePersentWidth,
sliceHeight = self.itemHeight,
sliceWidth = self.itemWidth / sliceCout,
elem,
childNodes = self.items[slideNumber].childNodes,
imageHandle,
imageSrc,
i,
l,
slicesElems,
direction;
//check to child elements
if (!childNodes) {
return self.animationFunctions.carousel.call(self, slideNumber);
}
/*l = childNodes.length;
for (i = 0; i < l; i += 1) {
if (childNodes[i].tagName !== 'IMG') {
return self.animationFunctions.carousel.call(self, slideNumber);
}
}*/
//block animation
this.animationBlock();
//clear effect container
self.effectContainer.innerHTML = '';
//get image handle
imageHandle = self.items[slideNumber].querySelector('img');
imageHandle.style.width = self.itemWidth + 'px';
imageHandle.style.height = self.itemHeight + 'px';
//get image src
imageSrc = imageHandle.getAttribute('src');
//create slice blocks
for (i = 0; i < sliceCout; i += 1) {
//create slice
elem = document.createElement('div');
self.applyStyles(elem, {
backgroundSize: self.itemWidth + 'px ' + self.itemHeight + 'px',
width: sliceWidth + 'px',
height: sliceHeight + 'px',
backgroundImage: 'url(' + imageSrc + ')',
position: 'absolute',
opacity: 0
});
direction = (!(i % 2)) ? 'top' : 'bottom';
sliceWidth = self.itemWidth / sliceCout;
sliceHeight = self.itemHeight;
elem.style.backgroundPosition = '-' + (sliceWidth * i) + 'px 0';
elem.style[direction] = (-sliceHeight) + 'px';
elem.style.left = (sliceWidth * i) + 'px';
//append into the effect container
self.effectContainer.appendChild(elem);
}
//return;
//start animation
slicesElems = self.effectContainer.querySelectorAll('div');
l = slicesElems.length;
for (i = 0; i < l; i += 1) {
(function (slice, index, allCount) {
var delayTime = useDelay ? index * 50 : 0;
self.delay(delayTime, function () {
var direction = (!(index % 2)) ? 'top' : 'bottom';
self.animate(slice, direction, 0, 'px');
self.animate(slice, 'opacity', 1, '', function () {
if (index === allCount) {
//set position to realy slide
self.showSlide(slideNumber);
//clear effect container
self.effectContainer.innerHTML = '';
//unblock animation
self.animationUnblock();
}
});
});
}(slicesElems[i], i, l - 1));
}
},
sliceTopBottomUseDelay: function (slideNumber) {
return this.animationFunctions.sliceTopBottom.apply(this, [slideNumber, true]);
},
sliceToRight: function (slideNumber) {
return this.animationFunctions.slice.apply(this, [slideNumber, 'left', 20]);
},
sliceToLeft: function (slideNumber) {
return this.animationFunctions.slice.apply(this, [slideNumber, 'right', 20]);
},
sliceToTop: function (slideNumber) {
return this.animationFunctions.slice.apply(this, [slideNumber, 'top', 8]);
},
sliceToBottom: function (slideNumber) {
return this.animationFunctions.slice.apply(this, [slideNumber, 'bottom', 8]);
},
sliceRandom: function (slideNumber) {
var rand = Math.floor(Math.random() * (8)) + 1,
sliceFunction = 'sliceToLeft';
switch (rand) {
case 1:
sliceFunction = 'sliceToLeft';
break;
case 2:
sliceFunction = 'sliceToRight';
break;
case 3:
sliceFunction = 'sliceToTop';
break;
case 4:
sliceFunction = 'sliceToBottom';
break;
case 5:
sliceFunction = 'sliceTopBottom';
break;
case 6:
sliceFunction = 'sliceTopBottomUseDelay';
break;
case 7:
sliceFunction = 'slicePrizma';
break;
case 8:
sliceFunction = 'slicePrizmaUseDelay';
break;
}
return this.animationFunctions[sliceFunction].apply(this, [slideNumber]);
}
},
timeFunctions: {
linear: function (progress) {
//return new this.Bezier(0, 0, 1.0, 1.0)(progress);
return progress;
},
quad: function (progress) {
return Math.pow(progress, 2);
},
bounce: function (progress) {
for (var a = 0, b = 1, result; 1; a += b, b /= 2) {
if (progress >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
}
}
},
circ: function (progress) {
return 1 - Math.sin(Math.acos(progress));
},
back: function (progress) {
var x = 1.5;
return Math.pow(progress, 2) * ((x + 1) * progress - x);
},
elastic: function (progress) {
var x = 1.5;
return Math.pow(2, 10 * (progress - 1)) * Math.cos(20 * Math.PI * x / 3 * progress);
},
easeInQuad: function (progress) {
return progress * progress;
},
easeOutQuad: function (progress) {
return progress * (2 - progress);
},
easeInOutQuad: function (progress) {
return progress < .5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
},
easeInCubic: function (progress) {
return progress * progress * progress;
},
easeOutCubic: function (progress) {
return (--progress) * progress * progress +1;
},
easeInOut: function (progress) {
return new this.Bezier(.42, 0, .58, 1.0)(progress);
},
easeInOutCubic: function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 },
// accelerating from zero velocity
easeInQuart: function (t) { return t*t*t*t },
// decelerating to zero velocity
easeOutQuart: function (t) { return 1-(--t)*t*t*t },
// acceleration until halfway, then deceleration
easeInOutQuart: function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t },
// accelerating from zero velocity
easeInQuint: function (t) { return t*t*t*t*t },
// decelerating to zero velocity
easeOutQuint: function (t) { return 1+(--t)*t*t*t*t },
// acceleration until halfway, then deceleration
easeInOutQuint: function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t },
sine: function (progress) {
return 1 - Math.sin((1 - progress) * Math.PI/2);
},
test: function (progress) {
return new this.Bezier(.17, 1.12, .02, -0.55)(progress);
}
},
Bezier: function (p1,p2,p3,p4) {
// defining the bezier functions in the polynomial form
var Cx = 3 * p1;
var Bx = 3 * (p3 - p1) - Cx;
var Ax = 1 - Cx - Bx;
var Cy = 3 * p2;
var By = 3 * (p4 - p2) - Cy;
var Ay = 1 - Cy - By;
function bezier_x(t) { return t * (Cx + t * (Bx + t * Ax)); }
function bezier_y(t) { return t * (Cy + t * (By + t * Ay)); }
// using Newton's method to aproximate the parametric value of x for t
function bezier_x_der(t) { return Cx + t * (2*Bx + 3*Ax * t); }
function find_x_for(t) {
var x=t, i=0, z;
while (i < 5) { // making 5 iterations max
z = bezier_x(x) - t;
if (Math.abs(z) < 1e-3) break; // if already got close enough
x = x - z/bezier_x_der(x);
i++;
}
return x;
};
return function(t) {
return bezier_y(find_x_for(t));
}
}
};
/**
* Encapsulation
* @return {Object} - this handle
*/
root[common.className] = function () {
function construct(constructor, args) {
function Class() {
return constructor.apply(this, args);
}
Class.prototype = constructor.prototype;
return new Class();
}
var publicly = construct(Protected, arguments),
i,
l = common.publicMethods.length;
for (i = 0; i < l; i += 1) {
(function () {
var member = common.publicMethods[i];
root[common.className].prototype[member] = function () {
return publicly[member].apply(publicly, arguments);
};
}());
}
return this;
};
}(this));
(function () {
//init carousel
var jsCarousel = new JsCarousel(document.querySelector('.my-carousel'), {
timeFunction: 'easeInOut',
effect: 'random',
duration: 1250,
autoplay: true,
autoplayTimeout: 5000,
bullets: true,
controls: true
});
}());
</script>
.js-carousel-container{
margin: 0 auto;
background-color: #fff;
box-shadow: 0 0 13px -4px rgba(0, 0, 0, .65);
}
.js-carousel-container:before,
.js-carousel-container:after{
position: absolute;
z-index: -1;
bottom: 65px;
left: 0;
width: 50%;
height: 20px;
content: '';
border-radius: 100%;
box-shadow: 0 67px 20px -3px rgba(40, 40, 40, .63);
}
.js-carousel-container:after{
right: 0;
left: initial;
transform: rotateZ(2deg);
}
.js-carousel-container:before{
transform: rotateZ(-2deg);
}
/*JSCAROUSEL STYLES*/
.js-carousel{
position: relative;
z-index: 0;
margin: 0;
padding: 0;
list-style: none;
}
.js-carousel li{
display: none;
}
.js-carousel li:first-child{
display: block;
}
.js-carousel.loaded li{
font-size: 93px;
line-height: 240px;
position: relative;
display: block;
float: left;
margin: 0;
padding: 0;
text-align: center;
color: #2f2f2f;
}
.js-carousel.loaded li a{
position: absolute;
z-index: 1;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100%;
}
.js-carousel-prev-button,
.js-carousel-next-button{
position: absolute;
z-index: 2;
top: 50%;
bottom: 0;
left: -20px;
width: 0;
height: 0;
margin-top: -20px;
cursor: pointer;
color: #395058;
border: 20px solid #ffe;
border-radius: 100%;
box-shadow: 0 1px 12px -2px rgba(0, 0, 0, .46);
}
.js-carousel-next-button{
right: -20px;
left: initial;
}
.js-carousel-next-button:before{
position: absolute;
top: -7px;
left: -5px;
content: '►';
}
.js-carousel-prev-button:before{
position: absolute;
top: -7px;
left: -10px;
content: '◄';
}
.js-carousel-prev-button:hover,
.js-carousel-next-button:hover{
color: #fc6216;
}
.js-carousel-bullets-wrapper{
position: absolute;
z-index: 2;
bottom: -12px;
left: 50%;
}
.js-carousel-bullets-wrapper > div{
position: relative;
left: -50%;
background-color: red;
}
.js-carousel-bullets-wrapper .bullet{
position: relative;
float: left;
width: 5px;
height: 5px;
margin: 0 2px;
cursor: pointer;
text-indent: -4000px;
border: 12px solid #ffe;
border-radius: 100%;
background-color: #395058;
box-shadow: 0 1px 12px -2px rgba(0, 0, 0, .46);
}
.js-carousel-bullets-wrapper .bullet.active,
.js-carousel-bullets-wrapper .bullet:hover{
background-color: #fc6216;
}