Last active
July 5, 2022 16:33
-
-
Save FuruholmAnton/6523269a34fc23a43cf42c7d861d0a16 to your computer and use it in GitHub Desktop.
Animates a loading bar with GSAP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
import gsap from 'gsap'; | |
let animationDuration = () => { return (Math.sqrt(window.innerWidth) / 9)}; | |
let secoundStartValue; | |
let secoundStartFn = () => { return animationDuration() * 0.5 } | |
let colors = ['#daa9ae', '#98b8c1', '#d6deeb', '#acb198']; | |
/** | |
* IMPROVEMENTS: restart and stop instead of initialize and kill | |
*/ | |
/*---------- Library ----------*/ | |
class LoadingAnimation { | |
/** | |
* Sets the loading bars. | |
* If no element where sent to the constructor, it will look for the first 2 elements with class 'header-loading'. | |
* | |
* @param {Array} elements An array of elements | |
*/ | |
constructor(elements = [], secoundStart = 'default', ) { | |
/** | |
* If a single DOM element was sent, put it in an array | |
* Needs to be an array | |
*/ | |
if ( elements instanceof HTMLElement ) { | |
elements = [elements]; | |
} | |
else if ( !Array.isArray(elements) ) { | |
throw 'Param 1 needs to be an array'; | |
} | |
/* Allows numbers only */ | |
if ( /^-?\d+\.?\d*$/.test(secoundStart) ) { | |
secoundStartFn = () => { return secoundStart }; | |
} | |
else if (secoundStart == 'default') { | |
// secoundStartFn = animationDuration(); | |
} | |
else { | |
throw 'Param 2 needs to be a number'; | |
} | |
this.loadingBarTimeline = new TimelineMax({repeat: -1}); | |
let lines = []; | |
let bars = []; | |
let _this = this, | |
bar1, | |
bar2; | |
if (elements.length > 0) { | |
elements.forEach(function(element, index) { | |
bars.push(element); | |
}); | |
} | |
else { | |
bars[0] = document.querySelector('.header-loading'), | |
bars[1] = document.querySelectorAll('.header-loading')[1]; | |
} | |
bars.forEach(function(element, index) { | |
lines[index] = [].slice.call(bars[index].querySelectorAll('.header-loading__line')); | |
}); | |
this.colorIndex = 0; | |
this.count = 0; | |
this.bars = bars; | |
this.lines = lines; | |
} | |
start() { | |
// this.loadingBarTimeline.duration(6); | |
this.loadingBarTimeline.clear(); | |
this.loadingBarTimeline.timeScale(1); | |
this.loadingBarTimeline.repeat( -1 ); | |
let _this = this, | |
index = 0; | |
// this.bars.forEach(function(element, index) { | |
// _this.animate.call(_this, index); | |
// }); | |
for (index = 0; index < this.bars.length; index++) { | |
_this.animate.call(_this, index); | |
} | |
} | |
animate(barIndex) { | |
let _this = this; | |
let tweenOptionsFrom = { | |
x: '-101%' | |
}; | |
if (this.lines[barIndex] && this.lines[barIndex].length > 0) { | |
this.lines[barIndex].forEach(function(el, lineIndex) { | |
/** | |
* Time is backwords. | |
* The higher the number the earlier it starts | |
*/ | |
let timeOfLineStart = lineIndex * secoundStartFn(); | |
let timeOfBarStart = barIndex * animationDuration(); | |
let timeOfStart = '-=' + ( timeOfLineStart + timeOfBarStart); | |
/* Where the magic happens */ | |
_this.loadingBarTimeline.add( | |
TweenMax.fromTo(el, animationDuration(), tweenOptionsFrom, { | |
x: '100%', | |
ease: Power2.easeOut, | |
onRepeat: _this.tweenRepeat, | |
onRepeatScope: _this, | |
onRepeatParams: ['{self}'], | |
onStart: _this.tweenStart, | |
onStartScope: _this, | |
onStartParams: ['{self}'], | |
onUpdate: _this.setIndexHigh, | |
// onComplete: _this.pause | |
}), timeOfStart ); | |
}); | |
} | |
} | |
tweenRepeat(self) { | |
this.setIndexLow.call(this, self.target); | |
} | |
tweenStart(self) { | |
this.setIndexLow.call(this, self.target); | |
this.changeColor.call(this, self); | |
} | |
changeColor(Tween) { | |
Tween.target.style.backgroundColor = colors[this.colorIndex]; | |
this.count++; | |
if ( this.colorIndex < (colors.length - 1) ) { | |
if (this.count % 2 === 0) { | |
this.colorIndex++; | |
} | |
} else { | |
this.colorIndex = 0; | |
} | |
} | |
/** | |
* Set index to high towards animation end. So that it will always stay on top. | |
*/ | |
setIndexHigh() { | |
var time = Math.round(this.time() * 10) / 10; | |
if (time > 2) { | |
this.target.style['z-index'] = 10; | |
} | |
} | |
/** | |
* Set index to Low at the start. So that it will always stay on below. | |
*/ | |
setIndexLow(self) { | |
self.style['z-index'] = 9; | |
} | |
/** | |
* Stops the animation | |
* Is called externally | |
* | |
*/ | |
stop() { | |
this.loadingBarTimeline.repeat( 0 ); | |
let i = 0, | |
_this = this, | |
interval; | |
/* If second line has not been activated yet then remove it */ | |
let children = this.loadingBarTimeline.getChildren(false, true, true, 0); | |
children.forEach( function(tween, index) { | |
if (tween._active == false) { | |
tween.kill(); | |
} | |
}); | |
/* Gradually speeding ups by adding on interval */ | |
interval = setInterval(function(){ | |
let speed = 1 + (1 * i); | |
_this.loadingBarTimeline.timeScale(speed); | |
i++; | |
if (i == 10) { | |
clearInterval(interval); | |
} | |
}, 50); | |
} | |
pause() { | |
this.pause(0, true); | |
} | |
} | |
/*---------- EXPORT ----------*/ | |
module.exports = LoadingAnimation; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
import gsap from 'gsap'; | |
/** | |
* IMPROVEMENTS: restart and stop instead of initialize and kill | |
*/ | |
/*---------- Library ----------*/ | |
class LoadingAnimation { | |
/** | |
* Sets the loading bars. | |
* If no element where sent to the constructor, it will look for the first 2 elements with class 'header-loading'. | |
* | |
* @param {Array} elements An array of elements | |
*/ | |
constructor( elements = [] ) { | |
/** | |
* If a single DOM element was sent, put it in an array | |
* Needs to be an array | |
*/ | |
if ( elements instanceof HTMLElement ) { | |
elements = [elements]; | |
} | |
else if ( !Array.isArray(elements) ) { | |
console.warn('Param 1 needs to be an array'); | |
return; | |
} | |
let bars = [], | |
_this = this, | |
bar1, | |
bar2; | |
if (elements.length > 0) { | |
elements.forEach(function(element, index) { | |
bars.push(element); | |
}); | |
} | |
else { | |
bars[0] = document.querySelector('.header-loading'), | |
bars[1] = document.querySelectorAll('.header-loading')[1]; | |
} | |
this.tl = new TimelineMax({repeat:0}); | |
this.tl2 = new TimelineMax({repeat:0}); | |
this.colorIndex = 0; | |
this.count = 0; | |
this.bars = bars; | |
this.started = false; | |
} | |
start() { | |
let _this = this; | |
this.tl.fromTo(this.bars[0].querySelector('.header-loading__line'), 6, {xPercent:0}, { xPercent:60, ease:Power2.easeOut } ); | |
this.tl2.fromTo(this.bars[1].querySelector('.header-loading__line'), 6, {xPercent:0}, { xPercent:60, ease:Power2.easeOut } ); | |
this.started = true; | |
this.timeout = setTimeout(function() { | |
if (_this.started == true) { | |
_this.stop(); | |
} | |
}, (10 * 1000)); | |
} | |
clear (timeline, line) { | |
timeline.clear(); | |
line.style.transform = ''; | |
} | |
stop() { | |
let line1 = this.bars[0].querySelector('.header-loading__line'), | |
line2 = this.bars[1].querySelector('.header-loading__line'); | |
this.tl.clear(); | |
this.tl.to(line1, 0.6, { xPercent:100, ease:Power2.easeIn } ); | |
this.tl.to(line1, 0.4, { opacity: 0 } ); | |
this.tl.set(line1, { xPercent:0 } ); | |
this.tl.set(line1, { opacity: 1 } ); | |
this.tl.call(this.clear, [this.tl, line1]); | |
this.tl2.clear(); | |
this.tl2.to(line2, 0.6, { xPercent:100, ease:Power2.easeIn } ); | |
this.tl2.to(line2, 0.4, { opacity: 0 } ); | |
this.tl2.set(line2, { xPercent:0 } ); | |
this.tl2.set(line2, { opacity: 1 } ); | |
this.tl2.call(this.clear, [this.tl2, line2]); | |
if (this.timeout) { | |
clearTimeout(this.timeout); | |
} | |
this.started = false; | |
} | |
} | |
/*---------- EXPORT ----------*/ | |
module.exports = LoadingAnimation; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment