Skip to content

Instantly share code, notes, and snippets.

@FuruholmAnton
Last active July 5, 2022 16:33
Show Gist options
  • Save FuruholmAnton/6523269a34fc23a43cf42c7d861d0a16 to your computer and use it in GitHub Desktop.
Save FuruholmAnton/6523269a34fc23a43cf42c7d861d0a16 to your computer and use it in GitHub Desktop.
Animates a loading bar with GSAP
'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;
'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