1/** 2 * demo2.js 3 * http://www.codrops.com 4 * 5 * Licensed under the MIT license. 6 * http://www.opensource.org/licenses/mit-license.php 7 * 8 * Copyright 2017, Codrops 9 * http://www.codrops.com 10 */ 11 12// { 13// setTimeout(() => document.body.classList.add('render'), 60); 14// const navdemos = Array.from(document.querySelectorAll('nav.demos > .demo')); 15// const navigate = (linkEl) => { 16// document.body.classList.remove('render'); 17// document.body.addEventListener('transitionend', () => window.location = linkEl.href); 18// }; 19// navdemos.forEach(link => link.addEventListener('click', (ev) => { 20// ev.preventDefault(); 21// navigate(ev.target); 22// })); 23// } 24 25{ 26 // From https://davidwalsh.name/javascript-debounce-function. 27 function debounce(func, wait, immediate) { 28 var timeout; 29 return function() { 30 var context = this, args = arguments; 31 var later = function() { 32 timeout = null; 33 if (!immediate) func.apply(context, args); 34 }; 35 var callNow = immediate && !timeout; 36 clearTimeout(timeout); 37 timeout = setTimeout(later, wait); 38 if (callNow) func.apply(context, args); 39 }; 40 }; 41 42 class Slideshow { 43 constructor(el) { 44 this.DOM = {}; 45 this.DOM.el = el; 46 this.settings = { 47 animation: { 48 slides: { 49 duration: 600, 50 easing: 'easeOutQuint' 51 }, 52 shape: { 53 duration: 300, 54 easing: {in: 'easeOutQuint', out: 'easeOutQuad'} 55 } 56 }, 57 frameFill: '#f1f1f1' 58 } 59 this.init(); 60 } 61 init() { 62 this.DOM.slides = Array.from(this.DOM.el.querySelectorAll('.slides > .slider')); 63 this.slidesTotal = this.DOM.slides.length; 64 this.DOM.nav = this.DOM.el.querySelector('.slidenav'); 65 this.DOM.nextCtrl = this.DOM.nav.querySelector('.slidenav__item--next'); 66 this.DOM.prevCtrl = this.DOM.nav.querySelector('.slidenav__item--prev'); 67 this.current = 0; 68 this.createFrame(); 69 this.initEvents(); 70 } 71 createFrame() { 72 this.rect = this.DOM.el.getBoundingClientRect(); 73 this.frameSize = this.rect.width/12; 74 this.paths = { 75 initial: this.calculatePath('initial'), 76 final: this.calculatePath('final') 77 }; 78 this.DOM.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 79 this.DOM.svg.setAttribute('class', 'shape'); 80 this.DOM.svg.setAttribute('width','100%'); 81 this.DOM.svg.setAttribute('height','100%'); 82 this.DOM.svg.setAttribute('viewbox',`0 0 ${this.rect.width} ${this.rect.height}`); 83 this.DOM.svg.innerHTML = `<path fill="${this.settings.frameFill}" d="${this.paths.initial}"/>`; 84 this.DOM.el.insertBefore(this.DOM.svg, this.DOM.nav); 85 this.DOM.shape = this.DOM.svg.querySelector('path'); 86 } 87 updateFrame() { 88 this.paths.initial = this.calculatePath('initial'); 89 this.paths.final = this.calculatePath('final'); 90 this.DOM.svg.setAttribute('viewbox',`0 0 ${this.rect.width} ${this.rect.height}`); 91 this.DOM.shape.setAttribute('d', this.isAnimating ? this.paths.final : this.paths.initial); 92 } 93 calculatePath(path = 'initial') { 94 return path === 'initial' ? 95 `M 0,0 0,${this.rect.height} ${this.rect.width},${this.rect.height} ${this.rect.width},0 0,0 Z M 0,0 ${this.rect.width},0 ${this.rect.width},${this.rect.height} 0,${this.rect.height} Z` : 96 `M 0,0 0,${this.rect.height} ${this.rect.width},${this.rect.height} ${this.rect.width},0 0,0 Z M ${this.frameSize},${this.frameSize} ${this.rect.width-this.frameSize},${this.frameSize} ${this.rect.width-this.frameSize},${this.rect.height-this.frameSize} ${this.frameSize},${this.rect.height-this.frameSize} Z`; 97 } 98 initEvents() { 99 this.DOM.nextCtrl.addEventListener('click', () => this.navigate('next')); 100 this.DOM.prevCtrl.addEventListener('click', () => this.navigate('prev')); 101 102 window.addEventListener('resize', debounce(() => { 103 this.rect = this.DOM.el.getBoundingClientRect(); 104 this.updateFrame(); 105 }, 20)); 106 107 document.addEventListener('keydown', (ev) => {
108 const keyCode = ev.keyCode || ev.which; 109 if ( keyCode === 37 ) { 110 this.navigate('prev'); 111 } 112 else if ( keyCode === 39 ) { 113 this.navigate('next'); 114 } 115 }); 116 } 117 navigate(dir = 'next') { 118 if ( this.isAnimating ) return false; 119 this.isAnimating = true; 120 121 const animateShapeIn = anime({ 122 targets: this.DOM.shape, 123 duration: this.settings.animation.shape.duration, 124 easing: this.settings.animation.shape.easing.in, 125 d: this.paths.final 126 }); 127 128 const animateSlides = () => { 129 return new Promise((resolve, reject) => { 130 const currentSlide = this.DOM.slides[this.current]; 131 anime({ 132 targets: currentSlide, 133 duration: this.settings.animation.slides.duration, 134 easing: this.settings.animation.slides.easing, 135 translateX: dir === 'next' ? -1*this.rect.width : this.rect.width, 136 complete: () => { 137 currentSlide.classList.remove('slide--current'); 138 resolve(); 139 } 140 }); 141 142 this.current = dir === 'next' ? 143 this.current < this.slidesTotal-1 ? this.current + 1 : 0 : 144 this.current > 0 ? this.current - 1 : this.slidesTotal-1; 145 146 const newSlide = this.DOM.slides[this.current]; 147 newSlide.classList.add('slide--current'); 148 anime({ 149 targets: newSlide, 150 duration: this.settings.animation.slides.duration, 151 easing: this.settings.animation.slides.easing, 152 translateX: [dir === 'next' ? this.rect.width : -1*this.rect.width,0] 153 }); 154 155 const newSlideImg = newSlide.querySelector('.slide__img'); 156 anime.remove(newSlideImg); 157 anime({ 158 targets: newSlideImg, 159 duration: this.settings.animation.slides.duration*4, 160 easing: this.settings.animation.slides.easing, 161 translateX: [dir === 'next' ? 200 : -200, 0] 162 }); 163 164 anime({ 165 targets: [newSlide.querySelector('.slide__title'), newSlide.querySelector('.slide__desc'), newSlide.querySelector('.slide__link')], 166 duration: this.settings.animation.slides.duration*2, 167 easing: this.settings.animation.slides.easing, 168 delay: (t,i) => i*100+100, 169 translateX: [dir === 'next' ? 300 : -300,0], 170 opacity: [0,1] 171 }); 172 }); 173 }; 174 175 const animateShapeOut = () => { 176 anime({ 177 targets: this.DOM.shape, 178 duration: this.settings.animation.shape.duration, 179 delay: 150, 180 easing: this.settings.animation.shape.easing.out, 181 d: this.paths.initial, 182 complete: () => this.isAnimating = false 183 }); 184 } 185 186 animateShapeIn.finished.then(animateSlides).then(animateShapeOut); 187 } 188 }; 189 190 if (document.querySelector('.slideshow')) { 191 new Slideshow(document.querySelector('.slideshow')); 192 imagesLoaded('.slide__img', { background: true }, () => document.body.classList.remove('loading')); 193 } 194};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.