/*! * @file ScrollMagic GSAP Animation Plugin. * * requires: GSAP ~1.14 * Powered by the Greensock Animation Platform (GSAP): http://www.greensock.com/js * Greensock License info at http://www.greensock.com/licensing/ */ /** * This plugin is meant to be used in conjunction with the Greensock Animation Plattform. * It offers an easy API to trigger Tweens or synchronize them to the scrollbar movement. * * Both the `lite` and the `max` versions of the GSAP library are supported. * The most basic requirement is `TweenLite`. * * To have access to this extension, please include `plugins/animation.gsap.js`. * @requires {@link http://greensock.com/gsap|GSAP ~1.14.x} * @mixin animation.GSAP */ (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['ScrollMagic', 'gsap', 'TweenMax', 'TimelineMax'], factory); } else if (typeof exports === 'object') { // CommonJS // Loads whole gsap package onto global scope. var gsap = require("gsap/dist/gsap") || require("gsap"); // TweenMax/TimelineMax will be global in v2. In v3, they will be on the gsap object factory(require('scrollmagic'), gsap, TweenMax || gsap, TimelineMax || gsap); } else { // Browser globals factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic), root.gsap, root.gsap || root.TweenMax || root.TweenLite, root.gsap || root.TimelineMax || root.TimelineLite); } }(this, function(ScrollMagic, Gsap, Tween, Timeline) { "use strict"; var NAMESPACE = "animation.gsap"; var GSAP3_OR_GREATER = Gsap && parseFloat(Gsap.version) >= 3; // (BUILD) - REMOVE IN MINIFY - START var console = window.console || {}, err = Function.prototype.bind.call(console.error || console.log || function() {}, console); if (!ScrollMagic) { err("(" + NAMESPACE + ") -> ERROR: The ScrollMagic main module could not be found. Please make sure it's loaded before this plugin or use an asynchronous loader like requirejs."); } if (!Tween) { err("(" + NAMESPACE + ") -> ERROR: TweenLite or TweenMax could not be found. Please make sure GSAP is loaded before ScrollMagic or use an asynchronous loader like requirejs."); } // (BUILD) - REMOVE IN MINIFY - END /* * ---------------------------------------------------------------- * Extensions for Scene * ---------------------------------------------------------------- */ /** * Every instance of ScrollMagic.Scene now accepts an additional option. * See {@link ScrollMagic.Scene} for a complete list of the standard options. * @memberof! animation.GSAP# * @method new ScrollMagic.Scene(options) * @example * var scene = new ScrollMagic.Scene({tweenChanges: true}); * * @param {object} [options] - Options for the Scene. The options can be updated at any time. * @param {boolean} [options.tweenChanges=false] - Tweens Animation to the progress target instead of setting it. Does not affect animations where duration is `0`. */ /** * **Get** or **Set** the tweenChanges option value. * This only affects scenes with a duration. If `tweenChanges` is `true`, the progress update when scrolling will not be immediate, but instead the animation will smoothly animate to the target state. * For a better understanding, try enabling and disabling this option in the [Scene Manipulation Example](../examples/basic/scene_manipulation.html). * @memberof! animation.GSAP# * @method Scene.tweenChanges * * @example * // get the current tweenChanges option * var tweenChanges = scene.tweenChanges(); * * // set new tweenChanges option * scene.tweenChanges(true); * * @fires {@link Scene.change}, when used as setter * @param {boolean} [newTweenChanges] - The new tweenChanges setting of the scene. * @returns {boolean} `get` - Current tweenChanges option value. * @returns {Scene} `set` - Parent object for chaining. */ // add option (TODO: DOC (private for dev)) ScrollMagic.Scene.addOption( "tweenChanges", // name false, // default function (val) { // validation callback return !!val; } ); // extend scene ScrollMagic.Scene.extend(function () { var Scene = this, _tween; // (BUILD) - REMOVE IN MINIFY - START var log = function () { if (Scene._log) { // not available, when main source minified Array.prototype.splice.call(arguments, 1, 0, "(" + NAMESPACE + ")", "->"); Scene._log.apply(this, arguments); } }; // (BUILD) - REMOVE IN MINIFY - END // set listeners Scene.on("progress.plugin_gsap", function () { updateTweenProgress(); }); Scene.on("destroy.plugin_gsap", function (e) { Scene.removeTween(e.reset); }); /** * Update the tween progress to current position. * @private */ var updateTweenProgress = function () { if (_tween) { var progress = Scene.progress(), state = Scene.state(); if (_tween.repeat && _tween.repeat() === -1) { // infinite loop, so not in relation to progress if (state === 'DURING' && _tween.paused()) { _tween.play(); } else if (state !== 'DURING' && !_tween.paused()) { _tween.pause(); } } else if (progress != _tween.progress()) { // do we even need to update the progress? // no infinite loop - so should we just play or go to a specific point in time? if (Scene.duration() === 0) { // play the animation if (progress > 0) { // play from 0 to 1 _tween.play(); } else { // play from 1 to 0 _tween.reverse(); } } else { // go to a specific point in time if (Scene.tweenChanges() && _tween.tweenTo) { // go smooth _tween.tweenTo(progress * _tween.duration()); } else { // just hard set it _tween.progress(progress).pause(); } } } } }; /** * Add a tween to the scene. * If you want to add multiple tweens, add them into a GSAP Timeline object and supply it instead (see example below). * * If the scene has a duration, the tween's duration will be projected to the scroll distance of the scene, meaning its progress will be synced to scrollbar movement. * For a scene with a duration of `0`, the tween will be triggered when scrolling forward past the scene's trigger position and reversed, when scrolling back. * To gain better understanding, check out the [Simple Tweening example](../examples/basic/simple_tweening.html). * * Instead of supplying a tween this method can also be used as a shorthand for `TweenMax.to()` (see example below). * @memberof! animation.GSAP# * * @example * // add a single tween directly * scene.setTween(TweenMax.to("obj"), 1, {x: 100}); * * // add a single tween via variable * var tween = TweenMax.to("obj"), 1, {x: 100}; * scene.setTween(tween); * * // add multiple tweens, wrapped in a timeline. * var timeline = new TimelineMax(); * var tween1 = TweenMax.from("obj1", 1, {x: 100}); * var tween2 = TweenMax.to("obj2", 1, {y: 100}); * timeline * .add(tween1) * .add(tween2); * scene.addTween(timeline); * * // short hand to add a TweenMax.to() tween * scene.setTween("obj3", 0.5, {y: 100}); * * // short hand to add a TweenMax.to() tween for 1 second * // this is useful, when the scene has a duration and the tween duration isn't important anyway * scene.setTween("obj3", {y: 100}); * * @param {(object|string)} TweenObject - A TweenMax, TweenLite, TimelineMax or TimelineLite object that should be animated in the scene. Can also be a Dom Element or Selector, when using direct tween definition (see examples). * @param {(number|object)} duration - A duration for the tween, or tween parameters. If an object containing parameters are supplied, a default duration of 1 will be used. * @param {object} params - The parameters for the tween * @returns {Scene} Parent object for chaining. */ Scene.setTween = function (TweenObject, duration, params) { var newTween; if (arguments.length > 1) { var durationIsSet = typeof arguments['1'] === 'number'; if(GSAP3_OR_GREATER){ // If we're using gsap 3 with proper gsap 3 syntax of 2 arguments if(!durationIsSet){ params = duration; } // Add a duration is there isn't one if (!params.hasOwnProperty('duration')) { params.duration = durationIsSet ? duration : 1; } } else { // If we're using gsap 2 or earlier syntax if (arguments.length < 3) { params = duration; duration = 1; } } // 2 arguments should be gsap 3 syntax, and 3 arguments for TweenObject = GSAP3_OR_GREATER ? Tween.to(TweenObject, params) : Tween.to(TweenObject, duration, params); } try { // wrap Tween into a Timeline Object if not gsap 3 or greater and available to include delay and repeats in the duration and standardize methods. if (Timeline && !GSAP3_OR_GREATER) { newTween = new Timeline({smoothChildTiming: true}) .add(TweenObject); } else { newTween = TweenObject; } newTween.pause(); } catch (e) { log(1, "ERROR calling method 'setTween()': Supplied argument is not a valid TweenObject"); return Scene; } if (_tween) { // kill old tween? Scene.removeTween(); } _tween = newTween; // 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()); } // (BUILD) - REMOVE IN MINIFY - START // Some tween validations and debugging helpers if (Scene.tweenChanges() && !_tween.tweenTo) { log(2, "WARNING: tweenChanges will only work if the TimelineMax object is available for ScrollMagic."); } // check if there are position tweens defined for the trigger and warn about it :) if (_tween && Scene.controller() && Scene.triggerElement() && Scene.loglevel() >= 2) {// controller is needed to know scroll direction. var triggerTweens = Tween.getTweensOf(Scene.triggerElement()), vertical = Scene.controller().info("vertical"); triggerTweens.forEach(function (value, index) { 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 // However, onInterrupt deprecated onOverwrite in GSAP v3 methodUsed = GSAP3_OR_GREATER ? 'onInterrupt' : 'onOverwrite', list = _tween.getChildren ? _tween.getChildren(true, true, false) : [_tween], // 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