413 lines
12 KiB
JavaScript
413 lines
12 KiB
JavaScript
|
/*
|
|||
|
_ _ _____ _ _
|
|||
|
| | | __ \ | | (_)
|
|||
|
___ ___ _ __ ___ | | | |__) |_____ _____ __ _| | _ ___
|
|||
|
/ __|/ __| '__/ _ \| | | _ // _ \ \ / / _ \/ _` | | | / __|
|
|||
|
\__ \ (__| | | (_) | | | | \ \ __/\ V / __/ (_| | |_| \__ \
|
|||
|
|___/\___|_| \___/|_|_|_| \_\___| \_/ \___|\__,_|_(_) |___/ v.0.1.3
|
|||
|
_/ |
|
|||
|
|__/
|
|||
|
|
|||
|
"Declarative on-scroll reveal animations."
|
|||
|
|
|||
|
/*=============================================================================
|
|||
|
|
|||
|
scrollReveal.js was inspired by cbpScroller.js (c) 2014 Codrops.
|
|||
|
|
|||
|
Licensed under the MIT license.
|
|||
|
http://www.opensource.org/licenses/mit-license.php
|
|||
|
|
|||
|
=============================================================================*/
|
|||
|
|
|||
|
/*! scrollReveal.js v0.1.3 (c) 2014 Julian Lloyd | MIT license */
|
|||
|
|
|||
|
/*===========================================================================*/
|
|||
|
|
|||
|
|
|||
|
window.scrollReveal = (function (window) {
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
// generator (increments) for the next scroll-reveal-id
|
|||
|
var nextId = 1;
|
|||
|
|
|||
|
/**
|
|||
|
* RequestAnimationFrame polyfill
|
|||
|
* @function
|
|||
|
* @private
|
|||
|
*/
|
|||
|
var requestAnimFrame = (function () {
|
|||
|
return window.requestAnimationFrame ||
|
|||
|
window.webkitRequestAnimationFrame ||
|
|||
|
window.mozRequestAnimationFrame ||
|
|||
|
function (callback) {
|
|||
|
window.setTimeout(callback, 1000 / 60);
|
|||
|
};
|
|||
|
}());
|
|||
|
|
|||
|
function scrollReveal(options) {
|
|||
|
|
|||
|
this.options = this.extend(this.defaults, options);
|
|||
|
this.docElem = this.options.elem;
|
|||
|
this.styleBank = {};
|
|||
|
|
|||
|
if (this.options.init == true) this.init();
|
|||
|
}
|
|||
|
|
|||
|
scrollReveal.prototype = {
|
|||
|
|
|||
|
defaults: {
|
|||
|
after: '0s',
|
|||
|
enter: 'bottom',
|
|||
|
move: '24px',
|
|||
|
over: '0.66s',
|
|||
|
easing: 'ease-in-out',
|
|||
|
opacity: 0,
|
|||
|
complete: function() {},
|
|||
|
|
|||
|
// if 0, the element is considered in the viewport as soon as it enters
|
|||
|
// if 1, the element is considered in the viewport when it's fully visible
|
|||
|
viewportFactor: 0.33,
|
|||
|
|
|||
|
// if false, animations occur only once
|
|||
|
// if true, animations occur each time an element enters the viewport
|
|||
|
reset: false,
|
|||
|
|
|||
|
// if true, scrollReveal.init() is automaticaly called upon instantiation
|
|||
|
init: true,
|
|||
|
elem: window.document.documentElement
|
|||
|
},
|
|||
|
|
|||
|
/*=============================================================================*/
|
|||
|
|
|||
|
init: function () {
|
|||
|
|
|||
|
this.scrolled = false;
|
|||
|
|
|||
|
var self = this;
|
|||
|
|
|||
|
// Check DOM for the data-scrollReveal attribute
|
|||
|
// and initialize all found elements.
|
|||
|
this.elems = Array.prototype.slice.call(this.docElem.querySelectorAll('[data-scroll-reveal]'));
|
|||
|
this.elems.forEach(function (el, i) {
|
|||
|
|
|||
|
// Capture original style attribute
|
|||
|
var id = el.getAttribute("data-scroll-reveal-id");
|
|||
|
if (!id) {
|
|||
|
id = nextId++;
|
|||
|
el.setAttribute("data-scroll-reveal-id", id);
|
|||
|
}
|
|||
|
if (!self.styleBank[id]) {
|
|||
|
self.styleBank[id] = el.getAttribute('style');
|
|||
|
}
|
|||
|
|
|||
|
self.update(el);
|
|||
|
});
|
|||
|
|
|||
|
var scrollHandler = function (e) {
|
|||
|
// No changing, exit
|
|||
|
if (!self.scrolled) {
|
|||
|
self.scrolled = true;
|
|||
|
requestAnimFrame(function () {
|
|||
|
self._scrollPage();
|
|||
|
});
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var resizeHandler = function () {
|
|||
|
|
|||
|
// If we’re still waiting for settimeout, reset the timer.
|
|||
|
if (self.resizeTimeout) {
|
|||
|
clearTimeout(self.resizeTimeout);
|
|||
|
}
|
|||
|
function delayed() {
|
|||
|
self._scrollPage();
|
|||
|
self.resizeTimeout = null;
|
|||
|
}
|
|||
|
self.resizeTimeout = setTimeout(delayed, 200);
|
|||
|
};
|
|||
|
|
|||
|
// captureScroll
|
|||
|
if (this.docElem == window.document.documentElement) {
|
|||
|
window.addEventListener('scroll', scrollHandler, false);
|
|||
|
window.addEventListener('resize', resizeHandler, false);
|
|||
|
}
|
|||
|
else {
|
|||
|
this.docElem.addEventListener('scroll', scrollHandler, false);
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
/*=============================================================================*/
|
|||
|
|
|||
|
_scrollPage: function () {
|
|||
|
var self = this;
|
|||
|
|
|||
|
this.elems.forEach(function (el, i) {
|
|||
|
self.update(el);
|
|||
|
});
|
|||
|
this.scrolled = false;
|
|||
|
},
|
|||
|
|
|||
|
/*=============================================================================*/
|
|||
|
|
|||
|
parseLanguage: function (el) {
|
|||
|
|
|||
|
// Splits on a sequence of one or more commas or spaces.
|
|||
|
var words = el.getAttribute('data-scroll-reveal').split(/[, ]+/),
|
|||
|
parsed = {};
|
|||
|
|
|||
|
function filter (words) {
|
|||
|
var ret = [],
|
|||
|
|
|||
|
blacklist = [
|
|||
|
"from",
|
|||
|
"the",
|
|||
|
"and",
|
|||
|
"then",
|
|||
|
"but",
|
|||
|
"with"
|
|||
|
];
|
|||
|
|
|||
|
words.forEach(function (word, i) {
|
|||
|
if (blacklist.indexOf(word) > -1) {
|
|||
|
return;
|
|||
|
}
|
|||
|
ret.push(word);
|
|||
|
});
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
words = filter(words);
|
|||
|
|
|||
|
words.forEach(function (word, i) {
|
|||
|
|
|||
|
switch (word) {
|
|||
|
case "enter":
|
|||
|
parsed.enter = words[i + 1];
|
|||
|
return;
|
|||
|
|
|||
|
case "after":
|
|||
|
parsed.after = words[i + 1];
|
|||
|
return;
|
|||
|
|
|||
|
case "wait":
|
|||
|
parsed.after = words[i + 1];
|
|||
|
return;
|
|||
|
|
|||
|
case "move":
|
|||
|
parsed.move = words[i + 1];
|
|||
|
return;
|
|||
|
|
|||
|
case "ease":
|
|||
|
parsed.move = words[i + 1];
|
|||
|
parsed.ease = "ease";
|
|||
|
return;
|
|||
|
|
|||
|
case "ease-in":
|
|||
|
parsed.move = words[i + 1];
|
|||
|
parsed.easing = "ease-in";
|
|||
|
return;
|
|||
|
|
|||
|
case "ease-in-out":
|
|||
|
parsed.move = words[i + 1];
|
|||
|
parsed.easing = "ease-in-out";
|
|||
|
return;
|
|||
|
|
|||
|
case "ease-out":
|
|||
|
parsed.move = words[i + 1];
|
|||
|
parsed.easing = "ease-out";
|
|||
|
return;
|
|||
|
|
|||
|
case "over":
|
|||
|
parsed.over = words[i + 1];
|
|||
|
return;
|
|||
|
|
|||
|
default:
|
|||
|
return;
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
return parsed;
|
|||
|
},
|
|||
|
|
|||
|
|
|||
|
/*=============================================================================*/
|
|||
|
|
|||
|
update: function (el) {
|
|||
|
|
|||
|
var that = this;
|
|||
|
var css = this.genCSS(el);
|
|||
|
var style = this.styleBank[el.getAttribute("data-scroll-reveal-id")];
|
|||
|
|
|||
|
if (style != null) style += ";"; else style = "";
|
|||
|
|
|||
|
if (!el.getAttribute('data-scroll-reveal-initialized')) {
|
|||
|
el.setAttribute('style', style + css.initial);
|
|||
|
el.setAttribute('data-scroll-reveal-initialized', true);
|
|||
|
}
|
|||
|
|
|||
|
if (!this.isElementInViewport(el, this.options.viewportFactor)) {
|
|||
|
if (this.options.reset) {
|
|||
|
el.setAttribute('style', style + css.initial + css.reset);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (el.getAttribute('data-scroll-reveal-complete')) return;
|
|||
|
|
|||
|
if (this.isElementInViewport(el, this.options.viewportFactor)) {
|
|||
|
el.setAttribute('style', style + css.target + css.transition);
|
|||
|
// Without reset enabled, we can safely remove the style tag
|
|||
|
// to prevent CSS specificy wars with authored CSS.
|
|||
|
if (!this.options.reset) {
|
|||
|
setTimeout(function () {
|
|||
|
if (style != "") {
|
|||
|
el.setAttribute('style', style);
|
|||
|
} else {
|
|||
|
el.removeAttribute('style');
|
|||
|
}
|
|||
|
el.setAttribute('data-scroll-reveal-complete',true);
|
|||
|
that.options.complete(el);
|
|||
|
}, css.totalDuration);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
/*=============================================================================*/
|
|||
|
|
|||
|
genCSS: function (el) {
|
|||
|
var parsed = this.parseLanguage(el),
|
|||
|
enter,
|
|||
|
axis;
|
|||
|
|
|||
|
if (parsed.enter) {
|
|||
|
|
|||
|
if (parsed.enter == "top" || parsed.enter == "bottom") {
|
|||
|
enter = parsed.enter;
|
|||
|
axis = "y";
|
|||
|
}
|
|||
|
|
|||
|
if (parsed.enter == "left" || parsed.enter == "right") {
|
|||
|
enter = parsed.enter;
|
|||
|
axis = "x";
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (this.options.enter == "top" || this.options.enter == "bottom") {
|
|||
|
enter = this.options.enter
|
|||
|
axis = "y";
|
|||
|
}
|
|||
|
|
|||
|
if (this.options.enter == "left" || this.options.enter == "right") {
|
|||
|
enter = this.options.enter
|
|||
|
axis = "x";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// After all values are parsed, let’s make sure our our
|
|||
|
// pixel distance is negative for top and left entrances.
|
|||
|
//
|
|||
|
// ie. "move 25px from top" starts at 'top: -25px' in CSS.
|
|||
|
|
|||
|
if (enter == "top" || enter == "left") {
|
|||
|
if (parsed.move) {
|
|||
|
parsed.move = "-" + parsed.move;
|
|||
|
}
|
|||
|
else {
|
|||
|
parsed.move = "-" + this.options.move;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var dist = parsed.move || this.options.move,
|
|||
|
dur = parsed.over || this.options.over,
|
|||
|
delay = parsed.after || this.options.after,
|
|||
|
easing = parsed.easing || this.options.easing,
|
|||
|
opacity = parsed.opacity || this.options.opacity;
|
|||
|
|
|||
|
var transition = "-webkit-transition: -webkit-transform " + dur + " " + easing + " " + delay + ", opacity " + dur + " " + easing + " " + delay + ";" +
|
|||
|
"transition: transform " + dur + " " + easing + " " + delay + ", opacity " + dur + " " + easing + " " + delay + ";" +
|
|||
|
"-webkit-perspective: 1000;" +
|
|||
|
"-webkit-backface-visibility: hidden;";
|
|||
|
|
|||
|
// The same as transition, but removing the delay for elements fading out.
|
|||
|
var reset = "-webkit-transition: -webkit-transform " + dur + " " + easing + " 0s, opacity " + dur + " " + easing + " " + delay + ";" +
|
|||
|
"transition: transform " + dur + " " + easing + " 0s, opacity " + dur + " " + easing + " " + delay + ";" +
|
|||
|
"-webkit-perspective: 1000;" +
|
|||
|
"-webkit-backface-visibility: hidden;";
|
|||
|
|
|||
|
var initial = "-webkit-transform: translate" + axis + "(" + dist + ");" +
|
|||
|
"transform: translate" + axis + "(" + dist + ");" +
|
|||
|
"opacity: " + opacity + ";";
|
|||
|
|
|||
|
var target = "-webkit-transform: translate" + axis + "(0);" +
|
|||
|
"transform: translate" + axis + "(0);" +
|
|||
|
"opacity: 1;";
|
|||
|
return {
|
|||
|
transition: transition,
|
|||
|
initial: initial,
|
|||
|
target: target,
|
|||
|
reset: reset,
|
|||
|
totalDuration: ((parseFloat(dur) + parseFloat(delay)) * 1000)
|
|||
|
};
|
|||
|
},
|
|||
|
|
|||
|
getViewportH : function () {
|
|||
|
var client = this.docElem['clientHeight'],
|
|||
|
inner = window['innerHeight'];
|
|||
|
|
|||
|
if (this.docElem == window.document.documentElement)
|
|||
|
return (client < inner) ? inner : client;
|
|||
|
else
|
|||
|
return client;
|
|||
|
},
|
|||
|
|
|||
|
getOffset : function(el) {
|
|||
|
var offsetTop = 0,
|
|||
|
offsetLeft = 0;
|
|||
|
|
|||
|
do {
|
|||
|
if (!isNaN(el.offsetTop)) {
|
|||
|
offsetTop += el.offsetTop;
|
|||
|
}
|
|||
|
if (!isNaN(el.offsetLeft)) {
|
|||
|
offsetLeft += el.offsetLeft;
|
|||
|
}
|
|||
|
} while (el = el.offsetParent)
|
|||
|
|
|||
|
return {
|
|||
|
top: offsetTop,
|
|||
|
left: offsetLeft
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
isElementInViewport : function(el, h) {
|
|||
|
var scrolled = this.docElem.scrollTop + this.docElem.offsetTop;
|
|||
|
if (this.docElem == window.document.documentElement)scrolled = window.pageYOffset;
|
|||
|
var
|
|||
|
viewed = scrolled + this.getViewportH(),
|
|||
|
elH = el.offsetHeight,
|
|||
|
elTop = this.getOffset(el).top,
|
|||
|
elBottom = elTop + elH,
|
|||
|
h = h || 0;
|
|||
|
|
|||
|
return (elTop + elH * h) <= viewed
|
|||
|
&& (elBottom) >= scrolled
|
|||
|
|| (el.currentStyle? el.currentStyle : window.getComputedStyle(el, null)).position == 'fixed';
|
|||
|
},
|
|||
|
|
|||
|
extend: function (a, b){
|
|||
|
for (var key in b) {
|
|||
|
if (b.hasOwnProperty(key)) {
|
|||
|
|
|||
|
a[key] = b[key];
|
|||
|
}
|
|||
|
}
|
|||
|
return a;
|
|||
|
}
|
|||
|
}; // end scrollReveal.prototype
|
|||
|
|
|||
|
return scrollReveal;
|
|||
|
})(window);
|