1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
/*!
* @file ScrollMagic Velocity Animation Plugin.
*
* requires: velocity ~1.2
* Powered by VelocityJS: http://VelocityJS.org
* Velocity is published under MIT license.
*/
/**
* This plugin is meant to be used in conjunction with the Velocity animation framework.
* It offers an easy API to __trigger__ Velocity animations.
*
* With the current version of Velocity scrollbound animations (scenes with duration) are not supported.
* This feature will be added as soon as Velocity provides the appropriate API.
*
* To have access to this extension, please include `plugins/animation.velocity.js`.
* @requires {@link http://julian.com/research/velocity/|Velocity ~1.2.0}
* @mixin animation.Velocity
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['ScrollMagic', 'velocity'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(require('scrollmagic'), require('velocity'));
} else {
// Browser globals
factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic), root.Velocity || (root.jQuery && root.jQuery.Velocity));
}
}(this, function(ScrollMagic, velocity) {
"use strict";
var NAMESPACE = "animation.velocity";
// (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 (!velocity) {
err("(" + NAMESPACE + ") -> ERROR: Velocity could not be found. Please make sure it's loaded before ScrollMagic or use an asynchronous loader like requirejs.");
}
// (BUILD) - REMOVE IN MINIFY - END
var autoindex = 0;
ScrollMagic.Scene.extend(function () {
var
Scene = this,
_util = ScrollMagic._util,
_currentProgress = 0,
_elems,
_properties,
_options,
_dataID; // used to identify element data related to this scene, will be defined everytime a new velocity animation is added
// (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_velocity", function () {
updateAnimationProgress();
});
Scene.on("destroy.plugin_velocity", function (e) {
Scene.off("*.plugin_velocity");
Scene.removeVelocity(e.reset);
});
var animate = function (elem, properties, options) {
if (_util.type.Array(elem)) {
elem.forEach(function(elem) {
animate(elem, properties, options);
});
} else {
// set reverse values
if (!velocity.Utilities.data(elem, _dataID)) {
velocity.Utilities.data(elem, _dataID,
{
reverseProps: _util.css(elem, Object.keys(_properties))
}
);
}
// animate
velocity(elem, properties, options);
if (options.queue !== undefined) {
velocity.Utilities.dequeue(elem, options.queue);
}
}
};
var reverse = function (elem, options) {
if (_util.type.Array(elem)) {
elem.forEach(function(elem) {
reverse(elem, options);
});
} else {
var data = velocity.Utilities.data(elem, _dataID);
if (data && data.reverseProps) {
velocity(elem, data.reverseProps, options);
if (options.queue !== undefined) {
velocity.Utilities.dequeue(elem, options.queue);
}
}
}
};
/**
* Update the tween progress to current position.
* @private
*/
var updateAnimationProgress = function () {
if (_elems) {
var progress = Scene.progress();
if (progress != _currentProgress) { // do we even need to update the progress?
if (Scene.duration() === 0) {
// play the animation
if (progress > 0) { // play forward
animate(_elems, _properties, _options);
} else { // play reverse
reverse(_elems, _options);
// velocity(_elems, _propertiesReverse, _options);
// velocity("reverse");
}
} else {
// TODO: Scrollbound animations not supported yet...
}
_currentProgress = progress;
}
}
};
/**
* Add a Velocity animation to the scene.
* The method accepts the same parameters as Velocity, with the first parameter being the target element.
*
* To gain better understanding, check out the [Velocity example](../examples/basic/simple_velocity.html).
* @memberof! animation.Velocity#
*
* @example
* // trigger a Velocity animation
* scene.setVelocity("#myElement", {opacity: 0.5}, {duration: 1000, easing: "linear"});
*
* @param {(object|string)} elems - One or more Dom Elements or a Selector that should be used as the target of the animation.
* @param {object} properties - The CSS properties that should be animated.
* @param {object} options - Options for the animation, like duration or easing.
* @returns {Scene} Parent object for chaining.
*/
Scene.setVelocity = function (elems, properties, options) {
if (_elems) { // kill old ani?
Scene.removeVelocity();
}
_elems = _util.get.elements(elems);
_properties = properties || {};
_options = options || {};
_dataID = "ScrollMagic." + NAMESPACE + "[" + (autoindex++) + "]";
if (_options.queue !== undefined) {
// we'll use the queue to identify the animation. When defined it will always stop the previously running one.
// if undefined the animation will always fully run, as is expected.
// defining anything other than 'false' as the que doesn't make much sense, because ScrollMagic takes control over the trigger.
// thus it is also overwritten.
_options.queue = _dataID + "_queue";
}
// (BUILD) - REMOVE IN MINIFY - START
var checkDuration = function () {
if (Scene.duration() !== 0) {
log(1, "ERROR: The Velocity animation plugin does not support scrollbound animations (scenes with duration) yet.");
}
};
Scene.on("change.plugin_velocity", function (e) {
if (e.what == 'duration') {
checkDuration();
}
});
checkDuration();
// (BUILD) - REMOVE IN MINIFY - END
log(3, "added animation");
updateAnimationProgress();
return Scene;
};
/**
* Remove the animation from the scene.
* This will stop the scene from triggering the animation.
*
* Using the reset option you can decide if the animation should remain in the current state or be rewound to set the target elements back to the state they were in before the animation was added to the scene.
* @memberof! animation.Velocity#
*
* @example
* // remove the animation from the scene without resetting it
* scene.removeVelocity();
*
* // remove the animation from the scene and reset the elements to initial state
* scene.removeVelocity(true);
*
* @param {boolean} [reset=false] - If `true` the animation will rewound.
* @returns {Scene} Parent object for chaining.
*/
Scene.removeVelocity = function (reset) {
if (_elems) {
// stop running animations
if (_options.queue !== undefined) {
velocity(_elems, "stop", _options.queue);
}
if (reset) {
reverse(_elems, {duration: 0});
}
_elems.forEach(function(elem) {
velocity.Utilities.removeData(elem, _dataID);
});
_elems = _properties = _options = _dataID = undefined;
}
return Scene;
};
});
}));