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