<!--
Insipred by Alexander Laguta/Alexey Smolkin:
https://www.behance.net/gallery/19539847/Helen-Miller
Pictures by Jennifer Esseiva: hhttps://www.behance.net/gallery/63821461/Capricious-Weather
-->
<canvas id="canvas0" width="800" height="480"></canvas>
<canvas id="canvas1" width="800" height="480"></canvas>
<canvas id="canvas2" width="800" height="480"></canvas>
<canvas id="canvas3" width="800" height="480"></canvas>
<nav class="link-list">
<ul>
<li><a href="" data-order="0" data-imagesrc="https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/1fcd7259138189.5a168738899cc.jpg"></a></li>
<li><a href="" data-order="1" data-imagesrc="https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/04de5959138189.5a168738850c3.jpg"></a></li>
<li><a href="" data-order="2" data-imagesrc="https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/d00a5e59138189.5a16873887bdd.jpg"></a></li>
<li><a href="" data-order="3" data-imagesrc="https://mir-s3-cdn-cf.behance.net/project_modules/1400/c9a2a063821461.5ac1239819171.jpg"></a></li>
<li><a href="" data-order="4" data-imagesrc="https://mir-s3-cdn-cf.behance.net/project_modules/1400/dad4f463821461.5ac1076d90b2c.jpg"></a></li>
</ul>
</nav>
<nav class="btns">
<button class="show-prev"><span>PREV</span></button>
<button class="show-next"><span>NEXT</span></button>
</nav>
<p class="loading-txt">Loading images...</p>
@import "compass/css3";
@import "compass/reset";
$maincolor: #C8A36C;
canvas{
position: absolute;
}
nav.link-list{
position: absolute;
left:50%;
transform: translateX(-50%);
bottom: 20px;
display: inline-block;
li{
overflow: hidden;
float: left;
}
a{
position: relative;
width: 12px;
height: 12px;
margin:5px;
display: inline-block;
border-radius: 50%;
background-color: #fff;
transition: background-color 0.5s ease;
&.is-active{
background-color: $maincolor;
}
}
}
nav.btns{
position: absolute;
top: 45%;
width: 100%;
button{
position: absolute;
display:inline-block;
width: 44px;
height: 44px;
text-align: center;
line-height: 44px;
font-weight: bold;
font-size: 10px;
font-family: serif;
border-radius:50%;
background-color: #fff;
cursor: pointer;
border: 0;
transition: all 0.5s ease;
&:focus{
outline: 0;
}
&:before{
content: '';
position: absolute;
width: 44px;
height: 44px;
top: 0;
left: 0;
border: 2px solid $maincolor;
border-radius: 50%;
opacity:0;
transition: all 0.5s ease;
}
span{
opacity: 0;
transition: opacity 0.2s ease;
}
&:hover {
background-color: $maincolor;
width: 64px;
height: 64px;
transform: translateY(-10px);
&:before{
opacity:1;
width: 104px;
height: 104px;
top: -22px;
left: -22px;
}
span{
opacity: 1;
}
}
&.show-prev{
left: 15%;
}
&.show-next{
right: 15%;
}
}
}
footer{
position: absolute;
bottom: 10px;
right: 10px;
font-family: sans-serif;
color: #ccc;
font-size: 12px;
line-height: 12px;
a {
color: inherit;
}
}
.loading-txt{
text-align: center;
width: 100%;
font-size: 24px;
position: absolute;
top: 50%;
transform: translateY(-50%);
&.is-hidden{
display: none;
}
}
View Compiled
(function() {
'use strict';
/* global TweenMax, Power1 */
//DOM
var canvas0 = document.getElementById('canvas0'),
ctx0 = canvas0.getContext('2d'),
canvas1 = document.getElementById('canvas1'),
ctx1 = canvas1.getContext('2d'),
canvas2 = document.getElementById('canvas2'),
ctx2 = canvas2.getContext('2d'),
canvas3 = document.getElementById('canvas3'),
ctx3 = canvas3.getContext('2d'),
linklist = document.querySelector('.link-list'),
btns = document.querySelector('.btns'),
nextBtn = btns.querySelector('.show-next'),
loadTxt = document.querySelector('.loading-txt');;
// CONST
var VW, VH, AR;
var IS_ACTIVE = 'is-active';
// VARS
var isAnimating = false,
currentImage = 0,
prevImage = 0,
currentLink,
imagesloaded = 0,
partMove = {
val: 1
};
var slideshowInterval;
// IMAGES STUFF
var imagesList = [],
linkList = [];
var imgW, imgH, IAR;
// CANVAS STUFF
var partList = [{
context: ctx1,
xpos: 100,
radius: 0 // circumference of mask1
}, {
context: ctx2,
xpos: -70,
radius: 0 // circumference of mask2
}, {
context: ctx3,
xpos: 50,
radius: 0 // circumference of mask3
}];
function drawImages() {
var imgPrev = imagesList[prevImage];
var imgNext = imagesList[currentImage];
// This is Next
ctx0.globalAlpha = 1;
ctx0.drawImage(imgNext, 0, 0, imgW, imgH);
// This is Prev
ctx0.globalAlpha = partMove.val;
ctx0.drawImage(imgPrev, 0, 0, imgW, imgH);
var obj, ctx, xPrev, xNext;
for (var i = 0; i < partList.length; i++) {
obj = partList[i];
ctx = obj.context;
xPrev = -obj.xpos * (1 - partMove.val);
xNext = obj.xpos * partMove.val;
ctx.clearRect(0, 0, VW, VH);
ctx.save();
ctx.beginPath();
ctx.arc(VW / 2, VH / 2, obj.radius, 0, 2 * Math.PI, false);
ctx.fill();
// This is Next
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = 'source-in';
ctx.drawImage(imgNext, xNext, 0, imgW, imgH);
// This is Prev
ctx.globalAlpha = partMove.val;
ctx.globalCompositeOperation = 'source-atop';
ctx.drawImage(imgPrev, xPrev, 0, imgW, imgH);
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1;
if (i === 0) {
// if (i !== partList.length-1) {
ctx.lineWidth = 1;
ctx.strokeStyle = '#fff';
ctx.stroke();
}
// ctx.restore();
}
}
function changeImage() {
// Do not interupt previous movement
if (isAnimating) {
return;
}
isAnimating = true;
TweenMax.to(partMove, 1, {
val: 0,
ease: Power1.easeInOut,
onUpdate: drawImages,
onComplete: function() {
partMove.val = 1;
isAnimating = false;
}
});
}
function onBtnsClick(e) {
e.preventDefault();
// Do not interupt previous animation
if (isAnimating) {
return;
}
var trgt = e.target;
if (trgt.nodeName === 'BUTTON') {
prevImage = currentImage;
if (trgt.classList.contains('show-next')) {
(currentImage + 1 >= imagesList.length) ? currentImage = 0: currentImage++;
} else {
(currentImage - 1 < 0) ? currentImage = imagesList.length - 1: currentImage--;
}
changeImage();
selectLink();
clearInterval(slideshowInterval);
}
}
function onListClick(e) {
e.preventDefault();
// Do not interupt previous animation
if (isAnimating) {
return;
}
var trgt = e.target;
if (trgt.nodeName === 'A') {
prevImage = currentImage;
currentImage = parseInt(trgt.getAttribute('data-order'), 10);
changeImage();
selectLink();
clearInterval(slideshowInterval);
}
}
function selectLink() {
if (currentLink !== undefined) {
currentLink.classList.remove(IS_ACTIVE);
}
currentLink = linkList[currentImage];
currentLink.classList.add(IS_ACTIVE);
}
function calculateScreen() {
VW = window.innerWidth;
VH = window.innerHeight;
AR = VW / VH;
canvas0.width = canvas1.width = canvas2.width = canvas3.width = VW;
canvas0.height = canvas1.height = canvas2.height = canvas3.height = VH;
partList[0].radius = VW * 0.4;
partList[1].radius = VW * 0.25;
partList[2].radius = VW * 0.08;
}
function resizeBg() {
var image1 = imagesList[0];
IAR = image1.width / image1.height;
if (IAR < AR) {
imgW = VW;
imgH = VW / IAR;
} else {
imgW = VH * IAR;
imgH = VH;
}
}
function slideshowChange () {
prevImage = currentImage;
(currentImage + 1 >= imagesList.length) ? currentImage = 0: currentImage++;
changeImage();
selectLink();
}
function addEL() {
var debounceResize = debounce(function() {
calculateScreen();
resizeBg();
changeImage();
}, 200);
window.addEventListener('resize', debounceResize);
btns.addEventListener('click', onBtnsClick);
linklist.addEventListener('click', onListClick);
}
function preloadImages() {
imagesList.forEach(function(img) {
if (img.complete) {
handleImageComplete();
} else {
img.onload = handleImageComplete;
}
});
}
function handleImageComplete() {
imagesloaded++;
if (imagesloaded === imagesList.length) {
loadTxt.classList.add('is-hidden');
addEL();
init();
}
}
function init() {
calculateScreen();
resizeBg();
selectLink();
changeImage();
slideshowInterval = setInterval(slideshowChange,3000);
}
function preInit() {
var alist = linklist.querySelectorAll('a');
var img;
for (var i = 0; i < alist.length; i++) {
linkList.push(alist[i]);
img = new Image();
img.src = alist[i].getAttribute('data-imagesrc');
imagesList.push(img);
}
preloadImages();
}
preInit();
/**
* Helpers
*/
// http://davidwalsh.name/javascript-debounce-function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
})();
This Pen doesn't use any external CSS resources.