<p><strong>Click to open/close the preloader.</strong><br>Completely customizable (colors, radius, number of dots, size, etc.).<br>One JavaScript call opens or closes the preloader elegantly.</p>
xxxxxxxxxx
/* none of this CSS is necessary for the preloader */
body {
background-color: #ccc;
font-family: sans-serif;
font-size: 18px;
}
p {
position: fixed;
bottom: 0;
text-align: center;
width: 100%;
padding: 0 10px 4px 10px;
}
//Pure JS, completely customizable preloader from GreenSock.
//Once you create an instance like var preloader = new GSPreloader(), call preloader.active(true) to open it, preloader.active(false) to close it, and preloader.active() to get the current status. Only requires TweenLite and CSSPlugin (http://www.greensock.com/gsap/)
var preloader = new GSPreloader({
radius:42,
dotSize:15,
dotCount:10,
colors:["#61AC27","#555","purple","#FF6600"], //have as many or as few colors as you want.
boxOpacity:0.2,
boxBorder:"1px solid #AAA",
animationOffset: 1.8, //jump 1.8 seconds into the animation for a more active part of the spinning initially (just looks a bit better in my opinion)
});
//open the preloader
preloader.active(true);
//for testing: click the window to toggle open/close the preloader
document.onclick = document.ontouchstart = function() {
preloader.active( !preloader.active() );
};
//this is the whole preloader class/function
function GSPreloader(options) {
options = options || {};
var parent = options.parent || document.body,
element = this.element = document.createElement("div"),
radius = options.radius || 42,
dotSize = options.dotSize || 15,
animationOffset = options.animationOffset || 1.8, //jumps to a more active part of the animation initially (just looks cooler especially when the preloader isn't displayed for very long)
createDot = function(rotation) {
var dot = document.createElement("div");
element.appendChild(dot);
TweenLite.set(dot, {width:dotSize, height:dotSize, transformOrigin:(-radius + "px 0px"), x: radius, backgroundColor:colors[colors.length-1], borderRadius:"50%", force3D:true, position:"absolute", rotation:rotation});
dot.className = options.dotClass || "preloader-dot";
return dot;
},
i = options.dotCount || 10,
rotationIncrement = 360 / i,
colors = options.colors || ["#61AC27","black"],
animation = new TimelineLite({paused:true}),
dots = [],
isActive = false,
box = document.createElement("div"),
tl, dot, closingAnimation, j;
colors.push(colors.shift());
//setup background box
TweenLite.set(box, {width: radius * 2 + 70, height: radius * 2 + 70, borderRadius:"14px", backgroundColor:options.boxColor || "white", border: options.boxBorder || "1px solid #AAA", position:"absolute", xPercent:-50, yPercent:-50, opacity:((options.boxOpacity != null) ? options.boxOpacity : 0.3)});
box.className = options.boxClass || "preloader-box";
element.appendChild(box);
parent.appendChild(element);
TweenLite.set(element, {position:"fixed", top:"45%", left:"50%", perspective:600, overflow:"visible", zIndex:2000});
animation.from(box, 0.1, {opacity:0, scale:0.1, ease:Power1.easeOut}, animationOffset);
while (--i > -1) {
dot = createDot(i * rotationIncrement);
dots.unshift(dot);
animation.from(dot, 0.1, {scale:0.01, opacity:0, ease:Power1.easeOut}, animationOffset);
//tuck the repeating parts of the animation into a nested TimelineMax (the intro shouldn't be repeated)
tl = new TimelineMax({repeat:-1, repeatDelay:0.25});
for (j = 0; j < colors.length; j++) {
tl.to(dot, 2.5, {rotation:"-=360", ease:Power2.easeInOut}, j * 2.9)
.to(dot, 1.2, {skewX:"+=360", backgroundColor:colors[j], ease:Power2.easeInOut}, 1.6 + 2.9 * j);
}
//stagger its placement into the master timeline
animation.add(tl, i * 0.07);
}
if (TweenLite.render) {
TweenLite.render(); //trigger the from() tweens' lazy-rendering (otherwise it'd take one tick to render everything in the beginning state, thus things may flash on the screen for a moment initially). There are other ways around this, but TweenLite.render() is probably the simplest in this case.
}
//call preloader.active(true) to open the preloader, preloader.active(false) to close it, or preloader.active() to get the current state.
this.active = function(show) {
if (!arguments.length) {
return isActive;
}
if (isActive != show) {
isActive = show;
if (closingAnimation) {
closingAnimation.kill(); //in case the preloader is made active/inactive/active/inactive really fast and there's still a closing animation running, kill it.
}
if (isActive) {
element.style.visibility = "visible";
TweenLite.set([element, box], {rotation:0});
animation.play(animationOffset);
} else {
closingAnimation = new TimelineLite();
if (animation.time() < animationOffset + 0.3) {
animation.pause();
closingAnimation.to(element, 1, {rotation:-360, ease:Power1.easeInOut}).to(box, 1, {rotation:360, ease:Power1.easeInOut}, 0);
}
closingAnimation.staggerTo(dots, 0.3, {scale:0.01, opacity:0, ease:Power1.easeIn, overwrite:false}, 0.05, 0).to(box, 0.4, {opacity:0, scale:0.2, ease:Power2.easeIn, overwrite:false}, 0).call(function() { animation.pause(); closingAnimation = null; }).set(element, {visibility:"hidden"});
}
}
return this;
};
}