UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

315 lines (282 loc) 9.04 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2012 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Martin Wittemann (wittemann) ************************************************************************ */ /** * Cross browser animation layer. It uses feature detection to check if CSS * animations are available and ready to use. If not, a JavaScript-based * fallback will be used. * * @require(qx.module.Css) * @require(qx.module.Event) * @require(qx.module.Environment) */ qx.Bootstrap.define("qx.module.Animation", { events: { /** Fired when an animation starts. */ animationStart: undefined, /** Fired when an animation has ended one iteration. */ animationIteration: undefined, /** Fired when an animation has ended. */ animationEnd: undefined }, statics: { /** * Animation description used in {@link #fadeOut}. */ _fadeOut: { duration: 700, timing: "ease-out", keep: 100, keyFrames: { 0: { opacity: 1 }, 100: { opacity: 0, display: "none" } } }, /** * Animation description used in {@link #fadeIn}. */ _fadeIn: { duration: 700, timing: "ease-in", keep: 100, keyFrames: { 0: { opacity: 0 }, 100: { opacity: 1 } } }, /** * Animation execute either regular or reversed direction. * @param desc {Map} The animation"s description. * @param duration {Number?} The duration in milliseconds of the animation, * which will override the duration given in the description. * @param reverse {Boolean} <code>true</code>, if the animation should be reversed */ _animate(desc, duration, reverse) { this._forEachElement(function (el, i) { // stop all running animations if (el.$$animation) { el.$$animation.stop(); } var handle; if (reverse) { handle = qx.bom.element.Animation.animateReverse(el, desc, duration); } else { handle = qx.bom.element.Animation.animate(el, desc, duration); } var self = this; // only register for the first element if (i == 0) { handle.on( "start", function () { self.emit("animationStart"); }, handle ); handle.on( "iteration", function () { self.emit("animationIteration"); }, handle ); } handle.on( "end", function () { for (var i = 0; i < self.length; i++) { if (self[i].$$animation) { return; } } self.emit("animationEnd"); }, el ); }); } }, members: { /** * Returns the stored animation handles. The handles are only * available while an animation is running. * * @internal * @return {Array} An array of animation handles. */ getAnimationHandles() { var animationHandles = []; for (var i = 0; i < this.length; i++) { animationHandles[i] = this[i].$$animation; } return animationHandles; }, /** * Starts the animation with the given description. * * *duration* is the time in milliseconds one animation cycle should take. * * *keep* is the key frame to apply at the end of the animation. (optional) * * *keyFrames* is a map of separate frames. Each frame is defined by a * number which is the percentage value of time in the animation. The value * is a map itself which holds css properties or transforms * (Transforms only for CSS Animations). * * *origin* maps to the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin">transform origin</a> * (Only for CSS animations). * * *repeat* is the amount of time the animation should be run in * sequence. You can also use "infinite". * * *timing* takes one of these predefined values: * <code>ease</code> | <code>linear</code> | <code>ease-in</code> * | <code>ease-out</code> | <code>ease-in-out</code> | * <code>cubic-bezier(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;)</code> * (cubic-bezier only available for CSS animations) * * *alternate* defines if every other animation should be run in reverse order. * * *delay* is the time in milliseconds the animation should wait before start. * * @attach {qxWeb} * @param desc {Map} The animation"s description. * @param duration {Number?} The duration in milliseconds of the animation, * which will override the duration given in the description. * @return {qxWeb} The collection for chaining. */ animate(desc, duration) { qx.module.Animation._animate.bind(this)(desc, duration, false); return this; }, /** * Starts an animation in reversed order. For further details, take a look at * the {@link #animate} method. * @attach {qxWeb} * @param desc {Map} The animation"s description. * @param duration {Number?} The duration in milliseconds of the animation, * which will override the duration given in the description. * @return {qxWeb} The collection for chaining. */ animateReverse(desc, duration) { qx.module.Animation._animate.bind(this)(desc, duration, true); return this; }, /** * Manipulates the play state of the animation. * This can be used to continue an animation when paused. * @attach {qxWeb} * @return {qxWeb} The collection for chaining. */ play() { for (var i = 0; i < this.length; i++) { var handle = this[i].$$animation; if (handle) { handle.play(); } } return this; }, /** * Manipulates the play state of the animation. * This can be used to pause an animation when running. * @attach {qxWeb} * @return {qxWeb} The collection for chaining. */ pause() { for (var i = 0; i < this.length; i++) { var handle = this[i].$$animation; if (handle) { handle.pause(); } } return this; }, /** * Stops a running animation. * @attach {qxWeb} * @return {qxWeb} The collection for chaining. */ stop() { for (var i = 0; i < this.length; i++) { var handle = this[i].$$animation; if (handle) { handle.stop(); } } return this; }, /** * Returns whether an animation is running or not. * @attach {qxWeb} * @return {Boolean} <code>true</code>, if an animation is running. */ isPlaying() { for (var i = 0; i < this.length; i++) { var handle = this[i].$$animation; if (handle && handle.isPlaying()) { return true; } } return false; }, /** * Returns whether an animation has ended or not. * @attach {qxWeb} * @return {Boolean} <code>true</code>, if an animation has ended. */ isEnded() { for (var i = 0; i < this.length; i++) { var handle = this[i].$$animation; if (handle && !handle.isEnded()) { return false; } } return true; }, /** * Fades in all elements in the collection. * @attach {qxWeb} * @param duration {Number?} The duration in milliseconds. * @return {qxWeb} The collection for chaining. */ fadeIn(duration) { // remove "display: none" style this.setStyle("display", ""); return this.animate(qx.module.Animation._fadeIn, duration); }, /** * Fades out all elements in the collection. * @attach {qxWeb} * @param duration {Number?} The duration in milliseconds. * @return {qxWeb} The collection for chaining. */ fadeOut(duration) { return this.animate(qx.module.Animation._fadeOut, duration); } }, defer(statics) { qxWeb.$attachAll(this); /** * End value for opacity style. This value is modified for all browsers which are * 'optimizing' this style value by not setting it (like IE9). This leads to a wrong * end state for the 'fadeIn' animation if a opacity value is set by CSS. */ if ( qxWeb.env.get("browser.name") === "ie" && qxWeb.env.get("browser.version") <= 9 ) { // has to be fixed using direct access since we cannot store the value as static member. // The 'fadeIn' description is evaluated during class definition statics._fadeIn.keyFrames[100].opacity = 0.99; } } });