Path: blob/trunk/third_party/closure/goog/fx/anim/anim.js
1864 views
// Copyright 2006 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Basic animation controls.16*17* @author [email protected] (Erik Arvidsson)18*/19goog.provide('goog.fx.anim');20goog.provide('goog.fx.anim.Animated');2122goog.require('goog.async.AnimationDelay');23goog.require('goog.async.Delay');24goog.require('goog.object');25262728/**29* An interface for programatically animated objects. I.e. rendered in30* javascript frame by frame.31*32* @interface33*/34goog.fx.anim.Animated = function() {};353637/**38* Function called when a frame is requested for the animation.39*40* @param {number} now Current time in milliseconds.41*/42goog.fx.anim.Animated.prototype.onAnimationFrame;434445/**46* Default wait timeout for animations (in milliseconds). Only used for timed47* animation, which uses a timer (setTimeout) to schedule animation.48*49* @type {number}50* @const51*/52goog.fx.anim.TIMEOUT = goog.async.AnimationDelay.TIMEOUT;535455/**56* A map of animations which should be cycled on the global timer.57*58* @type {!Object<number, goog.fx.anim.Animated>}59* @private60*/61goog.fx.anim.activeAnimations_ = {};626364/**65* An optional animation window.66* @type {Window}67* @private68*/69goog.fx.anim.animationWindow_ = null;707172/**73* An interval ID for the global timer or event handler uid.74* @type {goog.async.Delay|goog.async.AnimationDelay}75* @private76*/77goog.fx.anim.animationDelay_ = null;787980/**81* Registers an animation to be cycled on the global timer.82* @param {goog.fx.anim.Animated} animation The animation to register.83*/84goog.fx.anim.registerAnimation = function(animation) {85var uid = goog.getUid(animation);86if (!(uid in goog.fx.anim.activeAnimations_)) {87goog.fx.anim.activeAnimations_[uid] = animation;88}8990// If the timer is not already started, start it now.91goog.fx.anim.requestAnimationFrame_();92};939495/**96* Removes an animation from the list of animations which are cycled on the97* global timer.98* @param {goog.fx.anim.Animated} animation The animation to unregister.99*/100goog.fx.anim.unregisterAnimation = function(animation) {101var uid = goog.getUid(animation);102delete goog.fx.anim.activeAnimations_[uid];103104// If a timer is running and we no longer have any active timers we stop the105// timers.106if (goog.object.isEmpty(goog.fx.anim.activeAnimations_)) {107goog.fx.anim.cancelAnimationFrame_();108}109};110111112/**113* Tears down this module. Useful for testing.114*/115// TODO(nicksantos): Wow, this api is pretty broken. This should be fixed.116goog.fx.anim.tearDown = function() {117goog.fx.anim.animationWindow_ = null;118goog.dispose(goog.fx.anim.animationDelay_);119goog.fx.anim.animationDelay_ = null;120goog.fx.anim.activeAnimations_ = {};121};122123124/**125* Registers an animation window. This allows usage of the timing control API126* for animations. Note that this window must be visible, as non-visible127* windows can potentially stop animating. This window does not necessarily128* need to be the window inside which animation occurs, but must remain visible.129* See: https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame.130*131* @param {Window} animationWindow The window in which to animate elements.132*/133goog.fx.anim.setAnimationWindow = function(animationWindow) {134// If a timer is currently running, reset it and restart with new functions135// after a timeout. This is to avoid mismatching timer UIDs if we change the136// animation window during a running animation.137//138// In practice this cannot happen before some animation window and timer139// control functions has already been set.140var hasTimer =141goog.fx.anim.animationDelay_ && goog.fx.anim.animationDelay_.isActive();142143goog.dispose(goog.fx.anim.animationDelay_);144goog.fx.anim.animationDelay_ = null;145goog.fx.anim.animationWindow_ = animationWindow;146147// If the timer was running, start it again.148if (hasTimer) {149goog.fx.anim.requestAnimationFrame_();150}151};152153154/**155* Requests an animation frame based on the requestAnimationFrame and156* cancelRequestAnimationFrame function pair.157* @private158*/159goog.fx.anim.requestAnimationFrame_ = function() {160if (!goog.fx.anim.animationDelay_) {161// We cannot guarantee that the global window will be one that fires162// requestAnimationFrame events (consider off-screen chrome extension163// windows). Default to use goog.async.Delay, unless164// the client has explicitly set an animation window.165if (goog.fx.anim.animationWindow_) {166// requestAnimationFrame will call cycleAnimations_ with the current167// time in ms, as returned from goog.now().168goog.fx.anim.animationDelay_ =169new goog.async.AnimationDelay(function(now) {170goog.fx.anim.cycleAnimations_(now);171}, goog.fx.anim.animationWindow_);172} else {173goog.fx.anim.animationDelay_ = new goog.async.Delay(function() {174goog.fx.anim.cycleAnimations_(goog.now());175}, goog.fx.anim.TIMEOUT);176}177}178179var delay = goog.fx.anim.animationDelay_;180if (!delay.isActive()) {181delay.start();182}183};184185186/**187* Cancels an animation frame created by requestAnimationFrame_().188* @private189*/190goog.fx.anim.cancelAnimationFrame_ = function() {191if (goog.fx.anim.animationDelay_) {192goog.fx.anim.animationDelay_.stop();193}194};195196197/**198* Cycles through all registered animations.199* @param {number} now Current time in milliseconds.200* @private201*/202goog.fx.anim.cycleAnimations_ = function(now) {203goog.object.forEach(goog.fx.anim.activeAnimations_, function(anim) {204anim.onAnimationFrame(now);205});206207if (!goog.object.isEmpty(goog.fx.anim.activeAnimations_)) {208goog.fx.anim.requestAnimationFrame_();209}210};211212213