ScrollMagic v1.1.2
The jQuery plugin for magical scroll interactions.
ScrollMagic is a jQuery plugin which essentially lets you use the scrollbar like a playback scrub control.
It's the plugin for you, if you want to ...
ScrollMagic v1.2.0
The jQuery plugin for magical scroll interactions.
ScrollMagic is a jQuery plugin which essentially lets you use the scrollbar like a playback scrub control.
It's the plugin for you, if you want to ...
- ... start an animation at a specific scroll position.
- ... synchronize an animation to the scrollbar movement. @@ -225,7 +226,7 @@
- Version: -
- 1.1.2
+ - 1.2.0
diff --git a/docs/jquery.scrollmagic.debug.js.html b/docs/jquery.scrollmagic.debug.js.html
index 2aee1b4e..ef54a305 100644
--- a/docs/jquery.scrollmagic.debug.js.html
+++ b/docs/jquery.scrollmagic.debug.js.html
@@ -12,6 +12,7 @@
+
@@ -107,7 +108,7 @@
Source: jquery.scrollmagic.debug.js
/*
-ScrollMagic v1.1.2
+ScrollMagic v1.2.0
The jQuery plugin for doing magical scroll interactions.
(c) 2014 Jan Paepke (@janpaepke)
License & Info: http://janpaepke.github.io/ScrollMagic
@@ -120,11 +121,19 @@ Source: jquery.scrollmagic.debug.js
*/
/*
@overview Debug Extension for ScrollMagic.
- @version 1.1.2
+ @version 1.2.0
@license Dual licensed under MIT license and GPL.
@author Jan Paepke - e-mail@janpaepke.de
*/
-(function($, ScrollScene) {
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['ScrollScene', 'jquery'], factory);
+ } else {
+ // no browser global needed, just execute
+ factory(root.ScrollScene, root.jQuery);
+ }
+}(this, function(ScrollScene, $) {
/**
* Add Indicators for a ScrollScene.
* __REQUIRES__ ScrollMagic Debug Extension: `jquery.scrollmagic.debug.js`
@@ -356,7 +365,7 @@ Source: jquery.scrollmagic.debug.js
}
}
};
-})(jQuery, ScrollScene);
+}));
diff --git a/docs/jquery.scrollmagic.js.html b/docs/jquery.scrollmagic.js.html
index 2f2bfb97..5c08acde 100644
--- a/docs/jquery.scrollmagic.js.html
+++ b/docs/jquery.scrollmagic.js.html
@@ -12,6 +12,7 @@
+
@@ -107,7 +108,7 @@ Source: jquery.scrollmagic.js
/*
-ScrollMagic v1.1.2
+ScrollMagic v1.2.0
The jQuery plugin for doing magical scroll interactions.
(c) 2014 Jan Paepke (@janpaepke)
License & Info: http://janpaepke.github.io/ScrollMagic
@@ -120,7 +121,7 @@ Source: jquery.scrollmagic.js
*/
/**
@overview ##Info
-@version 1.1.2
+@version 1.2.0
@license Dual licensed under MIT license and GPL.
@author Jan Paepke - e-mail@janpaepke.de
@@ -129,10 +130,26 @@ Source: jquery.scrollmagic.js
@todo: bug: having multiple scroll directions with cascaded pins doesn't work (one scroll vertical, one horizontal)
@todo: feature: optimize performance on debug plugin (huge drawbacks, when using many scenes)
*/
-(function($, window) {
+(function(root) {
"use strict";
+ var define = root.define, ScrollMagic, ScrollScene;
+ if (typeof define !== 'function' || !define.amd) {
+ // No AMD loader -> Provide custom method to to register browser globals instead
+ define = function (moduleName, dependencies, factory) {
+ for (var x = 0, dependency; x<dependencies.length; x++) {
+ dependency = dependencies[x];
+ if (dependency === 'jquery') { // lowercase with require, but camel case as global
+ dependency = 'jQuery';
+ }
+ dependencies[x] = root[dependency];
+ }
+ root[moduleName] = factory.apply(root, dependencies);
+ };
+ }
+
+define('ScrollMagic', ['jquery', 'TweenMax', 'TimelineMax'], function ($, TweenMax, TimelineMax) {
/**
* The main class that is needed once per scroll container.
*
@@ -155,12 +172,12 @@ Source: jquery.scrollmagic.js
** `1` => errors
** `2` => errors, warnings
** `3` => errors, warnings, debuginfo
- * @param {boolean} [options._refreshInterval=100] - Some changes don't call events by default, like changing the container size or moving a scene trigger element.
+ * @param {boolean} [options.refreshInterval=100] - Some changes don't call events by default, like changing the container size or moving a scene trigger element.
This interval polls these parameters to fire the necessary events.
If you don't use custom containers, trigger elements or have static layouts, where the positions of the trigger elements don't change, you can set this to 0 disable interval checking and improve performance.
*
*/
- var ScrollMagic = function(options) {
+ ScrollMagic = function(options) {
/*
* ----------------------------------------------------------------
@@ -187,13 +204,13 @@ Source: jquery.scrollmagic.js
ScrollMagic = this,
_options = $.extend({}, DEFAULT_OPTIONS, options),
_sceneObjects = [],
- _updateScenesOnNextTick = false, // can be boolean (true => all scenes) or an array of scenes to be updated
+ _updateScenesOnNextCycle = false, // can be boolean (true => all scenes) or an array of scenes to be updated
_scrollPos = 0,
_scrollDirection = "PAUSED",
_isDocument = true,
_viewPortSize = 0,
- _tickerUsed = false,
_enabled = true,
+ _updateCycle,
_refreshInterval;
/*
@@ -224,19 +241,14 @@ Source: jquery.scrollmagic.js
_viewPortSize = _options.vertical ? _options.container.height() : _options.container.width();
// set event handlers
_options.container.on("scroll resize", onChange);
- try {
- TweenLite.ticker.addEventListener("tick", onTick); // prefer TweenMax Ticker, but don't rely on it for basic functionality
- _tickerUsed = true;
- } catch (e) {
- _options.container.on("scroll resize", onTick); // okay then just update on scroll/resize...
- _tickerUsed = false;
- }
_options.refreshInterval = parseInt(_options.refreshInterval);
if (_options.refreshInterval > 0) {
_refreshInterval = window.setInterval(refresh, _options.refreshInterval);
}
+ // start checking for changes
+ _updateCycle = animationFrameCallback(updateScenes);
log(3, "added new " + NAMESPACE + " controller (v" + ScrollMagic.version + ")");
};
@@ -260,13 +272,13 @@ Source: jquery.scrollmagic.js
};
/**
- * Handle updates on tick instead of on scroll (performance)
+ * Handle updates in cycles instead of on scroll (performance)
* @private
*/
- var onTick = function (e) {
- if (_updateScenesOnNextTick && _enabled) {
+ var updateScenes = function () {
+ if (_enabled && _updateScenesOnNextCycle) {
var
- scenesToUpdate = $.isArray(_updateScenesOnNextTick) ? _updateScenesOnNextTick : _sceneObjects.slice(0),
+ scenesToUpdate = $.isArray(_updateScenesOnNextCycle) ? _updateScenesOnNextCycle : _sceneObjects.slice(0),
oldScrollPos = _scrollPos;
// update scroll pos & direction
_scrollPos = ScrollMagic.scrollPos();
@@ -283,8 +295,9 @@ Source: jquery.scrollmagic.js
if (scenesToUpdate.length === 0 && _options.loglevel >= 3) {
log(3, "updating 0 Scenes (nothing added to controller)");
}
- _updateScenesOnNextTick = false;
+ _updateScenesOnNextCycle = false;
}
+ _updateCycle = animationFrameCallback(updateScenes);
};
/**
@@ -295,7 +308,7 @@ Source: jquery.scrollmagic.js
if (e.type == "resize") {
_viewPortSize = _options.vertical ? _options.container.height() : _options.container.width();
}
- _updateScenesOnNextTick = true;
+ _updateScenesOnNextCycle = true;
};
var refresh = function () {
@@ -436,18 +449,18 @@ Source: jquery.scrollmagic.js
* _**Note:** This method gets called constantly whenever ScrollMagic detects a change. The only application for you is if you change something outside of the realm of ScrollMagic, like moving the trigger or changing tween parameters._
* @public
* @example
- * // update a specific scene on next tick
+ * // update a specific scene on next cycle
* controller.updateScene(scene);
*
* // update a specific scene immediately
* controller.updateScene(scene, true);
*
- * // update multiple scenes scene on next tick
+ * // update multiple scenes scene on next cycle
* controller.updateScene([scene1, scene2, scene3]);
*
* @param {ScrollScene} ScrollScene - ScrollScene or Array of ScrollScenes that is/are supposed to be updated.
- * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick.
- This is useful when changing multiple properties of the scene - this way it will only be updated once all new properties are set (onTick).
+ * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle.
+ This is useful when changing multiple properties of the scene - this way it will only be updated once all new properties are set (updateScenes).
* @return {ScrollMagic} Parent object for chaining.
*/
this.updateScene = function (ScrollScene, immediately) {
@@ -460,13 +473,13 @@ Source: jquery.scrollmagic.js
ScrollScene.update(true);
} else {
// prep array for next update cycle
- if (!$.isArray(_updateScenesOnNextTick)) {
- _updateScenesOnNextTick = [];
+ if (!$.isArray(_updateScenesOnNextCycle)) {
+ _updateScenesOnNextCycle = [];
}
- if ($.inArray(ScrollScene, _updateScenesOnNextTick) == -1) {
- _updateScenesOnNextTick.push(ScrollScene);
+ if ($.inArray(ScrollScene, _updateScenesOnNextCycle) == -1) {
+ _updateScenesOnNextCycle.push(ScrollScene);
}
- _updateScenesOnNextTick = sortScenes(_updateScenesOnNextTick); // sort
+ _updateScenesOnNextCycle = sortScenes(_updateScenesOnNextCycle); // sort
}
}
return ScrollMagic;
@@ -481,19 +494,19 @@ Source: jquery.scrollmagic.js
* For this case there will also be the need to provide a custom function to calculate the correct scroll position. See `ScrollMagic.scrollPos()` for details.
* @public
* @example
- * // update the controller on next tick (saves performance)
+ * // update the controller on next cycle (saves performance due to elimination of redundant updates)
* controller.update();
*
* // update the controller immediately
* controller.update(true);
*
- * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick (better performance)
+ * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance)
* @return {ScrollMagic} Parent object for chaining.
*/
this.update = function (immediately) {
- onChange({type: "resize"}); // will update size and set _updateScenesOnNextTick to true
+ onChange({type: "resize"}); // will update size and set _updateScenesOnNextCycle to true
if (immediately) {
- onTick();
+ updateScenes();
}
return ScrollMagic;
};
@@ -565,7 +578,7 @@ Source: jquery.scrollmagic.js
* **Get** the current scrollPosition or **Set** a new method to calculate it.
* -> **GET**:
* When used as a getter this function will return the current scroll position.
- * To get a cached value use ScrollMagic.info("scrollPos"), which will be updated on tick to save on performance.
+ * To get a cached value use ScrollMagic.info("scrollPos"), which will be updated in the update cycle.
* For vertical controllers it will return the top scroll offset and for horizontal applications it will return the left offset.
*
* -> **SET**:
@@ -711,20 +724,21 @@ Source: jquery.scrollmagic.js
_sceneObjects[i].destroy(resetScenes);
}
_options.container.off("scroll resize", onChange);
- if (_tickerUsed) {
- TweenLite.ticker.removeEventListener("tick", onTick);
- } else {
- _options.container.off("scroll resize", onTick);
- }
+ animationFrameCancelCallback(_updateCycle);
log(3, "destroyed " + NAMESPACE + " (reset: " + (resetScenes ? "true" : "false") + ")");
return null;
};
// INIT
construct();
+ ScrollMagic.version = "1.2.0"; // version number for each instance
return ScrollMagic;
};
+ ScrollMagic.version = "1.2.0"; // version number for browser global
+ return ScrollMagic;
+});
+define('ScrollScene', ['jquery', 'TweenMax', 'TimelineMax'], function ($, TweenMax, TimelineMax) {
/**
* A ScrollScene defines where the controller should react and how.
*
@@ -767,7 +781,7 @@ Source: jquery.scrollmagic.js
** `3` => errors, warnings, debuginfo
*
*/
- var ScrollScene = function (options) {
+ ScrollScene = function (options) {
/*
* ----------------------------------------------------------------
@@ -875,23 +889,6 @@ Source: jquery.scrollmagic.js
log(1, "ERROR: Invalid value for option \"loglevel\":", wrongval);
}
},
- "checkIfTriggerElementIsTweened" : function () {
- // check if there are position tweens defined for the trigger and warn about it :)
- if (_tween && _parent && _options.triggerElement && _options.loglevel >= 2) {// parent is needed to know scroll direction.
- var
- triggerTweens = _tween.getTweensOf($(_options.triggerElement)),
- vertical = _parent.info("vertical");
- $.each(triggerTweens, function (index, value) {
- var
- tweenvars = value.vars.css || value.vars,
- condition = vertical ? (tweenvars.top !== undefined || tweenvars.bottom !== undefined) : (tweenvars.left !== undefined || tweenvars.right !== undefined);
- if (condition) {
- log(2, "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!");
- return false;
- }
- });
- }
- },
};
/*
@@ -1285,12 +1282,13 @@ Source: jquery.scrollmagic.js
};
/**
- * Is called, when the mousewhel is used while over a pinned element.
- * If the scene is in fixed state scroll events used to be ignored. This forwards the event to the scroll container.
+ * Is called, when the mousewhel is used while over a pinned element inside a div container.
+ * If the scene is in fixed state scroll events would be counted towards the body. This forwards the event to the scroll container.
* @private
*/
var onMousewheelOverPin = function (e) {
- if (_parent && _pin && _state === "DURING") { // in pin state
+ if (_parent && _pin && _state === "DURING" && !_parent.info("isDocument")) { // in pin state
+ e.preventDefault();
_parent.scrollTo(_parent.info("scrollPos") - (e.originalEvent.wheelDelta/3 || -e.originalEvent.detail*30));
}
};
@@ -1615,7 +1613,7 @@ Source: jquery.scrollmagic.js
*
* @fires ScrollScene.update
*
- * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick (better performance).
+ * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance).
* @returns {ScrollScene} Parent object for chaining.
*/
this.update = function (immediately) {
@@ -1800,33 +1798,69 @@ Source: jquery.scrollmagic.js
* .add(tween2);
* scene.addTween(timeline);
*
- * @param {object} TweenMaxObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene.
+ * @param {object} TweenObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene.
* @returns {ScrollScene} Parent object for chaining.
*/
- this.setTween = function (TweenMaxObject) {
+ this.setTween = function (TweenObject) {
if (_tween) { // kill old tween?
ScrollScene.removeTween();
}
try {
// wrap Tween into a TimelineMax Object to include delay and repeats in the duration and standardize methods.
_tween = new TimelineMax({smoothChildTiming: true})
- .add(TweenMaxObject)
+ .add(TweenObject)
.pause();
} catch (e) {
- log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenMaxObject");
+ log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenObject");
} finally {
- // some propertties need to be transferred it to the wrapper, otherwise they would get lost.
- if (TweenMaxObject.repeat) { // TweenMax or TimelineMax Object?
- if (TweenMaxObject.repeat() === -1) {
- _tween.repeat(-1);
- _tween.yoyo(TweenMaxObject.yoyo());
+ // some properties need to be transferred it to the wrapper, otherwise they would get lost.
+ if (TweenObject.repeat && TweenObject.repeat() === -1) {// TweenMax or TimelineMax Object?
+ _tween.repeat(-1);
+ _tween.yoyo(TweenObject.yoyo());
+ }
+ }
+ // Some tween validations and debugging helpers
+
+ // check if there are position tweens defined for the trigger and warn about it :)
+ if (_tween && _parent && _options.triggerElement && _options.loglevel >= 2) {// parent is needed to know scroll direction.
+ var
+ triggerTweens = _tween.getTweensOf($(_options.triggerElement)),
+ vertical = _parent.info("vertical");
+ $.each(triggerTweens, function (index, value) {
+ var
+ tweenvars = value.vars.css || value.vars,
+ condition = vertical ? (tweenvars.top !== undefined || tweenvars.bottom !== undefined) : (tweenvars.left !== undefined || tweenvars.right !== undefined);
+ if (condition) {
+ log(2, "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!");
+ return false;
+ }
+ });
+ }
+
+ // warn about tween overwrites, when an element is tweened multiple times
+ if (parseFloat(TweenLite.version) >= 1.14) { // onOverwrite only present since GSAP v1.14.0
+ var
+ list = _tween.getChildren(true, true, false), // get all nested tween objects
+ newCallback = function () {
+ log(2, "WARNING: tween was overwritten by another. To learn how to avoid this issue see here: https://github.com/janpaepke/ScrollMagic/wiki/WARNING:-tween-was-overwritten-by-another");
+ };
+ for (var i=0, thisTween, oldCallback; i<list.length; i++) {
+ /*jshint loopfunc: true */
+ thisTween = list[i];
+ if (oldCallback !== newCallback) { // if tweens is added more than once
+ oldCallback = thisTween.vars.onOverwrite;
+ thisTween.vars.onOverwrite = function () {
+ if (oldCallback) {
+ oldCallback.apply(this, arguments);
+ }
+ newCallback.apply(this, arguments);
+ };
}
}
- validateOption("checkIfTriggerElementIsTweened");
- log(3, "added tween");
- updateTweenProgress();
- return ScrollScene;
}
+ log(3, "added tween");
+ updateTweenProgress();
+ return ScrollScene;
};
/**
@@ -2457,12 +2491,8 @@ Source: jquery.scrollmagic.js
construct();
return ScrollScene;
};
-
- // store version
- ScrollMagic.prototype.version = "1.1.2";
- // make global references available
- window.ScrollScene = ScrollScene;
- window.ScrollMagic = ScrollMagic;
+ return ScrollScene;
+});
/*
* ----------------------------------------------------------------
@@ -2470,55 +2500,41 @@ Source: jquery.scrollmagic.js
* ----------------------------------------------------------------
*/
- var
- console = (window.console = window.console || {}),
- loglevels = [
- "error",
- "warn",
- "log"
- ];
- if (!console.log) {
- console.log = $.noop; // no console log, well - do nothing then...
- }
- $.each(loglevels, function (index, method) { // make sure methods for all levels exist.
- if (!console[method]) {
- console[method] = console.log; // prefer .log over nothing
+ var debug = (function (console) {
+ var loglevels = ["error", "warn", "log"];
+ if (!console.log) {
+ console.log = function(){}; // no console log, well - do nothing then...
}
- });
- // debugging function
- var debug = function (loglevel) {
- if (loglevel > loglevels.length || loglevel <= 0) loglevel = loglevels.length;
- var now = new Date(),
- time = ("0"+now.getHours()).slice(-2) + ":" + ("0"+now.getMinutes()).slice(-2) + ":" + ("0"+now.getSeconds()).slice(-2) + ":" + ("00"+now.getMilliseconds()).slice(-3),
- method = loglevels[loglevel-1],
- args = Array.prototype.splice.call(arguments, 1),
- func = Function.prototype.bind.call(console[method], console);
-
- args.unshift(time);
- func.apply(console, args);
- };
+ for(var i = 0, method; i<loglevels.length; i++) { // make sure methods for all levels exist.
+ method = loglevels[i];
+ if (!console[method]) {
+ console[method] = console.log; // prefer .log over nothing
+ }
+ }
+ // debugging function
+ return function (loglevel) {
+ if (loglevel > loglevels.length || loglevel <= 0) loglevel = loglevels.length;
+ var now = new Date(),
+ time = ("0"+now.getHours()).slice(-2) + ":" + ("0"+now.getMinutes()).slice(-2) + ":" + ("0"+now.getSeconds()).slice(-2) + ":" + ("00"+now.getMilliseconds()).slice(-3),
+ method = loglevels[loglevel-1],
+ args = Array.prototype.splice.call(arguments, 1),
+ func = Function.prototype.bind.call(console[method], console);
+
+ args.unshift(time);
+ func.apply(console, args);
+ };
+ }(window.console = window.console || {}));
// a helper function that should generally be faster than jQuery.offset() and can also return position in relation to viewport.
- var getOffset = function ($elem, relativeToViewport) {
- var offset = {
- top: 0,
- left: 0
- },
- elem = $elem[0];
- if (elem) {
- if (elem.getBoundingClientRect) { // check if available
- var rect = elem.getBoundingClientRect();
- offset.top = rect.top;
- offset.left = rect.left;
- if (!relativeToViewport) { // clientRect is by default relative to viewport...
- offset.top += $(document).scrollTop();
- offset.left += $(document).scrollLeft();
- }
- } else { // fall back to jquery
- offset = $elem.offset() || offset; // if element has offset undefined (i.e. document) use 0 for top and left
- if (relativeToViewport) { // jquery.offset is by default NOT relative to viewport...
- offset.top -= $(document).scrollTop();
- offset.left -= $(document).scrollLeft();
- }
+ var getOffset = function (elem, relativeToViewport) {
+ var offset = {top: 0, left: 0};
+ elem = elem[0]; // tmp workaround until jQuery dependency is removed.
+ if (elem && elem.getBoundingClientRect) { // check if available
+ var rect = elem.getBoundingClientRect();
+ offset.top = rect.top;
+ offset.left = rect.left;
+ if (!relativeToViewport) { // clientRect is by default relative to viewport...
+ offset.top += (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || 0);
+ offset.left += (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || 0);
}
}
return offset;
@@ -2532,8 +2548,43 @@ Source: jquery.scrollmagic.js
var isMarginCollapseType = function (str) {
return ["block", "flex", "list-item", "table", "-webkit-box"].indexOf(str) > -1;
};
+ // implementation of requestAnimationFrame
+ var animationFrameCallback = window.requestAnimationFrame;
+ var animationFrameCancelCallback = window.cancelAnimationFrame;
+
+ // polyfill -> based on https://gist.github.com/paulirish/1579671
+ (function (window) {
+ var
+ lastTime = 0,
+ vendors = ['ms', 'moz', 'webkit', 'o'],
+ i;
+
+ // try vendor prefixes if the above doesn't work
+ for (i = 0; !animationFrameCallback && i < vendors.length; ++i) {
+ console.log(vendors[i] + 'RequestAnimationFrame');
+ animationFrameCallback = window[vendors[i] + 'RequestAnimationFrame'];
+ animationFrameCancelCallback = window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame'];
+ }
+
+ // fallbacks
+ if (!animationFrameCallback) {
+ animationFrameCallback = function (callback) {
+ var
+ currTime = new Date().getTime(),
+ timeToCall = Math.max(0, 16 - (currTime - lastTime)),
+ id = window.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+ }
+ if (!animationFrameCancelCallback) {
+ animationFrameCancelCallback = function (id) {
+ window.clearTimeout(id);
+ };
+ }
+ }(window));
-})(jQuery, window);
+})(this || window);
diff --git a/js/jquery.scrollmagic.debug.js b/js/jquery.scrollmagic.debug.js
index 819e7036..cb93af7b 100644
--- a/js/jquery.scrollmagic.debug.js
+++ b/js/jquery.scrollmagic.debug.js
@@ -1,5 +1,5 @@
/*
-ScrollMagic v1.1.2
+ScrollMagic v1.2.0
The jQuery plugin for doing magical scroll interactions.
(c) 2014 Jan Paepke (@janpaepke)
License & Info: http://janpaepke.github.io/ScrollMagic
@@ -12,11 +12,19 @@ Greensock License info at http://www.greensock.com/licensing/
*/
/*
@overview Debug Extension for ScrollMagic.
- @version 1.1.2
+ @version 1.2.0
@license Dual licensed under MIT license and GPL.
@author Jan Paepke - e-mail@janpaepke.de
*/
-(function($, ScrollScene) {
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['ScrollScene', 'jquery'], factory);
+ } else {
+ // no browser global needed, just execute
+ factory(root.ScrollScene, root.jQuery);
+ }
+}(this, function(ScrollScene, $) {
/**
* Add Indicators for a ScrollScene.
* __REQUIRES__ ScrollMagic Debug Extension: `jquery.scrollmagic.debug.js`
@@ -248,4 +256,4 @@ Greensock License info at http://www.greensock.com/licensing/
}
}
};
-})(jQuery, ScrollScene);
\ No newline at end of file
+}));
\ No newline at end of file
diff --git a/js/jquery.scrollmagic.js b/js/jquery.scrollmagic.js
index b75eebf8..949801e7 100644
--- a/js/jquery.scrollmagic.js
+++ b/js/jquery.scrollmagic.js
@@ -1,5 +1,5 @@
/*
-ScrollMagic v1.1.2
+ScrollMagic v1.2.0
The jQuery plugin for doing magical scroll interactions.
(c) 2014 Jan Paepke (@janpaepke)
License & Info: http://janpaepke.github.io/ScrollMagic
@@ -12,7 +12,7 @@ Greensock License info at http://www.greensock.com/licensing/
*/
/**
@overview ##Info
-@version 1.1.2
+@version 1.2.0
@license Dual licensed under MIT license and GPL.
@author Jan Paepke - e-mail@janpaepke.de
@@ -21,10 +21,26 @@ Greensock License info at http://www.greensock.com/licensing/
@todo: bug: having multiple scroll directions with cascaded pins doesn't work (one scroll vertical, one horizontal)
@todo: feature: optimize performance on debug plugin (huge drawbacks, when using many scenes)
*/
-(function($, window) {
+(function(root) {
"use strict";
+ var define = root.define, ScrollMagic, ScrollScene;
+ if (typeof define !== 'function' || !define.amd) {
+ // No AMD loader -> Provide custom method to to register browser globals instead
+ define = function (moduleName, dependencies, factory) {
+ for (var x = 0, dependency; x errors
** `2` => errors, warnings
** `3` => errors, warnings, debuginfo
- * @param {boolean} [options._refreshInterval=100] - Some changes don't call events by default, like changing the container size or moving a scene trigger element.
+ * @param {boolean} [options.refreshInterval=100] - Some changes don't call events by default, like changing the container size or moving a scene trigger element.
This interval polls these parameters to fire the necessary events.
If you don't use custom containers, trigger elements or have static layouts, where the positions of the trigger elements don't change, you can set this to 0 disable interval checking and improve performance.
*
*/
- var ScrollMagic = function(options) {
+ ScrollMagic = function(options) {
/*
* ----------------------------------------------------------------
@@ -79,13 +95,13 @@ Greensock License info at http://www.greensock.com/licensing/
ScrollMagic = this,
_options = $.extend({}, DEFAULT_OPTIONS, options),
_sceneObjects = [],
- _updateScenesOnNextTick = false, // can be boolean (true => all scenes) or an array of scenes to be updated
+ _updateScenesOnNextCycle = false, // can be boolean (true => all scenes) or an array of scenes to be updated
_scrollPos = 0,
_scrollDirection = "PAUSED",
_isDocument = true,
_viewPortSize = 0,
- _tickerUsed = false,
_enabled = true,
+ _updateCycle,
_refreshInterval;
/*
@@ -116,19 +132,14 @@ Greensock License info at http://www.greensock.com/licensing/
_viewPortSize = _options.vertical ? _options.container.height() : _options.container.width();
// set event handlers
_options.container.on("scroll resize", onChange);
- try {
- TweenLite.ticker.addEventListener("tick", onTick); // prefer TweenMax Ticker, but don't rely on it for basic functionality
- _tickerUsed = true;
- } catch (e) {
- _options.container.on("scroll resize", onTick); // okay then just update on scroll/resize...
- _tickerUsed = false;
- }
_options.refreshInterval = parseInt(_options.refreshInterval);
if (_options.refreshInterval > 0) {
_refreshInterval = window.setInterval(refresh, _options.refreshInterval);
}
+ // start checking for changes
+ _updateCycle = animationFrameCallback(updateScenes);
log(3, "added new " + NAMESPACE + " controller (v" + ScrollMagic.version + ")");
};
@@ -152,13 +163,13 @@ Greensock License info at http://www.greensock.com/licensing/
};
/**
- * Handle updates on tick instead of on scroll (performance)
+ * Handle updates in cycles instead of on scroll (performance)
* @private
*/
- var onTick = function (e) {
- if (_updateScenesOnNextTick && _enabled) {
+ var updateScenes = function () {
+ if (_enabled && _updateScenesOnNextCycle) {
var
- scenesToUpdate = $.isArray(_updateScenesOnNextTick) ? _updateScenesOnNextTick : _sceneObjects.slice(0),
+ scenesToUpdate = $.isArray(_updateScenesOnNextCycle) ? _updateScenesOnNextCycle : _sceneObjects.slice(0),
oldScrollPos = _scrollPos;
// update scroll pos & direction
_scrollPos = ScrollMagic.scrollPos();
@@ -175,8 +186,9 @@ Greensock License info at http://www.greensock.com/licensing/
if (scenesToUpdate.length === 0 && _options.loglevel >= 3) {
log(3, "updating 0 Scenes (nothing added to controller)");
}
- _updateScenesOnNextTick = false;
+ _updateScenesOnNextCycle = false;
}
+ _updateCycle = animationFrameCallback(updateScenes);
};
/**
@@ -187,7 +199,7 @@ Greensock License info at http://www.greensock.com/licensing/
if (e.type == "resize") {
_viewPortSize = _options.vertical ? _options.container.height() : _options.container.width();
}
- _updateScenesOnNextTick = true;
+ _updateScenesOnNextCycle = true;
};
var refresh = function () {
@@ -328,18 +340,18 @@ Greensock License info at http://www.greensock.com/licensing/
* _**Note:** This method gets called constantly whenever ScrollMagic detects a change. The only application for you is if you change something outside of the realm of ScrollMagic, like moving the trigger or changing tween parameters._
* @public
* @example
- * // update a specific scene on next tick
+ * // update a specific scene on next cycle
* controller.updateScene(scene);
*
* // update a specific scene immediately
* controller.updateScene(scene, true);
*
- * // update multiple scenes scene on next tick
+ * // update multiple scenes scene on next cycle
* controller.updateScene([scene1, scene2, scene3]);
*
* @param {ScrollScene} ScrollScene - ScrollScene or Array of ScrollScenes that is/are supposed to be updated.
- * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick.
- This is useful when changing multiple properties of the scene - this way it will only be updated once all new properties are set (onTick).
+ * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle.
+ This is useful when changing multiple properties of the scene - this way it will only be updated once all new properties are set (updateScenes).
* @return {ScrollMagic} Parent object for chaining.
*/
this.updateScene = function (ScrollScene, immediately) {
@@ -352,13 +364,13 @@ Greensock License info at http://www.greensock.com/licensing/
ScrollScene.update(true);
} else {
// prep array for next update cycle
- if (!$.isArray(_updateScenesOnNextTick)) {
- _updateScenesOnNextTick = [];
+ if (!$.isArray(_updateScenesOnNextCycle)) {
+ _updateScenesOnNextCycle = [];
}
- if ($.inArray(ScrollScene, _updateScenesOnNextTick) == -1) {
- _updateScenesOnNextTick.push(ScrollScene);
+ if ($.inArray(ScrollScene, _updateScenesOnNextCycle) == -1) {
+ _updateScenesOnNextCycle.push(ScrollScene);
}
- _updateScenesOnNextTick = sortScenes(_updateScenesOnNextTick); // sort
+ _updateScenesOnNextCycle = sortScenes(_updateScenesOnNextCycle); // sort
}
}
return ScrollMagic;
@@ -373,19 +385,19 @@ Greensock License info at http://www.greensock.com/licensing/
* For this case there will also be the need to provide a custom function to calculate the correct scroll position. See `ScrollMagic.scrollPos()` for details.
* @public
* @example
- * // update the controller on next tick (saves performance)
+ * // update the controller on next cycle (saves performance due to elimination of redundant updates)
* controller.update();
*
* // update the controller immediately
* controller.update(true);
*
- * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick (better performance)
+ * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance)
* @return {ScrollMagic} Parent object for chaining.
*/
this.update = function (immediately) {
- onChange({type: "resize"}); // will update size and set _updateScenesOnNextTick to true
+ onChange({type: "resize"}); // will update size and set _updateScenesOnNextCycle to true
if (immediately) {
- onTick();
+ updateScenes();
}
return ScrollMagic;
};
@@ -457,7 +469,7 @@ Greensock License info at http://www.greensock.com/licensing/
* **Get** the current scrollPosition or **Set** a new method to calculate it.
* -> **GET**:
* When used as a getter this function will return the current scroll position.
- * To get a cached value use ScrollMagic.info("scrollPos"), which will be updated on tick to save on performance.
+ * To get a cached value use ScrollMagic.info("scrollPos"), which will be updated in the update cycle.
* For vertical controllers it will return the top scroll offset and for horizontal applications it will return the left offset.
*
* -> **SET**:
@@ -603,20 +615,21 @@ Greensock License info at http://www.greensock.com/licensing/
_sceneObjects[i].destroy(resetScenes);
}
_options.container.off("scroll resize", onChange);
- if (_tickerUsed) {
- TweenLite.ticker.removeEventListener("tick", onTick);
- } else {
- _options.container.off("scroll resize", onTick);
- }
+ animationFrameCancelCallback(_updateCycle);
log(3, "destroyed " + NAMESPACE + " (reset: " + (resetScenes ? "true" : "false") + ")");
return null;
};
// INIT
construct();
+ ScrollMagic.version = "1.2.0"; // version number for each instance
return ScrollMagic;
};
+ ScrollMagic.version = "1.2.0"; // version number for browser global
+ return ScrollMagic;
+});
+define('ScrollScene', ['jquery', 'TweenMax', 'TimelineMax'], function ($, TweenMax, TimelineMax) {
/**
* A ScrollScene defines where the controller should react and how.
*
@@ -659,7 +672,7 @@ Greensock License info at http://www.greensock.com/licensing/
** `3` => errors, warnings, debuginfo
*
*/
- var ScrollScene = function (options) {
+ ScrollScene = function (options) {
/*
* ----------------------------------------------------------------
@@ -767,23 +780,6 @@ Greensock License info at http://www.greensock.com/licensing/
log(1, "ERROR: Invalid value for option \"loglevel\":", wrongval);
}
},
- "checkIfTriggerElementIsTweened" : function () {
- // check if there are position tweens defined for the trigger and warn about it :)
- if (_tween && _parent && _options.triggerElement && _options.loglevel >= 2) {// parent is needed to know scroll direction.
- var
- triggerTweens = _tween.getTweensOf($(_options.triggerElement)),
- vertical = _parent.info("vertical");
- $.each(triggerTweens, function (index, value) {
- var
- tweenvars = value.vars.css || value.vars,
- condition = vertical ? (tweenvars.top !== undefined || tweenvars.bottom !== undefined) : (tweenvars.left !== undefined || tweenvars.right !== undefined);
- if (condition) {
- log(2, "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!");
- return false;
- }
- });
- }
- },
};
/*
@@ -1177,12 +1173,13 @@ Greensock License info at http://www.greensock.com/licensing/
};
/**
- * Is called, when the mousewhel is used while over a pinned element.
- * If the scene is in fixed state scroll events used to be ignored. This forwards the event to the scroll container.
+ * Is called, when the mousewhel is used while over a pinned element inside a div container.
+ * If the scene is in fixed state scroll events would be counted towards the body. This forwards the event to the scroll container.
* @private
*/
var onMousewheelOverPin = function (e) {
- if (_parent && _pin && _state === "DURING") { // in pin state
+ if (_parent && _pin && _state === "DURING" && !_parent.info("isDocument")) { // in pin state
+ e.preventDefault();
_parent.scrollTo(_parent.info("scrollPos") - (e.originalEvent.wheelDelta/3 || -e.originalEvent.detail*30));
}
};
@@ -1507,7 +1504,7 @@ Greensock License info at http://www.greensock.com/licensing/
*
* @fires ScrollScene.update
*
- * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick (better performance).
+ * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance).
* @returns {ScrollScene} Parent object for chaining.
*/
this.update = function (immediately) {
@@ -1692,33 +1689,69 @@ Greensock License info at http://www.greensock.com/licensing/
* .add(tween2);
* scene.addTween(timeline);
*
- * @param {object} TweenMaxObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene.
+ * @param {object} TweenObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene.
* @returns {ScrollScene} Parent object for chaining.
*/
- this.setTween = function (TweenMaxObject) {
+ this.setTween = function (TweenObject) {
if (_tween) { // kill old tween?
ScrollScene.removeTween();
}
try {
// wrap Tween into a TimelineMax Object to include delay and repeats in the duration and standardize methods.
_tween = new TimelineMax({smoothChildTiming: true})
- .add(TweenMaxObject)
+ .add(TweenObject)
.pause();
} catch (e) {
- log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenMaxObject");
+ log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenObject");
} finally {
- // some propertties need to be transferred it to the wrapper, otherwise they would get lost.
- if (TweenMaxObject.repeat) { // TweenMax or TimelineMax Object?
- if (TweenMaxObject.repeat() === -1) {
- _tween.repeat(-1);
- _tween.yoyo(TweenMaxObject.yoyo());
+ // some properties need to be transferred it to the wrapper, otherwise they would get lost.
+ if (TweenObject.repeat && TweenObject.repeat() === -1) {// TweenMax or TimelineMax Object?
+ _tween.repeat(-1);
+ _tween.yoyo(TweenObject.yoyo());
+ }
+ }
+ // Some tween validations and debugging helpers
+
+ // check if there are position tweens defined for the trigger and warn about it :)
+ if (_tween && _parent && _options.triggerElement && _options.loglevel >= 2) {// parent is needed to know scroll direction.
+ var
+ triggerTweens = _tween.getTweensOf($(_options.triggerElement)),
+ vertical = _parent.info("vertical");
+ $.each(triggerTweens, function (index, value) {
+ var
+ tweenvars = value.vars.css || value.vars,
+ condition = vertical ? (tweenvars.top !== undefined || tweenvars.bottom !== undefined) : (tweenvars.left !== undefined || tweenvars.right !== undefined);
+ if (condition) {
+ log(2, "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!");
+ return false;
+ }
+ });
+ }
+
+ // warn about tween overwrites, when an element is tweened multiple times
+ if (parseFloat(TweenLite.version) >= 1.14) { // onOverwrite only present since GSAP v1.14.0
+ var
+ list = _tween.getChildren(true, true, false), // get all nested tween objects
+ newCallback = function () {
+ log(2, "WARNING: tween was overwritten by another. To learn how to avoid this issue see here: https://github.com/janpaepke/ScrollMagic/wiki/WARNING:-tween-was-overwritten-by-another");
+ };
+ for (var i=0, thisTween, oldCallback; i loglevels.length || loglevel <= 0) loglevel = loglevels.length;
- var now = new Date(),
- time = ("0"+now.getHours()).slice(-2) + ":" + ("0"+now.getMinutes()).slice(-2) + ":" + ("0"+now.getSeconds()).slice(-2) + ":" + ("00"+now.getMilliseconds()).slice(-3),
- method = loglevels[loglevel-1],
- args = Array.prototype.splice.call(arguments, 1),
- func = Function.prototype.bind.call(console[method], console);
-
- args.unshift(time);
- func.apply(console, args);
- };
+ for(var i = 0, method; i loglevels.length || loglevel <= 0) loglevel = loglevels.length;
+ var now = new Date(),
+ time = ("0"+now.getHours()).slice(-2) + ":" + ("0"+now.getMinutes()).slice(-2) + ":" + ("0"+now.getSeconds()).slice(-2) + ":" + ("00"+now.getMilliseconds()).slice(-3),
+ method = loglevels[loglevel-1],
+ args = Array.prototype.splice.call(arguments, 1),
+ func = Function.prototype.bind.call(console[method], console);
+
+ args.unshift(time);
+ func.apply(console, args);
+ };
+ }(window.console = window.console || {}));
// a helper function that should generally be faster than jQuery.offset() and can also return position in relation to viewport.
- var getOffset = function ($elem, relativeToViewport) {
- var offset = {
- top: 0,
- left: 0
- },
- elem = $elem[0];
- if (elem) {
- if (elem.getBoundingClientRect) { // check if available
- var rect = elem.getBoundingClientRect();
- offset.top = rect.top;
- offset.left = rect.left;
- if (!relativeToViewport) { // clientRect is by default relative to viewport...
- offset.top += $(document).scrollTop();
- offset.left += $(document).scrollLeft();
- }
- } else { // fall back to jquery
- offset = $elem.offset() || offset; // if element has offset undefined (i.e. document) use 0 for top and left
- if (relativeToViewport) { // jquery.offset is by default NOT relative to viewport...
- offset.top -= $(document).scrollTop();
- offset.left -= $(document).scrollLeft();
- }
+ var getOffset = function (elem, relativeToViewport) {
+ var offset = {top: 0, left: 0};
+ elem = elem[0]; // tmp workaround until jQuery dependency is removed.
+ if (elem && elem.getBoundingClientRect) { // check if available
+ var rect = elem.getBoundingClientRect();
+ offset.top = rect.top;
+ offset.left = rect.left;
+ if (!relativeToViewport) { // clientRect is by default relative to viewport...
+ offset.top += (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || 0);
+ offset.left += (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || 0);
}
}
return offset;
@@ -2424,5 +2439,40 @@ Greensock License info at http://www.greensock.com/licensing/
var isMarginCollapseType = function (str) {
return ["block", "flex", "list-item", "table", "-webkit-box"].indexOf(str) > -1;
};
+ // implementation of requestAnimationFrame
+ var animationFrameCallback = window.requestAnimationFrame;
+ var animationFrameCancelCallback = window.cancelAnimationFrame;
+
+ // polyfill -> based on https://gist.github.com/paulirish/1579671
+ (function (window) {
+ var
+ lastTime = 0,
+ vendors = ['ms', 'moz', 'webkit', 'o'],
+ i;
+
+ // try vendor prefixes if the above doesn't work
+ for (i = 0; !animationFrameCallback && i < vendors.length; ++i) {
+ console.log(vendors[i] + 'RequestAnimationFrame');
+ animationFrameCallback = window[vendors[i] + 'RequestAnimationFrame'];
+ animationFrameCancelCallback = window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame'];
+ }
+
+ // fallbacks
+ if (!animationFrameCallback) {
+ animationFrameCallback = function (callback) {
+ var
+ currTime = new Date().getTime(),
+ timeToCall = Math.max(0, 16 - (currTime - lastTime)),
+ id = window.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+ }
+ if (!animationFrameCancelCallback) {
+ animationFrameCancelCallback = function (id) {
+ window.clearTimeout(id);
+ };
+ }
+ }(window));
-})(jQuery, window);
\ No newline at end of file
+})(this || window);
\ No newline at end of file
diff --git a/js/jquery.scrollmagic.min.js b/js/jquery.scrollmagic.min.js
index c8b4fa0c..76b1e0ca 100644
--- a/js/jquery.scrollmagic.min.js
+++ b/js/jquery.scrollmagic.min.js
@@ -1,2 +1,2 @@
-/* ScrollMagic v1.1.2 | (c) 2014 Jan Paepke (@janpaepke) | license & info: http://janpaepke.github.io/ScrollMagic */
-!function(e,t){"use strict";var r=function(r){var s,a="ScrollMagic",l={container:t,vertical:!0,globalSceneOptions:{},loglevel:2,refreshInterval:100},c=this,u=e.extend({},l,r),g=[],f=!1,h=0,d="PAUSED",p=!0,v=0,m=!1,w=!0,E=function(){if(e.each(u,function(e){l.hasOwnProperty(e)||delete u[e]}),u.container=e(u.container).first(),0===u.container.length)throw a+" init failed.";p=!e.contains(document,u.container.get(0)),v=u.vertical?u.container.height():u.container.width(),u.container.on("scroll resize",b);try{TweenLite.ticker.addEventListener("tick",F),m=!0}catch(r){u.container.on("scroll resize",F),m=!1}u.refreshInterval=parseInt(u.refreshInterval),u.refreshInterval>0&&(s=t.setInterval(T,u.refreshInterval))},S=function(){return u.vertical?u.container.scrollTop():u.container.scrollLeft()},y=function(e){u.vertical?u.container.scrollTop(e):u.container.scrollLeft(e)},F=function(){if(f&&w){var t=e.isArray(f)?f:g.slice(0),r=h;h=c.scrollPos();var n=h-r;d=0===n?"PAUSED":n>0?"FORWARD":"REVERSE",0>n&&t.reverse(),e.each(t,function(e,t){t.update(!0)}),0===t.length&&u.loglevel>=3,f=!1}},b=function(e){"resize"==e.type&&(v=u.vertical?u.container.height():u.container.width()),f=!0},T=function(){p||v!=(u.vertical?u.container.height():u.container.width())&&u.container.trigger("resize"),e.each(g,function(e,t){t.refresh()})},z=function(e){if(e.length<=1)return e;var t=e.slice(0);return t.sort(function(e,t){return e.scrollOffset()>t.scrollOffset()?1:-1}),t};return this.addScene=function(t){return e.isArray(t)?e.each(t,function(e,t){c.addScene(t)}):t instanceof n&&(t.parent()!=c?t.addTo(c):e.inArray(t,g)<0&&(g.push(t),g=z(g),t.on("shift."+a+"_sort",function(){g=z(g)}),e.each(u.globalSceneOptions,function(e,r){t[e]&&t[e].call(t,r)}))),c},this.removeScene=function(t){if(e.isArray(t))e.each(t,function(e,t){c.removeScene(t)});else{var r=e.inArray(t,g);r>-1&&(t.off("shift."+a+"_sort"),g.splice(r,1),t.remove())}return c},this.updateScene=function(t,r){return e.isArray(t)?e.each(t,function(e,t){c.updateScene(t,r)}):r?t.update(!0):(e.isArray(f)||(f=[]),-1==e.inArray(t,f)&&f.push(t),f=z(f)),c},this.update=function(e){return b({type:"resize"}),e&&F(),c},this.scrollTo=function(t){if(t instanceof n)t.parent()===c?c.scrollTo(t.scrollOffset()):log(2,"scrollTo(): The supplied scene does not belong to this controller. Scroll cancelled.",t);else if("string"===e.type(t)||o(t)||t instanceof e){var r=e(t).first();if(r[0]){var s=u.vertical?"top":"left",a=i(u.container),l=i(r);p||(a[s]-=c.scrollPos()),c.scrollTo(l[s]-a[s])}else log(2,"scrollTo(): The supplied element could not be found. Scroll cancelled.",t)}else e.isFunction(t)?y=t:y.call(u.container[0],t);return c},this.scrollPos=function(t){return arguments.length?(e.isFunction(t)&&(S=t),c):S.call(c)},this.info=function(e){var t={size:v,vertical:u.vertical,scrollPos:h,scrollDirection:d,container:u.container,isDocument:p};return arguments.length?void 0!==t[e]?t[e]:void 0:t},this.loglevel=function(e){return arguments.length?(u.loglevel!=e&&(u.loglevel=e),c):u.loglevel},this.enabled=function(e){return arguments.length?(w!=e&&(w=!!e,c.updateScene(g,!0)),c):w},this.destroy=function(e){t.clearTimeout(s);for(var r=g.length;r--;)g[r].destroy(e);return u.container.off("scroll resize",b),m?TweenLite.ticker.removeEventListener("tick",F):u.container.off("scroll resize",F),null},E(),c},n=function(n){var o,a,l,c,u,g,f,h={onCenter:.5,onEnter:1,onLeave:0},d="ScrollScene",p={duration:0,offset:0,triggerElement:null,triggerHook:"onCenter",reverse:!0,tweenChanges:!1,loglevel:2},v=this,m=e.extend({},p,n),w="BEFORE",E=0,S={start:0,end:0},y=0,F=!0,b={unknownOptionSupplied:function(){e.each(m,function(e){p.hasOwnProperty(e)||delete m[e]})},duration:function(){if(e.isFunction(m.duration)){o=m.duration;try{m.duration=parseFloat(o())}catch(t){o=void 0,m.duration=p.duration}}else m.duration=parseFloat(m.duration),(!e.isNumeric(m.duration)||m.duration<0)&&(m.duration=p.duration)},offset:function(){m.offset=parseFloat(m.offset),e.isNumeric(m.offset)||(m.offset=p.offset)},triggerElement:function(){null!==m.triggerElement&&0===e(m.triggerElement).length&&(m.triggerElement=p.triggerElement)},triggerHook:function(){m.triggerHook in h||(m.triggerHook=e.isNumeric(m.triggerHook)?Math.max(0,Math.min(parseFloat(m.triggerHook),1)):p.triggerHook)},reverse:function(){m.reverse=!!m.reverse},tweenChanges:function(){m.tweenChanges=!!m.tweenChanges}},T=function(){z(),v.on("change.internal",function(e){"loglevel"!==e.what&&"tweenChanges"!==e.what&&("triggerElement"===e.what?I():"reverse"===e.what&&v.update())}).on("shift.internal",function(e){C(),v.update(),("AFTER"===w&&"duration"===e.reason||"DURING"===w&&0===m.duration)&&x()}).on("progress.internal",function(){P(),x()}).on("destroy",function(e){e.preventDefault()})},z=function(t){if(arguments.length)e.isArray(t)||(t=[t]);else{t=[];for(var r in b)t.push(r)}e.each(t,function(e,t){b[t]&&b[t]()})},R=function(e,t){var r=!1,n=m[e];return m[e]!=t&&(m[e]=t,z(e),r=n!=m[e]),r},C=function(){S={start:y+m.offset},a&&m.triggerElement&&(S.start-=a.info("size")*v.triggerHook()),S.end=S.start+m.duration},D=function(e){if(o){var t="duration";R(t,o.call(v))&&!e&&(v.trigger("change",{what:t,newval:m[t]}),v.trigger("shift",{reason:t}))}},I=function(t){var r=0;if(a&&m.triggerElement){for(var n=e(m.triggerElement).first(),o=a.info(),s=i(o.container),l=o.vertical?"top":"left";n.parent().data("ScrollMagicPinSpacer");)n=n.parent();var c=i(n);o.isDocument||(s[l]-=a.scrollPos()),r=c[l]-s[l]}var u=r!=y;y=r,u&&!t&&v.trigger("shift",{reason:"triggerElementPosition"})},P=function(e){if(l){var t=e>=0&&1>=e?e:E;if(-1===l.repeat())if("DURING"===w&&l.paused())l.play();else{if("DURING"===w||l.paused())return!1;l.pause()}else{if(t==l.progress())return!1;0===m.duration?"DURING"===w?l.play():l.reverse():m.tweenChanges?l.tweenTo(t*l.duration()):l.progress(t).pause()}return!0}return!1},x=function(e){if(c&&a){var t=a.info();if(e||"DURING"!==w){var r={position:u.inFlow?"relative":"absolute",top:0,left:0},n=c.css("position")!=r.position;u.pushFollowers?m.duration>0&&("AFTER"===w&&0===parseFloat(u.spacer.css("padding-top"))?n=!0:"BEFORE"===w&&0===parseFloat(u.spacer.css("padding-bottom"))&&(n=!0)):r[t.vertical?"top":"left"]=m.duration*E,c.css(r),n&&(c.removeClass(u.pinnedClass),k())}else{"fixed"!=c.css("position")&&(c.css("position","fixed"),k(),c.addClass(u.pinnedClass));var o=i(u.spacer,!0),s=m.reverse||0===m.duration?t.scrollPos-S.start:Math.round(E*m.duration*10)/10;o.top-=parseFloat(u.spacer.css("margin-top")),o[t.vertical?"top":"left"]+=s,c.css({top:o.top,left:o.left})}}},k=function(){if(c&&a&&u.inFlow){var r="AFTER"===w,n="BEFORE"===w,i="DURING"===w,o="fixed"==c.css("position"),l=a.info("vertical"),g=u.spacer.children().first(),f=s(u.spacer.css("display")),h={};f?(h["margin-top"]=n||i&&o?c.css("margin-top"):"auto",h["margin-bottom"]=r||i&&o?c.css("margin-bottom"):"auto"):h["margin-top"]=h["margin-bottom"]="auto",u.relSize.width||u.relSize.autoFullWidth?o?e(t).width()==u.spacer.parent().width()?c.css("width",u.relSize.autoFullWidth?"100%":"inherit"):c.css("width",u.spacer.width()):c.css("width","100%"):(h["min-width"]=g.outerWidth(!g.is(c)),h.width=o?h["min-width"]:"auto"),u.relSize.height?o?e(t).height()==u.spacer.parent().height()?c.css("height","inherit"):c.css("height",u.spacer.height()):c.css("height","100%"):(h["min-height"]=g.outerHeight(!f),h.height=o?h["min-height"]:"auto"),u.pushFollowers&&(h["padding"+(l?"Top":"Left")]=m.duration*E,h["padding"+(l?"Bottom":"Right")]=m.duration*(1-E)),u.spacer.css(h)}},O=function(){a&&c&&"DURING"===w&&!a.info("isDocument")&&x()},N=function(){a&&c&&"DURING"===w&&((u.relSize.width||u.relSize.autoFullWidth)&&e(t).width()!=u.spacer.parent().width()||u.relSize.height&&e(t).height()!=u.spacer.parent().height())&&k()},U=function(e){a&&c&&"DURING"===w&&a.scrollTo(a.info("scrollPos")-(e.originalEvent.wheelDelta/3||30*-e.originalEvent.detail))};return this.parent=function(){return a},this.duration=function(t){var r="duration";return arguments.length?(e.isFunction(t)||(o=void 0),R(r,t)&&(v.trigger("change",{what:r,newval:m[r]}),v.trigger("shift",{reason:r})),v):m[r]},this.offset=function(e){var t="offset";return arguments.length?(R(t,e)&&(v.trigger("change",{what:t,newval:m[t]}),v.trigger("shift",{reason:t})),v):m[t]},this.triggerElement=function(e){var t="triggerElement";return arguments.length?(R(t,e)&&v.trigger("change",{what:t,newval:m[t]}),v):m[t]},this.triggerHook=function(t){var r="triggerHook";return arguments.length?(R(r,t)&&(v.trigger("change",{what:r,newval:m[r]}),v.trigger("shift",{reason:r})),v):e.isNumeric(m[r])?m[r]:h[m[r]]},this.reverse=function(e){var t="reverse";return arguments.length?(R(t,e)&&v.trigger("change",{what:t,newval:m[t]}),v):m[t]},this.tweenChanges=function(e){var t="tweenChanges";return arguments.length?(R(t,e)&&v.trigger("change",{what:t,newval:m[t]}),v):m[t]},this.loglevel=function(e){var t="loglevel";return arguments.length?(R(t,e)&&v.trigger("change",{what:t,newval:m[t]}),v):m[t]},this.state=function(){return w},this.triggerPosition=function(){var e=m.offset;return a&&(e+=m.triggerElement?y:a.info("size")*v.triggerHook()),e},this.triggerOffset=function(){return v.triggerPosition()},this.scrollOffset=function(){return S.start},this.update=function(e){if(a)if(e)if(a.enabled()&&F){var t,r=a.info("scrollPos");t=m.duration>0?(r-S.start)/(S.end-S.start):r>=S.start?1:0,v.trigger("update",{startPos:S.start,endPos:S.end,scrollPos:r}),v.progress(t)}else c&&"DURING"===w&&x(!0);else a.updateScene(v,!1);return v},this.refresh=function(){return D(),I(),v},this.progress=function(e){if(arguments.length){var t=!1,r=w,n=a?a.info("scrollDirection"):"PAUSED",i=m.reverse||e>=E;if(0===m.duration?(t=E!=e,E=1>e&&i?0:1,w=0===E?"BEFORE":"DURING"):0>=e&&"BEFORE"!==w&&i?(E=0,w="BEFORE",t=!0):e>0&&1>e&&i?(E=e,w="DURING",t=!0):e>=1&&"AFTER"!==w?(E=1,w="AFTER",t=!0):"DURING"!==w||i||x(),t){var o={progress:E,state:w,scrollDirection:n},s=w!=r,l=function(e){v.trigger(e,o)};s&&"DURING"!==r&&(l("enter"),l("BEFORE"===r?"start":"end")),l("progress"),s&&"DURING"!==w&&(l("BEFORE"===w?"start":"end"),l("leave"))}return v}return E},this.setTween=function(e){l&&v.removeTween();try{l=new TimelineMax({smoothChildTiming:!0}).add(e).pause()}catch(t){}finally{return e.repeat&&-1===e.repeat()&&(l.repeat(-1),l.yoyo(e.yoyo())),z("checkIfTriggerElementIsTweened"),P(),v}},this.removeTween=function(e){return l&&(e&&P(0),l.kill(),l=void 0),v},this.setPin=function(r,n){var i={pushFollowers:!0,spacerClass:"scrollmagic-pin-spacer",pinnedClass:""};if(n=e.extend({},i,n),r=e(r).first(),0===r.length)return v;if("fixed"==r.css("position"))return v;if(c){if(c===r)return v;v.removePin()}c=r,c.parent().hide();var o="absolute"!=c.css("position"),a=c.css(["display","top","left","bottom","right"]),l=c.css(["width","height"]);c.parent().show(),"0px"===l.width&&o&&s(a.display),!o&&n.pushFollowers&&(n.pushFollowers=!1);var g=e("").addClass(n.spacerClass).css(a).data("ScrollMagicPinSpacer",!0).css({position:o?"relative":"absolute","margin-left":"auto","margin-right":"auto","box-sizing":"content-box"}),f=c[0].style;return u={spacer:g,relSize:{width:"%"===l.width.slice(-1),height:"%"===l.height.slice(-1),autoFullWidth:"0px"===l.width&&o&&s(a.display)},pushFollowers:n.pushFollowers,inFlow:o,origStyle:{width:f.width||"",position:f.position||"",top:f.top||"",left:f.left||"",bottom:f.bottom||"",right:f.right||"","box-sizing":f["box-sizing"]||"","-moz-box-sizing":f["-moz-box-sizing"]||"","-webkit-box-sizing":f["-webkit-box-sizing"]||""},pinnedClass:n.pinnedClass},u.relSize.width&&g.css("width",l.width),u.relSize.height&&g.css("height",l.height),c.before(g).appendTo(g).css({position:o?"relative":"absolute",top:"auto",left:"auto",bottom:"auto",right:"auto"}),(u.relSize.width||u.relSize.autoFullWidth)&&c.css("box-sizing","border-box"),e(t).on("scroll."+d+"_pin resize."+d+"_pin",O),c.on("mousewheel DOMMouseScroll",U),x(),v},this.removePin=function(r){return c&&(r||!a?(c.insertBefore(u.spacer).css(u.origStyle),u.spacer.remove()):"DURING"===w&&x(!0),e(t).off("scroll."+d+"_pin resize."+d+"_pin"),c.off("mousewheel DOMMouseScroll",U),c=void 0),v},this.setClassToggle=function(t,r){var n=e(t);return 0===n.length||"string"!==e.type(r)?v:(g=r,f=n,v.on("enter.internal_class leave.internal_class",function(e){f.toggleClass(g,"enter"===e.type)}),v)},this.removeClassToggle=function(e){return f&&e&&f.removeClass(g),v.off("start.internal_class end.internal_class"),g=void 0,f=void 0,v},this.addTo=function(e){return e instanceof r&&a!=e&&(a&&a.removeScene(v),a=e,z(),D(!0),I(!0),C(),k(),a.info("container").on("resize."+d,function(){N(),v.triggerHook()>0&&v.trigger("shift",{reason:"containerSize"})}),e.addScene(v),v.update()),v},this.enabled=function(e){return arguments.length?(F!=e&&(F=!!e,v.update(!0)),v):F},this.remove=function(){if(a){a.info("container").off("resize."+d);var e=a;a=void 0,e.removeScene(v)}return v},this.destroy=function(e){return v.removeTween(e),v.removePin(e),v.removeClassToggle(e),v.trigger("destroy",{reset:e}),v.remove(),v.off("start end enter leave progress change update shift destroy shift.internal change.internal progress.internal"),null},this.on=function(t,r){if(e.isFunction(r)){var n=e.trim(t).toLowerCase().replace(/(\w+)\.(\w+)/g,"$1."+d+"_$2").replace(/( |^)(\w+)(?= |$)/g,"$1$2."+d);e(v).on(n,r)}return v},this.off=function(t,r){var n=e.trim(t).toLowerCase().replace(/(\w+)\.(\w+)/g,"$1."+d+"_$2").replace(/( |^)(\w+)(?= |$)/g,"$1$2."+d+"$3");return e(v).off(n,r),v},this.trigger=function(t,r){var n=e.Event(e.trim(t).toLowerCase(),r);return e(v).trigger(n),v},T(),v};r.prototype.version="1.1.2",t.ScrollScene=n,t.ScrollMagic=r;var i=function(t,r){var n={top:0,left:0},i=t[0];if(i)if(i.getBoundingClientRect){var o=i.getBoundingClientRect();n.top=o.top,n.left=o.left,r||(n.top+=e(document).scrollTop(),n.left+=e(document).scrollLeft())}else n=t.offset()||n,r&&(n.top-=e(document).scrollTop(),n.left-=e(document).scrollLeft());return n},o=function(e){return"object"==typeof HTMLElement?e instanceof HTMLElement:e&&"object"==typeof e&&null!==e&&1===e.nodeType&&"string"==typeof e.nodeName},s=function(e){return["block","flex","list-item","table","-webkit-box"].indexOf(e)>-1}}(jQuery,window);
\ No newline at end of file
+/* ScrollMagic v1.2.0 | (c) 2014 Jan Paepke (@janpaepke) | license & info: http://janpaepke.github.io/ScrollMagic */
+!function(e){"use strict";var t,n,r=e.define;"function"==typeof r&&r.amd||(r=function(t,n,r){for(var i,o=0;o0&&(s=window.setInterval(R,g.refreshInterval)),r=a(T)},F=function(){return g.vertical?g.container.scrollTop():g.container.scrollLeft()},S=function(e){g.vertical?g.container.scrollTop(e):g.container.scrollLeft(e)},T=function(){if(y&&d){var t=e.isArray(d)?d:h.slice(0),n=p;p=f.scrollPos();var i=p-n;v=0===i?"PAUSED":i>0?"FORWARD":"REVERSE",0>i&&t.reverse(),e.each(t,function(e,t){t.update(!0)}),0===t.length&&g.loglevel>=3,d=!1}r=a(T)},b=function(e){"resize"==e.type&&(m=g.vertical?g.container.height():g.container.width()),d=!0},R=function(){w||m!=(g.vertical?g.container.height():g.container.width())&&g.container.trigger("resize"),e.each(h,function(e,t){t.refresh()})},z=function(e){if(e.length<=1)return e;var t=e.slice(0);return t.sort(function(e,t){return e.scrollOffset()>t.scrollOffset()?1:-1}),t};return this.addScene=function(t){return e.isArray(t)?e.each(t,function(e,t){f.addScene(t)}):t instanceof n&&(t.parent()!=f?t.addTo(f):e.inArray(t,h)<0&&(h.push(t),h=z(h),t.on("shift."+c+"_sort",function(){h=z(h)}),e.each(g.globalSceneOptions,function(e,n){t[e]&&t[e].call(t,n)}))),f},this.removeScene=function(t){if(e.isArray(t))e.each(t,function(e,t){f.removeScene(t)});else{var n=e.inArray(t,h);n>-1&&(t.off("shift."+c+"_sort"),h.splice(n,1),t.remove())}return f},this.updateScene=function(t,n){return e.isArray(t)?e.each(t,function(e,t){f.updateScene(t,n)}):n?t.update(!0):(e.isArray(d)||(d=[]),-1==e.inArray(t,d)&&d.push(t),d=z(d)),f},this.update=function(e){return b({type:"resize"}),e&&T(),f},this.scrollTo=function(t){if(t instanceof n)t.parent()===f?f.scrollTo(t.scrollOffset()):log(2,"scrollTo(): The supplied scene does not belong to this controller. Scroll cancelled.",t);else if("string"===e.type(t)||o(t)||t instanceof e){var r=e(t).first();if(r[0]){var s=g.vertical?"top":"left",a=i(g.container),l=i(r);w||(a[s]-=f.scrollPos()),f.scrollTo(l[s]-a[s])}else log(2,"scrollTo(): The supplied element could not be found. Scroll cancelled.",t)}else e.isFunction(t)?S=t:S.call(g.container[0],t);return f},this.scrollPos=function(t){return arguments.length?(e.isFunction(t)&&(F=t),f):F.call(f)},this.info=function(e){var t={size:m,vertical:g.vertical,scrollPos:p,scrollDirection:v,container:g.container,isDocument:w};return arguments.length?void 0!==t[e]?t[e]:void 0:t},this.loglevel=function(e){return arguments.length?(g.loglevel!=e&&(g.loglevel=e),f):g.loglevel},this.enabled=function(e){return arguments.length?(y!=e&&(y=!!e,f.updateScene(h,!0)),f):y},this.destroy=function(e){window.clearTimeout(s);for(var t=h.length;t--;)h[t].destroy(e);return g.container.off("scroll resize",b),l(r),null},E(),f.version="1.2.0",f},t.version="1.2.0",t}),r("ScrollScene",["jquery","TweenMax","TimelineMax"],function(e,r,o){return n=function(n){var r,a,l,c,u,f,g,h={onCenter:.5,onEnter:1,onLeave:0},d="ScrollScene",p={duration:0,offset:0,triggerElement:null,triggerHook:"onCenter",reverse:!0,tweenChanges:!1,loglevel:2},v=this,w=e.extend({},p,n),m="BEFORE",y=0,E={start:0,end:0},F=0,S=!0,T={unknownOptionSupplied:function(){e.each(w,function(e){p.hasOwnProperty(e)||delete w[e]})},duration:function(){if(e.isFunction(w.duration)){r=w.duration;try{w.duration=parseFloat(r())}catch(t){r=void 0,w.duration=p.duration}}else w.duration=parseFloat(w.duration),(!e.isNumeric(w.duration)||w.duration<0)&&(w.duration=p.duration)},offset:function(){w.offset=parseFloat(w.offset),e.isNumeric(w.offset)||(w.offset=p.offset)},triggerElement:function(){null!==w.triggerElement&&0===e(w.triggerElement).length&&(w.triggerElement=p.triggerElement)},triggerHook:function(){w.triggerHook in h||(w.triggerHook=e.isNumeric(w.triggerHook)?Math.max(0,Math.min(parseFloat(w.triggerHook),1)):p.triggerHook)},reverse:function(){w.reverse=!!w.reverse},tweenChanges:function(){w.tweenChanges=!!w.tweenChanges}},b=function(){R(),v.on("change.internal",function(e){"loglevel"!==e.what&&"tweenChanges"!==e.what&&("triggerElement"===e.what?x():"reverse"===e.what&&v.update())}).on("shift.internal",function(e){C(),v.update(),("AFTER"===m&&"duration"===e.reason||"DURING"===m&&0===w.duration)&&A()}).on("progress.internal",function(){P(),A()}).on("destroy",function(e){e.preventDefault()})},R=function(t){if(arguments.length)e.isArray(t)||(t=[t]);else{t=[];for(var n in T)t.push(n)}e.each(t,function(e,t){T[t]&&T[t]()})},z=function(e,t){var n=!1,r=w[e];return w[e]!=t&&(w[e]=t,R(e),n=r!=w[e]),n},C=function(){E={start:F+w.offset},a&&w.triggerElement&&(E.start-=a.info("size")*v.triggerHook()),E.end=E.start+w.duration},D=function(e){if(r){var t="duration";z(t,r.call(v))&&!e&&(v.trigger("change",{what:t,newval:w[t]}),v.trigger("shift",{reason:t}))}},x=function(t){var n=0;if(a&&w.triggerElement){for(var r=e(w.triggerElement).first(),o=a.info(),s=i(o.container),l=o.vertical?"top":"left";r.parent().data("ScrollMagicPinSpacer");)r=r.parent();var c=i(r);o.isDocument||(s[l]-=a.scrollPos()),n=c[l]-s[l]}var u=n!=F;F=n,u&&!t&&v.trigger("shift",{reason:"triggerElementPosition"})},P=function(e){if(l){var t=e>=0&&1>=e?e:y;if(-1===l.repeat())if("DURING"===m&&l.paused())l.play();else{if("DURING"===m||l.paused())return!1;l.pause()}else{if(t==l.progress())return!1;0===w.duration?"DURING"===m?l.play():l.reverse():w.tweenChanges?l.tweenTo(t*l.duration()):l.progress(t).pause()}return!0}return!1},A=function(e){if(c&&a){var t=a.info();if(e||"DURING"!==m){var n={position:u.inFlow?"relative":"absolute",top:0,left:0},r=c.css("position")!=n.position;u.pushFollowers?w.duration>0&&("AFTER"===m&&0===parseFloat(u.spacer.css("padding-top"))?r=!0:"BEFORE"===m&&0===parseFloat(u.spacer.css("padding-bottom"))&&(r=!0)):n[t.vertical?"top":"left"]=w.duration*y,c.css(n),r&&(c.removeClass(u.pinnedClass),O())}else{"fixed"!=c.css("position")&&(c.css("position","fixed"),O(),c.addClass(u.pinnedClass));var o=i(u.spacer,!0),s=w.reverse||0===w.duration?t.scrollPos-E.start:Math.round(y*w.duration*10)/10;o.top-=parseFloat(u.spacer.css("margin-top")),o[t.vertical?"top":"left"]+=s,c.css({top:o.top,left:o.left})}}},O=function(){if(c&&a&&u.inFlow){var t="AFTER"===m,n="BEFORE"===m,r="DURING"===m,i="fixed"==c.css("position"),o=a.info("vertical"),l=u.spacer.children().first(),f=s(u.spacer.css("display")),g={};f?(g["margin-top"]=n||r&&i?c.css("margin-top"):"auto",g["margin-bottom"]=t||r&&i?c.css("margin-bottom"):"auto"):g["margin-top"]=g["margin-bottom"]="auto",u.relSize.width||u.relSize.autoFullWidth?i?e(window).width()==u.spacer.parent().width()?c.css("width",u.relSize.autoFullWidth?"100%":"inherit"):c.css("width",u.spacer.width()):c.css("width","100%"):(g["min-width"]=l.outerWidth(!l.is(c)),g.width=i?g["min-width"]:"auto"),u.relSize.height?i?e(window).height()==u.spacer.parent().height()?c.css("height","inherit"):c.css("height",u.spacer.height()):c.css("height","100%"):(g["min-height"]=l.outerHeight(!f),g.height=i?g["min-height"]:"auto"),u.pushFollowers&&(g["padding"+(o?"Top":"Left")]=w.duration*y,g["padding"+(o?"Bottom":"Right")]=w.duration*(1-y)),u.spacer.css(g)}},I=function(){a&&c&&"DURING"===m&&!a.info("isDocument")&&A()},N=function(){a&&c&&"DURING"===m&&((u.relSize.width||u.relSize.autoFullWidth)&&e(window).width()!=u.spacer.parent().width()||u.relSize.height&&e(window).height()!=u.spacer.parent().height())&&O()},k=function(e){a&&c&&"DURING"===m&&!a.info("isDocument")&&(e.preventDefault(),a.scrollTo(a.info("scrollPos")-(e.originalEvent.wheelDelta/3||30*-e.originalEvent.detail)))};return this.parent=function(){return a},this.duration=function(t){var n="duration";return arguments.length?(e.isFunction(t)||(r=void 0),z(n,t)&&(v.trigger("change",{what:n,newval:w[n]}),v.trigger("shift",{reason:n})),v):w[n]},this.offset=function(e){var t="offset";return arguments.length?(z(t,e)&&(v.trigger("change",{what:t,newval:w[t]}),v.trigger("shift",{reason:t})),v):w[t]},this.triggerElement=function(e){var t="triggerElement";return arguments.length?(z(t,e)&&v.trigger("change",{what:t,newval:w[t]}),v):w[t]},this.triggerHook=function(t){var n="triggerHook";return arguments.length?(z(n,t)&&(v.trigger("change",{what:n,newval:w[n]}),v.trigger("shift",{reason:n})),v):e.isNumeric(w[n])?w[n]:h[w[n]]},this.reverse=function(e){var t="reverse";return arguments.length?(z(t,e)&&v.trigger("change",{what:t,newval:w[t]}),v):w[t]},this.tweenChanges=function(e){var t="tweenChanges";return arguments.length?(z(t,e)&&v.trigger("change",{what:t,newval:w[t]}),v):w[t]},this.loglevel=function(e){var t="loglevel";return arguments.length?(z(t,e)&&v.trigger("change",{what:t,newval:w[t]}),v):w[t]},this.state=function(){return m},this.triggerPosition=function(){var e=w.offset;return a&&(e+=w.triggerElement?F:a.info("size")*v.triggerHook()),e},this.triggerOffset=function(){return v.triggerPosition()},this.scrollOffset=function(){return E.start},this.update=function(e){if(a)if(e)if(a.enabled()&&S){var t,n=a.info("scrollPos");t=w.duration>0?(n-E.start)/(E.end-E.start):n>=E.start?1:0,v.trigger("update",{startPos:E.start,endPos:E.end,scrollPos:n}),v.progress(t)}else c&&"DURING"===m&&A(!0);else a.updateScene(v,!1);return v},this.refresh=function(){return D(),x(),v},this.progress=function(e){if(arguments.length){var t=!1,n=m,r=a?a.info("scrollDirection"):"PAUSED",i=w.reverse||e>=y;if(0===w.duration?(t=y!=e,y=1>e&&i?0:1,m=0===y?"BEFORE":"DURING"):0>=e&&"BEFORE"!==m&&i?(y=0,m="BEFORE",t=!0):e>0&&1>e&&i?(y=e,m="DURING",t=!0):e>=1&&"AFTER"!==m?(y=1,m="AFTER",t=!0):"DURING"!==m||i||A(),t){var o={progress:y,state:m,scrollDirection:r},s=m!=n,l=function(e){v.trigger(e,o)};s&&"DURING"!==n&&(l("enter"),l("BEFORE"===n?"start":"end")),l("progress"),s&&"DURING"!==m&&(l("BEFORE"===m?"start":"end"),l("leave"))}return v}return y},this.setTween=function(e){l&&v.removeTween();try{l=new o({smoothChildTiming:!0}).add(e).pause()}catch(t){}finally{e.repeat&&-1===e.repeat()&&(l.repeat(-1),l.yoyo(e.yoyo()))}return P(),v},this.removeTween=function(e){return l&&(e&&P(0),l.kill(),l=void 0),v},this.setPin=function(t,n){var r={pushFollowers:!0,spacerClass:"scrollmagic-pin-spacer",pinnedClass:""};if(n=e.extend({},r,n),t=e(t).first(),0===t.length)return v;if("fixed"==t.css("position"))return v;if(c){if(c===t)return v;v.removePin()}c=t,c.parent().hide();var i="absolute"!=c.css("position"),o=c.css(["display","top","left","bottom","right"]),a=c.css(["width","height"]);c.parent().show(),"0px"===a.width&&i&&s(o.display),!i&&n.pushFollowers&&(n.pushFollowers=!1);var l=e("").addClass(n.spacerClass).css(o).data("ScrollMagicPinSpacer",!0).css({position:i?"relative":"absolute","margin-left":"auto","margin-right":"auto","box-sizing":"content-box"}),f=c[0].style;return u={spacer:l,relSize:{width:"%"===a.width.slice(-1),height:"%"===a.height.slice(-1),autoFullWidth:"0px"===a.width&&i&&s(o.display)},pushFollowers:n.pushFollowers,inFlow:i,origStyle:{width:f.width||"",position:f.position||"",top:f.top||"",left:f.left||"",bottom:f.bottom||"",right:f.right||"","box-sizing":f["box-sizing"]||"","-moz-box-sizing":f["-moz-box-sizing"]||"","-webkit-box-sizing":f["-webkit-box-sizing"]||""},pinnedClass:n.pinnedClass},u.relSize.width&&l.css("width",a.width),u.relSize.height&&l.css("height",a.height),c.before(l).appendTo(l).css({position:i?"relative":"absolute",top:"auto",left:"auto",bottom:"auto",right:"auto"}),(u.relSize.width||u.relSize.autoFullWidth)&&c.css("box-sizing","border-box"),e(window).on("scroll."+d+"_pin resize."+d+"_pin",I),c.on("mousewheel DOMMouseScroll",k),A(),v},this.removePin=function(t){return c&&(t||!a?(c.insertBefore(u.spacer).css(u.origStyle),u.spacer.remove()):"DURING"===m&&A(!0),e(window).off("scroll."+d+"_pin resize."+d+"_pin"),c.off("mousewheel DOMMouseScroll",k),c=void 0),v},this.setClassToggle=function(t,n){var r=e(t);return 0===r.length||"string"!==e.type(n)?v:(f=n,g=r,v.on("enter.internal_class leave.internal_class",function(e){g.toggleClass(f,"enter"===e.type)}),v)},this.removeClassToggle=function(e){return g&&e&&g.removeClass(f),v.off("start.internal_class end.internal_class"),f=void 0,g=void 0,v},this.addTo=function(e){return e instanceof t&&a!=e&&(a&&a.removeScene(v),a=e,R(),D(!0),x(!0),C(),O(),a.info("container").on("resize."+d,function(){N(),v.triggerHook()>0&&v.trigger("shift",{reason:"containerSize"})}),e.addScene(v),v.update()),v},this.enabled=function(e){return arguments.length?(S!=e&&(S=!!e,v.update(!0)),v):S},this.remove=function(){if(a){a.info("container").off("resize."+d);var e=a;a=void 0,e.removeScene(v)}return v},this.destroy=function(e){return v.removeTween(e),v.removePin(e),v.removeClassToggle(e),v.trigger("destroy",{reset:e}),v.remove(),v.off("start end enter leave progress change update shift destroy shift.internal change.internal progress.internal"),null},this.on=function(t,n){if(e.isFunction(n)){var r=e.trim(t).toLowerCase().replace(/(\w+)\.(\w+)/g,"$1."+d+"_$2").replace(/( |^)(\w+)(?= |$)/g,"$1$2."+d);e(v).on(r,n)}return v},this.off=function(t,n){var r=e.trim(t).toLowerCase().replace(/(\w+)\.(\w+)/g,"$1."+d+"_$2").replace(/( |^)(\w+)(?= |$)/g,"$1$2."+d+"$3");return e(v).off(r,n),v},this.trigger=function(t,n){var r=e.Event(e.trim(t).toLowerCase(),n);return e(v).trigger(r),v},b(),v}});var i=function(e,t){var n={top:0,left:0};if(e=e[0],e&&e.getBoundingClientRect){var r=e.getBoundingClientRect();n.top=r.top,n.left=r.left,t||(n.top+=(window.pageYOffset||document.scrollTop||0)-(document.clientTop||0),n.left+=(window.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0))}return n},o=function(e){return"object"==typeof HTMLElement?e instanceof HTMLElement:e&&"object"==typeof e&&null!==e&&1===e.nodeType&&"string"==typeof e.nodeName},s=function(e){return["block","flex","list-item","table","-webkit-box"].indexOf(e)>-1},a=window.requestAnimationFrame,l=window.cancelAnimationFrame;!function(e){var t,n=0,r=["ms","moz","webkit","o"];for(t=0;!a&&t
/* -ScrollMagic v1.1.2 +ScrollMagic v1.2.0 The jQuery plugin for doing magical scroll interactions. (c) 2014 Jan Paepke (@janpaepke) License & Info: http://janpaepke.github.io/ScrollMagic @@ -120,11 +121,19 @@+}));Source: jquery.scrollmagic.debug.js
*/ /* @overview Debug Extension for ScrollMagic. - @version 1.1.2 + @version 1.2.0 @license Dual licensed under MIT license and GPL. @author Jan Paepke - e-mail@janpaepke.de */ -(function($, ScrollScene) { +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['ScrollScene', 'jquery'], factory); + } else { + // no browser global needed, just execute + factory(root.ScrollScene, root.jQuery); + } +}(this, function(ScrollScene, $) { /** * Add Indicators for a ScrollScene. * __REQUIRES__ ScrollMagic Debug Extension: `jquery.scrollmagic.debug.js` @@ -356,7 +365,7 @@Source: jquery.scrollmagic.debug.js
} } }; -})(jQuery, ScrollScene);
/* -ScrollMagic v1.1.2 +ScrollMagic v1.2.0 The jQuery plugin for doing magical scroll interactions. (c) 2014 Jan Paepke (@janpaepke) License & Info: http://janpaepke.github.io/ScrollMagic @@ -120,7 +121,7 @@+})(this || window);Source: jquery.scrollmagic.js
*/ /** @overview ##Info -@version 1.1.2 +@version 1.2.0 @license Dual licensed under MIT license and GPL. @author Jan Paepke - e-mail@janpaepke.de @@ -129,10 +130,26 @@Source: jquery.scrollmagic.js
@todo: bug: having multiple scroll directions with cascaded pins doesn't work (one scroll vertical, one horizontal) @todo: feature: optimize performance on debug plugin (huge drawbacks, when using many scenes) */ -(function($, window) { +(function(root) { "use strict"; + var define = root.define, ScrollMagic, ScrollScene; + if (typeof define !== 'function' || !define.amd) { + // No AMD loader -> Provide custom method to to register browser globals instead + define = function (moduleName, dependencies, factory) { + for (var x = 0, dependency; x<dependencies.length; x++) { + dependency = dependencies[x]; + if (dependency === 'jquery') { // lowercase with require, but camel case as global + dependency = 'jQuery'; + } + dependencies[x] = root[dependency]; + } + root[moduleName] = factory.apply(root, dependencies); + }; + } + +define('ScrollMagic', ['jquery', 'TweenMax', 'TimelineMax'], function ($, TweenMax, TimelineMax) { /** * The main class that is needed once per scroll container. * @@ -155,12 +172,12 @@Source: jquery.scrollmagic.js
** `1` => errors ** `2` => errors, warnings ** `3` => errors, warnings, debuginfo - * @param {boolean} [options._refreshInterval=100] - Some changes don't call events by default, like changing the container size or moving a scene trigger element. + * @param {boolean} [options.refreshInterval=100] - Some changes don't call events by default, like changing the container size or moving a scene trigger element. This interval polls these parameters to fire the necessary events. If you don't use custom containers, trigger elements or have static layouts, where the positions of the trigger elements don't change, you can set this to 0 disable interval checking and improve performance. * */ - var ScrollMagic = function(options) { + ScrollMagic = function(options) { /* * ---------------------------------------------------------------- @@ -187,13 +204,13 @@Source: jquery.scrollmagic.js
ScrollMagic = this, _options = $.extend({}, DEFAULT_OPTIONS, options), _sceneObjects = [], - _updateScenesOnNextTick = false, // can be boolean (true => all scenes) or an array of scenes to be updated + _updateScenesOnNextCycle = false, // can be boolean (true => all scenes) or an array of scenes to be updated _scrollPos = 0, _scrollDirection = "PAUSED", _isDocument = true, _viewPortSize = 0, - _tickerUsed = false, _enabled = true, + _updateCycle, _refreshInterval; /* @@ -224,19 +241,14 @@Source: jquery.scrollmagic.js
_viewPortSize = _options.vertical ? _options.container.height() : _options.container.width(); // set event handlers _options.container.on("scroll resize", onChange); - try { - TweenLite.ticker.addEventListener("tick", onTick); // prefer TweenMax Ticker, but don't rely on it for basic functionality - _tickerUsed = true; - } catch (e) { - _options.container.on("scroll resize", onTick); // okay then just update on scroll/resize... - _tickerUsed = false; - } _options.refreshInterval = parseInt(_options.refreshInterval); if (_options.refreshInterval > 0) { _refreshInterval = window.setInterval(refresh, _options.refreshInterval); } + // start checking for changes + _updateCycle = animationFrameCallback(updateScenes); log(3, "added new " + NAMESPACE + " controller (v" + ScrollMagic.version + ")"); }; @@ -260,13 +272,13 @@Source: jquery.scrollmagic.js
}; /** - * Handle updates on tick instead of on scroll (performance) + * Handle updates in cycles instead of on scroll (performance) * @private */ - var onTick = function (e) { - if (_updateScenesOnNextTick && _enabled) { + var updateScenes = function () { + if (_enabled && _updateScenesOnNextCycle) { var - scenesToUpdate = $.isArray(_updateScenesOnNextTick) ? _updateScenesOnNextTick : _sceneObjects.slice(0), + scenesToUpdate = $.isArray(_updateScenesOnNextCycle) ? _updateScenesOnNextCycle : _sceneObjects.slice(0), oldScrollPos = _scrollPos; // update scroll pos & direction _scrollPos = ScrollMagic.scrollPos(); @@ -283,8 +295,9 @@Source: jquery.scrollmagic.js
if (scenesToUpdate.length === 0 && _options.loglevel >= 3) { log(3, "updating 0 Scenes (nothing added to controller)"); } - _updateScenesOnNextTick = false; + _updateScenesOnNextCycle = false; } + _updateCycle = animationFrameCallback(updateScenes); }; /** @@ -295,7 +308,7 @@Source: jquery.scrollmagic.js
if (e.type == "resize") { _viewPortSize = _options.vertical ? _options.container.height() : _options.container.width(); } - _updateScenesOnNextTick = true; + _updateScenesOnNextCycle = true; }; var refresh = function () { @@ -436,18 +449,18 @@Source: jquery.scrollmagic.js
* _**Note:** This method gets called constantly whenever ScrollMagic detects a change. The only application for you is if you change something outside of the realm of ScrollMagic, like moving the trigger or changing tween parameters._ * @public * @example - * // update a specific scene on next tick + * // update a specific scene on next cycle * controller.updateScene(scene); * * // update a specific scene immediately * controller.updateScene(scene, true); * - * // update multiple scenes scene on next tick + * // update multiple scenes scene on next cycle * controller.updateScene([scene1, scene2, scene3]); * * @param {ScrollScene} ScrollScene - ScrollScene or Array of ScrollScenes that is/are supposed to be updated. - * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick. - This is useful when changing multiple properties of the scene - this way it will only be updated once all new properties are set (onTick). + * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle. + This is useful when changing multiple properties of the scene - this way it will only be updated once all new properties are set (updateScenes). * @return {ScrollMagic} Parent object for chaining. */ this.updateScene = function (ScrollScene, immediately) { @@ -460,13 +473,13 @@Source: jquery.scrollmagic.js
ScrollScene.update(true); } else { // prep array for next update cycle - if (!$.isArray(_updateScenesOnNextTick)) { - _updateScenesOnNextTick = []; + if (!$.isArray(_updateScenesOnNextCycle)) { + _updateScenesOnNextCycle = []; } - if ($.inArray(ScrollScene, _updateScenesOnNextTick) == -1) { - _updateScenesOnNextTick.push(ScrollScene); + if ($.inArray(ScrollScene, _updateScenesOnNextCycle) == -1) { + _updateScenesOnNextCycle.push(ScrollScene); } - _updateScenesOnNextTick = sortScenes(_updateScenesOnNextTick); // sort + _updateScenesOnNextCycle = sortScenes(_updateScenesOnNextCycle); // sort } } return ScrollMagic; @@ -481,19 +494,19 @@Source: jquery.scrollmagic.js
* For this case there will also be the need to provide a custom function to calculate the correct scroll position. See `ScrollMagic.scrollPos()` for details. * @public * @example - * // update the controller on next tick (saves performance) + * // update the controller on next cycle (saves performance due to elimination of redundant updates) * controller.update(); * * // update the controller immediately * controller.update(true); * - * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick (better performance) + * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance) * @return {ScrollMagic} Parent object for chaining. */ this.update = function (immediately) { - onChange({type: "resize"}); // will update size and set _updateScenesOnNextTick to true + onChange({type: "resize"}); // will update size and set _updateScenesOnNextCycle to true if (immediately) { - onTick(); + updateScenes(); } return ScrollMagic; }; @@ -565,7 +578,7 @@Source: jquery.scrollmagic.js
* **Get** the current scrollPosition or **Set** a new method to calculate it. * -> **GET**: * When used as a getter this function will return the current scroll position. - * To get a cached value use ScrollMagic.info("scrollPos"), which will be updated on tick to save on performance. + * To get a cached value use ScrollMagic.info("scrollPos"), which will be updated in the update cycle. * For vertical controllers it will return the top scroll offset and for horizontal applications it will return the left offset. * * -> **SET**: @@ -711,20 +724,21 @@Source: jquery.scrollmagic.js
_sceneObjects[i].destroy(resetScenes); } _options.container.off("scroll resize", onChange); - if (_tickerUsed) { - TweenLite.ticker.removeEventListener("tick", onTick); - } else { - _options.container.off("scroll resize", onTick); - } + animationFrameCancelCallback(_updateCycle); log(3, "destroyed " + NAMESPACE + " (reset: " + (resetScenes ? "true" : "false") + ")"); return null; }; // INIT construct(); + ScrollMagic.version = "1.2.0"; // version number for each instance return ScrollMagic; }; + ScrollMagic.version = "1.2.0"; // version number for browser global + return ScrollMagic; +}); +define('ScrollScene', ['jquery', 'TweenMax', 'TimelineMax'], function ($, TweenMax, TimelineMax) { /** * A ScrollScene defines where the controller should react and how. * @@ -767,7 +781,7 @@Source: jquery.scrollmagic.js
** `3` => errors, warnings, debuginfo * */ - var ScrollScene = function (options) { + ScrollScene = function (options) { /* * ---------------------------------------------------------------- @@ -875,23 +889,6 @@Source: jquery.scrollmagic.js
log(1, "ERROR: Invalid value for option \"loglevel\":", wrongval); } }, - "checkIfTriggerElementIsTweened" : function () { - // check if there are position tweens defined for the trigger and warn about it :) - if (_tween && _parent && _options.triggerElement && _options.loglevel >= 2) {// parent is needed to know scroll direction. - var - triggerTweens = _tween.getTweensOf($(_options.triggerElement)), - vertical = _parent.info("vertical"); - $.each(triggerTweens, function (index, value) { - var - tweenvars = value.vars.css || value.vars, - condition = vertical ? (tweenvars.top !== undefined || tweenvars.bottom !== undefined) : (tweenvars.left !== undefined || tweenvars.right !== undefined); - if (condition) { - log(2, "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!"); - return false; - } - }); - } - }, }; /* @@ -1285,12 +1282,13 @@Source: jquery.scrollmagic.js
}; /** - * Is called, when the mousewhel is used while over a pinned element. - * If the scene is in fixed state scroll events used to be ignored. This forwards the event to the scroll container. + * Is called, when the mousewhel is used while over a pinned element inside a div container. + * If the scene is in fixed state scroll events would be counted towards the body. This forwards the event to the scroll container. * @private */ var onMousewheelOverPin = function (e) { - if (_parent && _pin && _state === "DURING") { // in pin state + if (_parent && _pin && _state === "DURING" && !_parent.info("isDocument")) { // in pin state + e.preventDefault(); _parent.scrollTo(_parent.info("scrollPos") - (e.originalEvent.wheelDelta/3 || -e.originalEvent.detail*30)); } }; @@ -1615,7 +1613,7 @@Source: jquery.scrollmagic.js
* * @fires ScrollScene.update * - * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next tweenmax tick (better performance). + * @param {boolean} [immediately=false] - If `true` the update will be instant, if `false` it will wait until next update cycle (better performance). * @returns {ScrollScene} Parent object for chaining. */ this.update = function (immediately) { @@ -1800,33 +1798,69 @@Source: jquery.scrollmagic.js
* .add(tween2); * scene.addTween(timeline); * - * @param {object} TweenMaxObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene. + * @param {object} TweenObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene. * @returns {ScrollScene} Parent object for chaining. */ - this.setTween = function (TweenMaxObject) { + this.setTween = function (TweenObject) { if (_tween) { // kill old tween? ScrollScene.removeTween(); } try { // wrap Tween into a TimelineMax Object to include delay and repeats in the duration and standardize methods. _tween = new TimelineMax({smoothChildTiming: true}) - .add(TweenMaxObject) + .add(TweenObject) .pause(); } catch (e) { - log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenMaxObject"); + log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenObject"); } finally { - // some propertties need to be transferred it to the wrapper, otherwise they would get lost. - if (TweenMaxObject.repeat) { // TweenMax or TimelineMax Object? - if (TweenMaxObject.repeat() === -1) { - _tween.repeat(-1); - _tween.yoyo(TweenMaxObject.yoyo()); + // some properties need to be transferred it to the wrapper, otherwise they would get lost. + if (TweenObject.repeat && TweenObject.repeat() === -1) {// TweenMax or TimelineMax Object? + _tween.repeat(-1); + _tween.yoyo(TweenObject.yoyo()); + } + } + // Some tween validations and debugging helpers + + // check if there are position tweens defined for the trigger and warn about it :) + if (_tween && _parent && _options.triggerElement && _options.loglevel >= 2) {// parent is needed to know scroll direction. + var + triggerTweens = _tween.getTweensOf($(_options.triggerElement)), + vertical = _parent.info("vertical"); + $.each(triggerTweens, function (index, value) { + var + tweenvars = value.vars.css || value.vars, + condition = vertical ? (tweenvars.top !== undefined || tweenvars.bottom !== undefined) : (tweenvars.left !== undefined || tweenvars.right !== undefined); + if (condition) { + log(2, "WARNING: Tweening the position of the trigger element affects the scene timing and should be avoided!"); + return false; + } + }); + } + + // warn about tween overwrites, when an element is tweened multiple times + if (parseFloat(TweenLite.version) >= 1.14) { // onOverwrite only present since GSAP v1.14.0 + var + list = _tween.getChildren(true, true, false), // get all nested tween objects + newCallback = function () { + log(2, "WARNING: tween was overwritten by another. To learn how to avoid this issue see here: https://github.com/janpaepke/ScrollMagic/wiki/WARNING:-tween-was-overwritten-by-another"); + }; + for (var i=0, thisTween, oldCallback; i<list.length; i++) { + /*jshint loopfunc: true */ + thisTween = list[i]; + if (oldCallback !== newCallback) { // if tweens is added more than once + oldCallback = thisTween.vars.onOverwrite; + thisTween.vars.onOverwrite = function () { + if (oldCallback) { + oldCallback.apply(this, arguments); + } + newCallback.apply(this, arguments); + }; } } - validateOption("checkIfTriggerElementIsTweened"); - log(3, "added tween"); - updateTweenProgress(); - return ScrollScene; } + log(3, "added tween"); + updateTweenProgress(); + return ScrollScene; }; /** @@ -2457,12 +2491,8 @@Source: jquery.scrollmagic.js
construct(); return ScrollScene; }; - - // store version - ScrollMagic.prototype.version = "1.1.2"; - // make global references available - window.ScrollScene = ScrollScene; - window.ScrollMagic = ScrollMagic; + return ScrollScene; +}); /* * ---------------------------------------------------------------- @@ -2470,55 +2500,41 @@Source: jquery.scrollmagic.js
* ---------------------------------------------------------------- */ - var - console = (window.console = window.console || {}), - loglevels = [ - "error", - "warn", - "log" - ]; - if (!console.log) { - console.log = $.noop; // no console log, well - do nothing then... - } - $.each(loglevels, function (index, method) { // make sure methods for all levels exist. - if (!console[method]) { - console[method] = console.log; // prefer .log over nothing + var debug = (function (console) { + var loglevels = ["error", "warn", "log"]; + if (!console.log) { + console.log = function(){}; // no console log, well - do nothing then... } - }); - // debugging function - var debug = function (loglevel) { - if (loglevel > loglevels.length || loglevel <= 0) loglevel = loglevels.length; - var now = new Date(), - time = ("0"+now.getHours()).slice(-2) + ":" + ("0"+now.getMinutes()).slice(-2) + ":" + ("0"+now.getSeconds()).slice(-2) + ":" + ("00"+now.getMilliseconds()).slice(-3), - method = loglevels[loglevel-1], - args = Array.prototype.splice.call(arguments, 1), - func = Function.prototype.bind.call(console[method], console); - - args.unshift(time); - func.apply(console, args); - }; + for(var i = 0, method; i<loglevels.length; i++) { // make sure methods for all levels exist. + method = loglevels[i]; + if (!console[method]) { + console[method] = console.log; // prefer .log over nothing + } + } + // debugging function + return function (loglevel) { + if (loglevel > loglevels.length || loglevel <= 0) loglevel = loglevels.length; + var now = new Date(), + time = ("0"+now.getHours()).slice(-2) + ":" + ("0"+now.getMinutes()).slice(-2) + ":" + ("0"+now.getSeconds()).slice(-2) + ":" + ("00"+now.getMilliseconds()).slice(-3), + method = loglevels[loglevel-1], + args = Array.prototype.splice.call(arguments, 1), + func = Function.prototype.bind.call(console[method], console); + + args.unshift(time); + func.apply(console, args); + }; + }(window.console = window.console || {})); // a helper function that should generally be faster than jQuery.offset() and can also return position in relation to viewport. - var getOffset = function ($elem, relativeToViewport) { - var offset = { - top: 0, - left: 0 - }, - elem = $elem[0]; - if (elem) { - if (elem.getBoundingClientRect) { // check if available - var rect = elem.getBoundingClientRect(); - offset.top = rect.top; - offset.left = rect.left; - if (!relativeToViewport) { // clientRect is by default relative to viewport... - offset.top += $(document).scrollTop(); - offset.left += $(document).scrollLeft(); - } - } else { // fall back to jquery - offset = $elem.offset() || offset; // if element has offset undefined (i.e. document) use 0 for top and left - if (relativeToViewport) { // jquery.offset is by default NOT relative to viewport... - offset.top -= $(document).scrollTop(); - offset.left -= $(document).scrollLeft(); - } + var getOffset = function (elem, relativeToViewport) { + var offset = {top: 0, left: 0}; + elem = elem[0]; // tmp workaround until jQuery dependency is removed. + if (elem && elem.getBoundingClientRect) { // check if available + var rect = elem.getBoundingClientRect(); + offset.top = rect.top; + offset.left = rect.left; + if (!relativeToViewport) { // clientRect is by default relative to viewport... + offset.top += (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || 0); + offset.left += (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || 0); } } return offset; @@ -2532,8 +2548,43 @@Source: jquery.scrollmagic.js
var isMarginCollapseType = function (str) { return ["block", "flex", "list-item", "table", "-webkit-box"].indexOf(str) > -1; }; + // implementation of requestAnimationFrame + var animationFrameCallback = window.requestAnimationFrame; + var animationFrameCancelCallback = window.cancelAnimationFrame; + + // polyfill -> based on https://gist.github.com/paulirish/1579671 + (function (window) { + var + lastTime = 0, + vendors = ['ms', 'moz', 'webkit', 'o'], + i; + + // try vendor prefixes if the above doesn't work + for (i = 0; !animationFrameCallback && i < vendors.length; ++i) { + console.log(vendors[i] + 'RequestAnimationFrame'); + animationFrameCallback = window[vendors[i] + 'RequestAnimationFrame']; + animationFrameCancelCallback = window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame']; + } + + // fallbacks + if (!animationFrameCallback) { + animationFrameCallback = function (callback) { + var + currTime = new Date().getTime(), + timeToCall = Math.max(0, 16 - (currTime - lastTime)), + id = window.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + } + if (!animationFrameCancelCallback) { + animationFrameCancelCallback = function (id) { + window.clearTimeout(id); + }; + } + }(window)); -})(jQuery, window);