Repository: codrops/ImageTrailEffects Branch: master Commit: 5722f59a1ffb Files: 15 Total size: 64.2 KB Directory structure: gitextract_27kb7z8o/ ├── .gitignore ├── README.md ├── css/ │ └── base.css ├── index.html ├── index2.html ├── index3.html ├── index4.html ├── index5.html ├── index6.html └── js/ ├── demo.js ├── demo2.js ├── demo3.js ├── demo4.js ├── demo5.js └── demo6.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.DS_Store ================================================ FILE: README.md ================================================ # Image Trail Effects A set of effects for mouse-following image trails that show a random series of images. Inspired by the effect seen on [VLNC Studio](http://www.vlnc.studio/). ![Image Trail Effects](https://tympanus.net/codrops/wp-content/uploads/2019/08/ImageTrailEffects_featured.jpg) [Article on Codrops](https://tympanus.net/codrops/?p=42696) [Demo](https://tympanus.net/Development/ImageTrailEffects/) ## Credits - [TweenMax](https://greensock.com/tweenmax) by Greensock - [imagesLoaded](https://imagesloaded.desandro.com/) by Dave DeSandro - Images from [Unsplash.com](https://unsplash.com/) ## License This resource can be used freely if integrated or build upon in personal or commercial projects such as websites, web apps and web templates intended for sale. It is not allowed to take the resource "as-is" and sell it, redistribute, re-publish it, or sell "pluginized" versions of it. Free plugins built using this resource should have a visible mention and link to the original work. Always consider the licenses of all included libraries, scripts and images used. ## Misc Follow Codrops: [Twitter](http://www.twitter.com/codrops), [Facebook](http://www.facebook.com/codrops), [Google+](https://plus.google.com/101095823814290637419), [GitHub](https://github.com/codrops), [Pinterest](http://www.pinterest.com/codrops/), [Instagram](https://www.instagram.com/codropsss/) [© Codrops 2019](http://www.codrops.com) ================================================ FILE: css/base.css ================================================ article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;} *, *::after, *::before { box-sizing: border-box; } :root { font-size: 16px; } html, body { height: 100%; } body { --color-text: #262523; --color-bg: #efece5; --color-link: #eca324; --color-link-hover: #262523; --color-title: #ffffff; --img-maxwidth: 250px; --blendmode-title: difference; --filter-img: none; color: var(--color-text); background-color: var(--color-bg); font-family: quiroh, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .demo-2 { --color-text: #ffffff; --color-bg: #151413; --color-link: #d02d55; --color-link-hover: #ffffff; --color-title: #232323; } .demo-3 { --color-text: #320065; --color-bg: #d02d55; --color-link: #ffffff; --color-link-hover: #000000; --color-title: #320065; --filter-img: sepia(1) saturate(1) contrast(180%) brightness(80%) hue-rotate(295deg); } .demo-4 { --color-text: #000000; --color-bg: #e0fafb; --color-link: #ff3a7e; --color-link-hover: #000000; --color-title: #f9dae5; } .demo-5 { --color-text: #ffffff; --color-bg: #485656; --color-link: #000000; --color-link-hover: #ffffff; --color-title: #444c4c; --filter-img: hue-rotate(70deg) contrast(70%); } .demo-6 { --color-text: #fff; --color-bg: #000; --color-link: #f0f0f0; --color-link-hover: #fff; --color-title: #fff; --img-maxwidth: none; --blendmode-title: overlay; } /* Page Loader */ .js .loading::before { content: ''; position: fixed; z-index: 100000; top: 0; left: 0; width: 100%; height: 100%; background: var(--color-bg); } .js .loading::after { content: ''; position: fixed; z-index: 100000; top: 50%; left: 50%; width: 60px; height: 60px; margin: -30px 0 0 -30px; pointer-events: none; border-radius: 50%; opacity: 0.4; background: var(--color-link); animation: loaderAnim 0.7s linear infinite alternate forwards; } @keyframes loaderAnim { to { opacity: 1; transform: scale3d(0.5,0.5,1); } } a { text-decoration: none; color: var(--color-link); } a:hover, a:focus { color: var(--color-link-hover); outline: 0; } .message { padding: 1rem; color: var(--color-bg); background: var(--color-text); text-align: center; font-weight: bold; } .frame { padding: 1rem; text-align: center; position: relative; z-index: 1000; grid-area: 1 / 1 / 2 / 2; align-self: start; } .frame__title { font-size: 1rem; margin: 0 0 1rem; } .frame__links { display: inline; } .frame__github, .frame__links a:not(:last-child), .frame__demos a:not(:last-child) { margin-right: 1rem; } .frame__demos { margin: 1rem 0; } .frame__demo--current, .frame__demo--current:hover { color: var(--color-text); text-decoration: line-through; letter-spacing: 40px; } .frame__pagetitle { margin: 3rem 0 0 0; } .frame__pagetitle span { display: block; font-weight: normal; font-size: 0.85rem; } .frame__pagetitle span::before { content: '\2015 '; } .content { height: 300px; position: relative; display: flex; justify-content: center; align-items: center; isolation: isolate; } .content__title { font-family: forma-djr-display, sans-serif; font-weight: 700; position: relative; z-index: 10000; font-size: 27vw; mix-blend-mode: var(--blendmode-title); -webkit-text-stroke: 2px var(--color-title); text-stroke: 2px var(--color-title); -webkit-text-fill-color: transparent; text-fill-color: transparent; color: transparent; pointer-events: none; } .content__img { max-width: var(--img-maxwidth); position: absolute; top: 0; left: 0; opacity: 0; will-change: transform; filter: var(--filter-img); } .content__img--full { width: 100%; height: 100%; background-size: cover; } @media screen and (min-width: 53em) { :root { font-size: 18px; } body { overflow: hidden; } .message { display: none; } .frame { position: fixed; text-align: left; z-index: 10000; top: 0; left: 0; display: grid; align-content: space-between; width: 100%; max-width: none; height: 100vh; padding: 2rem; pointer-events: none; grid-template-columns: 75% 25%; grid-template-rows: auto auto auto; grid-template-areas: 'pagetitle github' '... ...' 'title ...'; } .frame__pagetitle { grid-area: pagetitle; margin: 0; } .frame__title-wrap { grid-area: title; display: flex; } .frame__title { margin: 0; font-weight: normal; } .frame__links { padding: 0; margin: 0 0 0 3rem; justify-self: end; } .frame__demos { margin: 0 0 0 3rem; } .frame__github { grid-area: github; justify-self: end; } .frame a { pointer-events: auto; } .content { height: 100vh; overflow: hidden; } } ================================================ FILE: index.html ================================================ Image Trail Effects | Demo 1 | Codrops
Hover effect — please view on desktop.

Image Trail Effects

1 2 3 4 5 6
Github

Camille Moulin Personality Stylist

Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image

llssmmhh

================================================ FILE: index2.html ================================================ Image Trail Effects | Demo 2 | Codrops
Hover effect — please view on desktop.

Image Trail Effects

1 2 3 4 5 6
Github

Camille Moulin Personality Stylist

Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image

lllooolllzzz

================================================ FILE: index3.html ================================================ Image Trail Effects | Demo 3 | Codrops
Hover effect — please view on desktop.

Image Trail Effects

1 2 3 4 5 6
Github

Camille Moulin Personality Stylist

Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image

oommgg

================================================ FILE: index4.html ================================================ Image Trail Effects | Demo 4 | Codrops
Hover effect — please view on desktop.

Image Trail Effects

1 2 3 4 5 6
Github

Camille Moulin Personality Stylist

Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image

bingbong

================================================ FILE: index5.html ================================================ Image Trail Effects | Demo 5 | Codrops
Hover effect — please view on desktop.

Image Trail Effects

1 2 3 4 5 6
Github

Camille Moulin Personality Stylist

Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image Some image

duhsduh

================================================ FILE: index6.html ================================================ Image Trail Effects | Demo 6 | Codrops
Hover effect — please view on desktop.

Image Trail Effects

1 2 3 4 5 6
Github

Camille Moulin Personality Stylist

xmxmxmx

================================================ FILE: js/demo.js ================================================ /** * demo.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2019, Codrops * http://www.codrops.com */ { // body element const body = document.body; // helper functions const MathUtils = { // linear interpolation lerp: (a, b, n) => (1 - n) * a + n * b, // distance between two points distance: (x1,y1,x2,y2) => Math.hypot(x2-x1, y2-y1) } // get the mouse position const getMousePos = (ev) => { let posx = 0; let posy = 0; if (!ev) ev = window.event; if (ev.pageX || ev.pageY) { posx = ev.pageX; posy = ev.pageY; } else if (ev.clientX || ev.clientY) { posx = ev.clientX + body.scrollLeft + docEl.scrollLeft; posy = ev.clientY + body.scrollTop + docEl.scrollTop; } return {x: posx, y: posy}; } // mousePos: current mouse position // cacheMousePos: previous mouse position // lastMousePos: last last recorded mouse position (at the time the last image was shown) let mousePos = lastMousePos = cacheMousePos = {x: 0, y: 0}; // update the mouse position window.addEventListener('mousemove', ev => mousePos = getMousePos(ev)); // gets the distance from the current mouse position to the last recorded mouse position const getMouseDistance = () => MathUtils.distance(mousePos.x,mousePos.y,lastMousePos.x,lastMousePos.y); class Image { constructor(el) { this.DOM = {el: el}; // image deafult styles this.defaultStyle = { scale: 1, x: 0, y: 0, opacity: 0 }; // get sizes/position this.getRect(); // init/bind events this.initEvents(); } initEvents() { // on resize get updated sizes/position window.addEventListener('resize', () => this.resize()); } resize() { // reset styles TweenMax.set(this.DOM.el, this.defaultStyle); // get sizes/position this.getRect(); } getRect() { this.rect = this.DOM.el.getBoundingClientRect(); } isActive() { // check if image is animating or if it's visible return TweenMax.isTweening(this.DOM.el) || this.DOM.el.style.opacity != 0; } } class ImageTrail { constructor() { // images container this.DOM = {content: document.querySelector('.content')}; // array of Image objs, one per image element this.images = []; [...this.DOM.content.querySelectorAll('img')].forEach(img => this.images.push(new Image(img))); // total number of images this.imagesTotal = this.images.length; // upcoming image index this.imgPosition = 0; // zIndex value to apply to the upcoming image this.zIndexVal = 1; // mouse distance required to show the next image this.threshold = 100; // render the images requestAnimationFrame(() => this.render()); } render() { // get distance between the current mouse position and the position of the previous image let distance = getMouseDistance(); // cache previous mouse position cacheMousePos.x = MathUtils.lerp(cacheMousePos.x || mousePos.x, mousePos.x, 0.1); cacheMousePos.y = MathUtils.lerp(cacheMousePos.y || mousePos.y, mousePos.y, 0.1); // if the mouse moved more than [this.threshold] then show the next image if ( distance > this.threshold ) { this.showNextImage(); ++this.zIndexVal; this.imgPosition = this.imgPosition < this.imagesTotal-1 ? this.imgPosition+1 : 0; lastMousePos = mousePos; } // check when mousemove stops and all images are inactive (not visible and not animating) let isIdle = true; for (let img of this.images) { if ( img.isActive() ) { isIdle = false; break; } } // reset z-index initial value if ( isIdle && this.zIndexVal !== 1 ) { this.zIndexVal = 1; } // loop.. requestAnimationFrame(() => this.render()); } showNextImage() { // show image at position [this.imgPosition] const img = this.images[this.imgPosition]; // kill any tween on the image TweenMax.killTweensOf(img.DOM.el); new TimelineMax() // show the image .set(img.DOM.el, { startAt: {opacity: 0, scale: 1}, opacity: 1, scale: 1, zIndex: this.zIndexVal, x: cacheMousePos.x - img.rect.width/2, y: cacheMousePos.y - img.rect.height/2 }, 0) // animate position .to(img.DOM.el, 0.9, { ease: Expo.easeOut, x: mousePos.x - img.rect.width/2, y: mousePos.y - img.rect.height/2 }, 0) // then make it disappear .to(img.DOM.el, 1, { ease: Power1.easeOut, opacity: 0 }, 0.4) // scale down the image .to(img.DOM.el, 1, { ease: Quint.easeOut, scale: 0.2 }, 0.4); } } /***********************************/ /********** Preload stuff **********/ // Preload images const preloadImages = () => { return new Promise((resolve, reject) => { imagesLoaded(document.querySelectorAll('.content__img'), resolve); }); }; // And then.. preloadImages().then(() => { // Remove the loader document.body.classList.remove('loading'); new ImageTrail(); }); } ================================================ FILE: js/demo2.js ================================================ /** * demo2.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2019, Codrops * http://www.codrops.com */ { // body element const body = document.body; // helper functions const MathUtils = { // linear interpolation lerp: (a, b, n) => (1 - n) * a + n * b, // distance between two points distance: (x1,y1,x2,y2) => Math.hypot(x2-x1, y2-y1) } // get the mouse position const getMousePos = (ev) => { let posx = 0; let posy = 0; if (!ev) ev = window.event; if (ev.pageX || ev.pageY) { posx = ev.pageX; posy = ev.pageY; } else if (ev.clientX || ev.clientY) { posx = ev.clientX + body.scrollLeft + docEl.scrollLeft; posy = ev.clientY + body.scrollTop + docEl.scrollTop; } return {x: posx, y: posy}; } // mousePos: current mouse position // cacheMousePos: previous mouse position // lastMousePos: last last recorded mouse position (at the time the last image was shown) let mousePos = lastMousePos = cacheMousePos = {x: 0, y: 0}; // update the mouse position window.addEventListener('mousemove', ev => mousePos = getMousePos(ev)); // gets the distance from the current mouse position to the last recorded mouse position const getMouseDistance = () => MathUtils.distance(mousePos.x,mousePos.y,lastMousePos.x,lastMousePos.y); class Image { constructor(el) { this.DOM = {el: el}; // image deafult styles this.defaultStyle = { x: 0, y: 0, opacity: 0 }; // get sizes/position this.getRect(); // init/bind events this.initEvents(); } initEvents() { // on resize get updated sizes/position window.addEventListener('resize', () => this.resize()); } resize() { // reset styles TweenMax.set(this.DOM.el, this.defaultStyle); // get sizes/position this.getRect(); } getRect() { this.rect = this.DOM.el.getBoundingClientRect(); } isActive() { // check if image is animating or if it's visible return TweenMax.isTweening(this.DOM.el) || this.DOM.el.style.opacity != 0; } } class ImageTrail { constructor() { // images container this.DOM = {content: document.querySelector('.content')}; // array of Image objs, one per image element this.images = []; [...this.DOM.content.querySelectorAll('img')].forEach(img => this.images.push(new Image(img))); // total number of images this.imagesTotal = this.images.length; // upcoming image index this.imgPosition = 0; // zIndex value to apply to the upcoming image this.zIndexVal = 1; // mouse distance required to show the next image this.threshold = 100; // render the images requestAnimationFrame(() => this.render()); } render() { // get distance between the current mouse position and the position of the previous image let distance = getMouseDistance(); // cache previous mouse position cacheMousePos.x = MathUtils.lerp(cacheMousePos.x || mousePos.x, mousePos.x, 0.1); cacheMousePos.y = MathUtils.lerp(cacheMousePos.y || mousePos.y, mousePos.y, 0.1); // if the mouse moved more than [this.threshold] then show the next image if ( distance > this.threshold ) { this.showNextImage(); ++this.zIndexVal; this.imgPosition = this.imgPosition < this.imagesTotal-1 ? this.imgPosition+1 : 0; lastMousePos = mousePos; } // check when mousemove stops and all images are inactive (not visible and not animating) let isIdle = true; for (let img of this.images) { if ( img.isActive() ) { isIdle = false; break; } } // reset z-index initial value if ( isIdle && this.zIndexVal !== 1 ) { this.zIndexVal = 1; } // loop.. requestAnimationFrame(() => this.render()); } showNextImage() { // show image at position [this.imgPosition] const img = this.images[this.imgPosition]; // kill any tween on the image TweenMax.killTweensOf(img.DOM.el); new TimelineMax() // show the image .set(img.DOM.el, { startAt: {opacity: 0}, opacity: 1, scale: 1, zIndex: this.zIndexVal, x: cacheMousePos.x - img.rect.width/2, y: cacheMousePos.y - img.rect.height/2 }, 0) // animate position .to(img.DOM.el, 1.8, { ease: Expo.easeOut, x: mousePos.x - img.rect.width/2, y: mousePos.y - img.rect.height/2 }, 0) // then make it disappear .to(img.DOM.el, 0.8, { ease: Power1.easeOut, opacity: 0 }, 0.8) // scale down the image .to(img.DOM.el, 0.8, { ease: Quint.easeInOut, scale: 2 }, 0.8); } } /***********************************/ /********** Preload stuff **********/ // Preload images const preloadImages = () => { return new Promise((resolve, reject) => { imagesLoaded(document.querySelectorAll('.content__img'), resolve); }); }; // And then.. preloadImages().then(() => { // Remove the loader document.body.classList.remove('loading'); new ImageTrail(); }); } ================================================ FILE: js/demo3.js ================================================ /** * demo3.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2019, Codrops * http://www.codrops.com */ { // body element const body = document.body; // helper functions const MathUtils = { // linear interpolation lerp: (a, b, n) => (1 - n) * a + n * b, // distance between two points distance: (x1,y1,x2,y2) => Math.hypot(x2-x1, y2-y1) } // calculate the viewport size let winsize; const calcWinsize = () => winsize = {width: window.innerWidth, height: window.innerHeight}; calcWinsize(); // and recalculate on resize window.addEventListener('resize', calcWinsize); // get the mouse position const getMousePos = (ev) => { let posx = 0; let posy = 0; if (!ev) ev = window.event; if (ev.pageX || ev.pageY) { posx = ev.pageX; posy = ev.pageY; } else if (ev.clientX || ev.clientY) { posx = ev.clientX + body.scrollLeft + docEl.scrollLeft; posy = ev.clientY + body.scrollTop + docEl.scrollTop; } return {x: posx, y: posy}; } // mousePos: current mouse position // cacheMousePos: previous mouse position // lastMousePos: last last recorded mouse position (at the time the last image was shown) let mousePos = lastMousePos = cacheMousePos = {x: 0, y: 0}; // update the mouse position window.addEventListener('mousemove', ev => mousePos = getMousePos(ev)); // gets the distance from the current mouse position to the last recorded mouse position const getMouseDistance = () => MathUtils.distance(mousePos.x,mousePos.y,lastMousePos.x,lastMousePos.y); class Image { constructor(el) { this.DOM = {el: el}; // image deafult styles this.defaultStyle = { x: 0, y: 0, opacity: 0 }; // get sizes/position this.getRect(); // init/bind events this.initEvents(); } initEvents() { // on resize get updated sizes/position window.addEventListener('resize', () => this.resize()); } resize() { // reset styles TweenMax.set(this.DOM.el, this.defaultStyle); // get sizes/position this.getRect(); } getRect() { this.rect = this.DOM.el.getBoundingClientRect(); } isActive() { // check if image is animating or if it's visible return TweenMax.isTweening(this.DOM.el) || this.DOM.el.style.opacity != 0; } } class ImageTrail { constructor() { // images container this.DOM = {content: document.querySelector('.content')}; // array of Image objs, one per image element this.images = []; [...this.DOM.content.querySelectorAll('img')].forEach(img => this.images.push(new Image(img))); // total number of images this.imagesTotal = this.images.length; // upcoming image index this.imgPosition = 0; // zIndex value to apply to the upcoming image this.zIndexVal = 1; // mouse distance required to show the next image this.threshold = 50; // render the images requestAnimationFrame(() => this.render()); } render() { // get distance between the current mouse position and the position of the previous image let distance = getMouseDistance(); // cache previous mouse position cacheMousePos.x = MathUtils.lerp(cacheMousePos.x || mousePos.x, mousePos.x, 0.1); cacheMousePos.y = MathUtils.lerp(cacheMousePos.y || mousePos.y, mousePos.y, 0.1); // if the mouse moved more than [this.threshold] then show the next image if ( distance > this.threshold ) { this.showNextImage(); ++this.zIndexVal; this.imgPosition = this.imgPosition < this.imagesTotal-1 ? this.imgPosition+1 : 0; lastMousePos = mousePos; } // check when mousemove stops and all images are inactive (not visible and not animating) let isIdle = true; for (let img of this.images) { if ( img.isActive() ) { isIdle = false; break; } } // reset z-index initial value if ( isIdle && this.zIndexVal !== 1 ) { this.zIndexVal = 1; } // loop.. requestAnimationFrame(() => this.render()); } showNextImage() { // show image at position [this.imgPosition] const img = this.images[this.imgPosition]; // kill any tween on the image TweenMax.killTweensOf(img.DOM.el); new TimelineMax() // show the image .set(img.DOM.el, { startAt: {opacity: 0}, opacity: 1, zIndex: this.zIndexVal, x: cacheMousePos.x - img.rect.width/2, y: cacheMousePos.y - img.rect.height/2 }, 0) // animate position .to(img.DOM.el, 1.6, { ease: Expo.easeOut, x: mousePos.x - img.rect.width/2, y: mousePos.y - img.rect.height/2 }, 0) // then make it disappear .to(img.DOM.el, 1, { ease: Power1.easeOut, opacity: 0 }, 0.4) // translate down the image .to(img.DOM.el, 1, { ease: Quint.easeInOut, y: `+=${winsize.height + img.rect.height/2}` }, 0.4); } } /***********************************/ /********** Preload stuff **********/ // Preload images const preloadImages = () => { return new Promise((resolve, reject) => { imagesLoaded(document.querySelectorAll('.content__img'), resolve); }); }; // And then.. preloadImages().then(() => { // Remove the loader document.body.classList.remove('loading'); new ImageTrail(); }); } ================================================ FILE: js/demo4.js ================================================ /** * demo4.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2019, Codrops * http://www.codrops.com */ { // body element const body = document.body; // helper functions const MathUtils = { // linear interpolation lerp: (a, b, n) => (1 - n) * a + n * b, // distance between two points distance: (x1,y1,x2,y2) => Math.hypot(x2-x1, y2-y1), // Random float getRandomFloat: (min, max) => (Math.random() * (max - min) + min).toFixed(2) } // calculate the viewport size let winsize; const calcWinsize = () => winsize = {width: window.innerWidth, height: window.innerHeight}; calcWinsize(); // and recalculate on resize window.addEventListener('resize', calcWinsize); // get the mouse position const getMousePos = (ev) => { let posx = 0; let posy = 0; if (!ev) ev = window.event; if (ev.pageX || ev.pageY) { posx = ev.pageX; posy = ev.pageY; } else if (ev.clientX || ev.clientY) { posx = ev.clientX + body.scrollLeft + docEl.scrollLeft; posy = ev.clientY + body.scrollTop + docEl.scrollTop; } return {x: posx, y: posy}; } // mousePos: current mouse position // cacheMousePos: previous mouse position // lastMousePos: last last recorded mouse position (at the time the last image was shown) let mousePos = lastMousePos = cacheMousePos = {x: 0, y: 0}; // update the mouse position window.addEventListener('mousemove', ev => mousePos = getMousePos(ev)); // gets the distance from the current mouse position to the last recorded mouse position const getMouseDistance = () => MathUtils.distance(mousePos.x,mousePos.y,lastMousePos.x,lastMousePos.y); class Image { constructor(el) { this.DOM = {el: el}; // image deafult styles this.defaultStyle = { rotation: 0, x: 0, y: 0, opacity: 0 }; // get sizes/position this.getRect(); // init/bind events this.initEvents(); } initEvents() { // on resize get updated sizes/position window.addEventListener('resize', () => this.resize()); } resize() { // reset styles TweenMax.set(this.DOM.el, this.defaultStyle); // get sizes/position this.getRect(); } getRect() { this.rect = this.DOM.el.getBoundingClientRect(); } isActive() { // check if image is animating or if it's visible return TweenMax.isTweening(this.DOM.el) || this.DOM.el.style.opacity != 0; } setRatio() { this.DOM.el.style.setProperty('--img-maxwidth', `${MathUtils.getRandomFloat(150,350)}px`); // get sizes/position this.getRect(); } } class ImageTrail { constructor() { // images container this.DOM = {content: document.querySelector('.content')}; // array of Image objs, one per image element this.images = []; [...this.DOM.content.querySelectorAll('img')].forEach(img => this.images.push(new Image(img))); // total number of images this.imagesTotal = this.images.length; // upcoming image index this.imgPosition = 0; // zIndex value to apply to the upcoming image this.zIndexVal = 1; // mouse distance required to show the next image this.threshold = 80; // render the images requestAnimationFrame(() => this.render()); } render() { // get distance between the current mouse position and the position of the previous image let distance = getMouseDistance(); // cache previous mouse position cacheMousePos.x = MathUtils.lerp(cacheMousePos.x || mousePos.x, mousePos.x, 0.1); cacheMousePos.y = MathUtils.lerp(cacheMousePos.y || mousePos.y, mousePos.y, 0.1); // if the mouse moved more than [this.threshold] then show the next image if ( distance > this.threshold ) { this.showNextImage(); ++this.zIndexVal; this.imgPosition = this.imgPosition < this.imagesTotal-1 ? this.imgPosition+1 : 0; lastMousePos = mousePos; } // check when mousemove stops and all images are inactive (not visible and not animating) let isIdle = true; for (let img of this.images) { if ( img.isActive() ) { isIdle = false; break; } } // reset z-index initial value if ( isIdle && this.zIndexVal !== 1 ) { this.zIndexVal = 1; } // loop.. requestAnimationFrame(() => this.render()); } showNextImage() { // show image at position [this.imgPosition] const img = this.images[this.imgPosition]; img.setRatio(); // kill any tween on the image TweenMax.killTweensOf(img.DOM.el); new TimelineMax() // show the image .set(img.DOM.el, { startAt: {opacity: 0}, opacity: 1, rotation: 0, zIndex: this.zIndexVal, x: cacheMousePos.x - img.rect.width/2, y: cacheMousePos.y - img.rect.height/2 }, 0) // animate position .to(img.DOM.el, 1.6, { ease: Expo.easeOut, x: mousePos.x - img.rect.width/2, y: mousePos.y - img.rect.height/2 }, 0) // then make it disappear .to(img.DOM.el, 0.8, { ease: Power1.easeOut, opacity: 0 }, 0.6) // translate down the image .to(img.DOM.el, 1, { ease: Quint.easeOut, x: `+=${MathUtils.getRandomFloat(-1*(winsize.width + img.rect.width/2), winsize.width + img.rect.width/2)}`, y: `+=${MathUtils.getRandomFloat(-1*(winsize.height + img.rect.height/2), winsize.height + img.rect.height/2)}`, rotation: MathUtils.getRandomFloat(-40,40) }, 0.6); } } /***********************************/ /********** Preload stuff **********/ // Preload images const preloadImages = () => { return new Promise((resolve, reject) => { imagesLoaded(document.querySelectorAll('.content__img'), resolve); }); }; // And then.. preloadImages().then(() => { // Remove the loader document.body.classList.remove('loading'); new ImageTrail(); }); } ================================================ FILE: js/demo5.js ================================================ /** * demo5.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2019, Codrops * http://www.codrops.com */ { // body element const body = document.body; // helper functions const MathUtils = { // linear interpolation lerp: (a, b, n) => (1 - n) * a + n * b, // distance between two points distance: (x1,y1,x2,y2) => Math.hypot(x2-x1, y2-y1), // Random float getRandomFloat: (min, max) => (Math.random() * (max - min) + min).toFixed(2) } // calculate the viewport size let winsize; const calcWinsize = () => winsize = {width: window.innerWidth, height: window.innerHeight}; calcWinsize(); // and recalculate on resize window.addEventListener('resize', calcWinsize); // get the mouse position const getMousePos = (ev) => { let posx = 0; let posy = 0; if (!ev) ev = window.event; if (ev.pageX || ev.pageY) { posx = ev.pageX; posy = ev.pageY; } else if (ev.clientX || ev.clientY) { posx = ev.clientX + body.scrollLeft + docEl.scrollLeft; posy = ev.clientY + body.scrollTop + docEl.scrollTop; } return {x: posx, y: posy}; } // mousePos: current mouse position // cacheMousePos: previous mouse position // lastMousePos: last last recorded mouse position (at the time the last image was shown) let mousePos = lastMousePos = cacheMousePos = {x: 0, y: 0}; // update the mouse position window.addEventListener('mousemove', ev => mousePos = getMousePos(ev)); // gets the distance from the current mouse position to the last recorded mouse position const getMouseDistance = () => MathUtils.distance(mousePos.x,mousePos.y,lastMousePos.x,lastMousePos.y); class Image { constructor(el) { this.DOM = {el: el}; // image deafult styles this.defaultStyle = { scaleX: 1, scaleY: 1, x: 0, y: 0, opacity: 0 }; // get sizes/position this.getRect(); // init/bind events this.initEvents(); } initEvents() { // on resize get updated sizes/position window.addEventListener('resize', () => this.resize()); } resize() { // reset styles TweenMax.set(this.DOM.el, this.defaultStyle); // get sizes/position this.getRect(); } getRect() { this.rect = this.DOM.el.getBoundingClientRect(); } isActive() { // check if image is animating or if it's visible return TweenMax.isTweening(this.DOM.el) || this.DOM.el.style.opacity != 0; } } class ImageTrail { constructor() { // images container this.DOM = {content: document.querySelector('.content')}; // array of Image objs, one per image element this.images = []; [...this.DOM.content.querySelectorAll('img')].forEach(img => this.images.push(new Image(img))); // total number of images this.imagesTotal = this.images.length; // upcoming image index this.imgPosition = 0; // zIndex value to apply to the upcoming image this.zIndexVal = 1; // mouse distance required to show the next image this.threshold = 100; // render the images requestAnimationFrame(() => this.render()); } render() { // get distance between the current mouse position and the position of the previous image let distance = getMouseDistance(); // cache previous mouse position cacheMousePos.x = MathUtils.lerp(cacheMousePos.x || mousePos.x, mousePos.x, 0.1); cacheMousePos.y = MathUtils.lerp(cacheMousePos.y || mousePos.y, mousePos.y, 0.1); // if the mouse moved more than [this.threshold] then show the next image if ( distance > this.threshold ) { this.showNextImage(); ++this.zIndexVal; this.imgPosition = this.imgPosition < this.imagesTotal-1 ? this.imgPosition+1 : 0; lastMousePos = mousePos; } // check when mousemove stops and all images are inactive (not visible and not animating) let isIdle = true; for (let img of this.images) { if ( img.isActive() ) { isIdle = false; break; } } // reset z-index initial value if ( isIdle && this.zIndexVal !== 1 ) { this.zIndexVal = 1; } // loop.. requestAnimationFrame(() => this.render()); } showNextImage() { // show image at position [this.imgPosition] const img = this.images[this.imgPosition]; // kill any tween on the image TweenMax.killTweensOf(img.DOM.el); new TimelineMax() // show the image .set(img.DOM.el, { startAt: {opacity: 0}, opacity: 1, scaleX: 1, scaleY: 1, zIndex: this.zIndexVal, x: mousePos.x - img.rect.width/2, y: mousePos.y - img.rect.height/2, transformOrigin: '50% -10%' }, 0) // then make it disappear .to(img.DOM.el, 0.5, { ease: Power1.easeOut, opacity: 0 }, 0.4) // translate down the image .to(img.DOM.el, 0.2, { ease: Quad.easeIn, scaleX: 0.5, scaleY: 2 }, 0.4) // translate down the image .to(img.DOM.el, 0.5, { ease: Expo.easeOut, scaleX: 0.7, scaleY: 1.7, y: `+=${MathUtils.getRandomFloat(winsize.height/2,winsize.height)}` }, 0.6); } } /***********************************/ /********** Preload stuff **********/ // Preload images const preloadImages = () => { return new Promise((resolve, reject) => { imagesLoaded(document.querySelectorAll('.content__img'), resolve); }); }; // And then.. preloadImages().then(() => { // Remove the loader document.body.classList.remove('loading'); new ImageTrail(); }); } ================================================ FILE: js/demo6.js ================================================ /** * demo6.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2019, Codrops * http://www.codrops.com */ { // body element const body = document.body; // helper functions const MathUtils = { // linear interpolation lerp: (a, b, n) => (1 - n) * a + n * b, // distance between two points distance: (x1,y1,x2,y2) => Math.hypot(x2-x1, y2-y1) } // get the mouse position const getMousePos = (ev) => { let posx = 0; let posy = 0; if (!ev) ev = window.event; if (ev.pageX || ev.pageY) { posx = ev.pageX; posy = ev.pageY; } else if (ev.clientX || ev.clientY) { posx = ev.clientX + body.scrollLeft + docEl.scrollLeft; posy = ev.clientY + body.scrollTop + docEl.scrollTop; } return {x: posx, y: posy}; } // mousePos: current mouse position // lastMousePos: last last recorded mouse position (at the time the last image was shown) let mousePos = lastMousePos = {x: 0, y: 0}; // update the mouse position window.addEventListener('mousemove', ev => mousePos = getMousePos(ev)); // gets the distance from the current mouse position to the last recorded mouse position const getMouseDistance = () => MathUtils.distance(mousePos.x,mousePos.y,lastMousePos.x,lastMousePos.y); class Image { constructor(el) { this.DOM = {el: el}; // image deafult styles this.defaultStyle = { x: 0, y: 0, opacity: 1 }; // get sizes/position this.getRect(); // init/bind events this.initEvents(); } initEvents() { // on resize get updated sizes/position window.addEventListener('resize', () => this.resize()); } resize() { // reset styles TweenMax.set(this.DOM.el, this.defaultStyle); // get sizes/position this.getRect(); } getRect() { this.rect = this.DOM.el.getBoundingClientRect(); } } class ImageTrail { constructor() { // images container this.DOM = {content: document.querySelector('.content')}; // array of Image objs, one per image element this.images = []; [...this.DOM.content.querySelectorAll('div.content__img')].forEach(img => this.images.push(new Image(img))); // total number of images this.imagesTotal = this.images.length; // upcoming image index this.imgPosition = 0; // zIndex value to apply to the upcoming image this.zIndexVal = 1; // mouse distance required to show the next image this.threshold = 100; this.showNextImage(); // render the images requestAnimationFrame(() => this.render()); } render() { // get distance between the current mouse position and the position of the previous image let distance = getMouseDistance(); // if the mouse moved more than [this.threshold] then show the next image if ( distance > this.threshold ) { this.showNextImage(); } // loop.. requestAnimationFrame(() => this.render()); } showNextImage() { // show image at position [this.imgPosition] const img = this.images[this.imgPosition]; // kill any tween on the image TweenMax.killTweensOf(img.DOM.el); new TimelineMax() // show the image .set(img.DOM.el, { opacity: 1, x: mousePos.x > lastMousePos.x ? 100 : -100, zIndex: this.zIndexVal }, 0) // animate position .to(img.DOM.el, 1.2, { ease: Expo.easeOut, x: 0 }, 0); ++this.zIndexVal; this.imgPosition = this.imgPosition < this.imagesTotal-1 ? this.imgPosition+1 : 0; lastMousePos = mousePos; } } /***********************************/ /********** Preload stuff **********/ // Preload images const preloadImages = () => { return new Promise((resolve, reject) => { imagesLoaded(document.querySelectorAll('.content__img'), {background: true}, resolve); }); }; // And then.. preloadImages().then(() => { // Remove the loader document.body.classList.remove('loading'); new ImageTrail(); }); }