<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.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 ---------->
<!--pictures from Adobe Stock-->
<p id="loading">loading...</p>
<div id="images">
<div class="lighten">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/lighten1.jpg" alt="" />
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/lighten2.jpg" alt="" />
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/lighten3.jpg" alt="" />
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/lighten4.jpg" alt="" />
</div>
<div class="normal">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/normal1.jpg" alt="" />
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/normal2.jpg" alt="" />
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/normal3.jpg" alt="" />
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/593507/normal4.jpg" alt="" />
</div>
<nav>
<ul>
<li class="pre"></li>
<li class="next"></li>
</ul>
</nav>
</div>
<script>
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
Double exposure is photographic technique that combines 2 different images into a single image.
Then I use this technique with canvas blend modes.
*/
window.onload = function () {
var loading = document.getElementById("loading");
loading.classList.add("loading-done");
var property = {
element: "#images",
parallax: .6,
interval: 2200,
animDuration: 1500,
easing: easingInOutQuad
};
var slider = new DXslider(property);
slider.init();
};
var DXslider = function () {
function DXslider(property) {
_classCallCheck(this, DXslider);
this.images = document.querySelector(property.element);
this.preButton = document.querySelector(property.element + " nav .pre");
this.nextButton = document.querySelector(property.element + " nav .next");
this.lightenImages = document.querySelectorAll(".lighten img");
this.normalImages = document.querySelectorAll(".normal img");
this.canvasBox = document.createElement("div");
this.paraEffect = property.parallax; //have to clamp 0 ~ 1
this.canvasArray = [];
this.progress = 0;
this.animating = false;
this.interval = property.interval;
this.left = true;
this.duration = property.animDuration;
this.easing = property.easing;
this.images.appendChild(this.canvasBox);
this.canvasBox.classList.add("canvas");
}
DXslider.prototype.init = function init() {
this.settingStyle();
this.settingCanvas();
this.preButton.addEventListener("click", function (e) {
if (!this.animating) {
this.left = false;
clearTimeout(this.timer);
this.slide();
}
}.bind(this), false);
this.preButton.addEventListener("touchend", function (e) {
if (!this.animating) {
this.left = false;
clearTimeout(this.timer);
this.slide();
}
}.bind(this), false);
this.nextButton.addEventListener("click", function (e) {
if (!this.animating) {
this.left = true;
clearTimeout(this.timer);
this.slide();
}
}.bind(this), false);
this.nextButton.addEventListener("touchend", function (e) {
if (!this.animating) {
this.left = true;
clearTimeout(this.timer);
this.slide();
}
}.bind(this), false);
};
DXslider.prototype.settingStyle = function settingStyle() {
this.imagesWidth = this.images.offsetWidth;
this.width = this.lightenImages[0].width;
this.height = this.lightenImages[0].height;
this.dpi = this.width / this.imagesWidth;
this.images.style.height = this.canvasBox.style.height = this.imagesWidth * this.height / this.width + "px";
this.preButton.classList.add("after-loading");
this.nextButton.classList.add("after-loading");
};
DXslider.prototype.settingCanvas = function settingCanvas() {
var canvas, context, normal, lighten, n;
for (var i = 0, len = this.normalImages.length * 2; i < len; i++) {
canvas = document.createElement("canvas");
this.canvasBox.appendChild(canvas);
context = canvas.getContext("2d");
canvas.width = this.width;
canvas.height = this.height;
canvas.style.width = this.imagesWidth + "px";
canvas.style.height = this.imagesWidth * this.height / this.width + "px";
//add images(lighten and normal) into canvasArray
n = i % (len / 2);
normal = this.normalImages[n];
lighten = this.lightenImages[n];
this.canvasArray.push({
canvas: canvas, context: context, normal: normal, lighten: lighten
});
}
this.render(this.progress, -this.imagesWidth);
this.timer = setTimeout(this.slide.bind(this), this.interval);
};
DXslider.prototype.slide = function slide() {
this.left ? this.tween(-this.imagesWidth, this.duration, this.easing) : this.tween(this.imagesWidth, this.duration, this.easing);
};
DXslider.prototype.tween = function tween(change, duration, easingFunc) {
var startTime = new Date();
this.progress = 0;
this.animating = true;
this.update(startTime, change, duration, easingFunc);
};
DXslider.prototype.update = function update(startTime, change, duration, easingFunc) {
var time = new Date() - startTime;
if (time < duration) {
this.progress = easingFunc(time / duration);
this.render(this.progress, change);
requestAnimationFrame(this.update.bind(this, startTime, change, duration, easingFunc));
} else {
if (this.left) {
var firstEle = this.canvasArray[0];
this.canvasArray.shift();
this.canvasArray.push(firstEle);
} else {
var lastEle = this.canvasArray[this.canvasArray.length - 1];
this.canvasArray.pop();
this.canvasArray.unshift(lastEle);
}
this.progress = 1;
this.animating = false;
time = duration;
this.left = true;
this.render(0, -this.imagesWidth);
this.timer = setTimeout(this.slide.bind(this), this.interval);
}
};
DXslider.prototype.render = function render(progress, position) {
for (var i = 0, len = this.canvasArray.length; i < len; i++) {
var canvas = this.canvasArray[i].canvas;
canvas.style.setProperty("-webkit-transform", "translate(" + (progress * position - (len / 2 - i) * this.imagesWidth) + "px, 0)");
canvas.style.transform = "translate(" + (progress * position - (len / 2 - i) * this.imagesWidth) + "px, 0)";
var context = this.canvasArray[i].context;
context.clearRect(0, 0, this.width, this.height);
context.globalCompositeOperation = "source-over";
context.drawImage(this.canvasArray[i].normal, 0, 0, this.width, this.height);
context.globalCompositeOperation = "lighten";
context.drawImage(this.canvasArray[i].lighten, ((len / 2 - i) * this.imagesWidth - progress * position) * this.dpi * this.paraEffect, 0, this.width, this.height);
}
};
return DXslider;
}();
//easing
//prepare only easingInOutQuad
function easingInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
</script>
*{
margin: 0;
padding: 0;
}
body{
background: #222;
}
#loading{
color: #fff;
position: absolute;
letter-spacing: 3px;
width: 10em;
line-height: 2em;
top: calc(50% - 1em) ;
left: calc(50% - 5em);
z-index: 2;
text-align: center;
}
.loading-done{
display: none;
}
#images{
position: absolute;
width: 600px;
left: calc(50% - 300px);
}
.canvas{
position: relative;
display:block;
overflow: hidden;
}
#images img{
display: none;
vertical-align: bottom;
}
canvas{
vertical-align: bottom;
position: absolute;
}
nav ul{
height: 0;
margin: 0;
}
nav li {
position: absolute;
width: 25px;
height: 25px;
opacity: .3;
list-style: none;
top: calc(50% - 12px);
z-index: 100;
transition: opacity .3s;
}
nav li:hover{
opacity: .7;
}
.pre.after-loading{
left: -40px;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
border-top: 2px solid #fff;
border-left: 2px solid #fff;
}
.next.after-loading{
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
border-top: 2px solid #fff;
border-right: 2px solid #fff;
right: -40px;
}