SinkDark/myblog/static/js/scrollReveal.js
2024-09-17 17:30:58 +08:00

413 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
_ _ _____ _ _
| | | __ \ | | (_)
___ ___ _ __ ___ | | | |__) |_____ _____ __ _| | _ ___
/ __|/ __| '__/ _ \| | | _ // _ \ \ / / _ \/ _` | | | / __|
\__ \ (__| | | (_) | | | | \ \ __/\ 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 were 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, lets 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);