// Copyright 2011 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview CSS3 transition base library. * * @author chrishenry@google.com (Chris Henry) */ goog.provide('goog.fx.css3.Transition'); goog.require('goog.Timer'); goog.require('goog.asserts'); goog.require('goog.fx.TransitionBase'); goog.require('goog.style'); goog.require('goog.style.transition'); /** * A class to handle targeted CSS3 transition. This class * handles common features required for targeted CSS3 transition. * * Browser that does not support CSS3 transition will still receive all * the events fired by the transition object, but will not have any transition * played. If the browser supports the final state as set in setFinalState * method, the element will ends in the final state. * * Transitioning multiple properties with the same setting is possible * by setting Css3Property's property to 'all'. Performing multiple * transitions can be done via setting multiple initialStyle, * finalStyle and transitions. Css3Property's delay can be used to * delay one of the transition. Here is an example for a transition * that expands on the width and then followed by the height: * *
 *   var animation = new goog.fx.css3.Transition(
 *     element,
 *     duration,
 *     {width: 10px, height: 10px},
 *     {width: 100px, height: 100px},
 *     [
 *       {property: width, duration: 1, timing: 'ease-in', delay: 0},
 *       {property: height, duration: 1, timing: 'ease-in', delay: 1}
 *     ]
 *   );
 * 
* * @param {Element} element The element to be transitioned. * @param {number} duration The duration of the transition in seconds. * This should be the longest of all transitions. * @param {Object} initialStyle Initial style properties of the element before * animating. Set using {@code goog.style.setStyle}. * @param {Object} finalStyle Final style properties of the element after * animating. Set using {@code goog.style.setStyle}. * @param {goog.style.transition.Css3Property| * Array} transitions A single CSS3 * transition property or an array of it. * @extends {goog.fx.TransitionBase} * @constructor * @struct */ goog.fx.css3.Transition = function( element, duration, initialStyle, finalStyle, transitions) { goog.fx.css3.Transition.base(this, 'constructor'); /** * Timer id to be used to cancel animation part-way. * @private {number} */ this.timerId_; /** * @type {Element} * @private */ this.element_ = element; /** * @type {number} * @private */ this.duration_ = duration; /** * @type {Object} * @private */ this.initialStyle_ = initialStyle; /** * @type {Object} * @private */ this.finalStyle_ = finalStyle; /** * @type {Array} * @private */ this.transitions_ = goog.isArray(transitions) ? transitions : [transitions]; }; goog.inherits(goog.fx.css3.Transition, goog.fx.TransitionBase); /** @override */ goog.fx.css3.Transition.prototype.play = function() { if (this.isPlaying()) { return false; } this.onBegin(); this.onPlay(); this.startTime = goog.now(); this.setStatePlaying(); if (goog.style.transition.isSupported()) { goog.style.setStyle(this.element_, this.initialStyle_); // Allow element to get updated to its initial state before installing // CSS3 transition. this.timerId_ = goog.Timer.callOnce(this.play_, undefined, this); return true; } else { this.stop_(false); return false; } }; /** * Helper method for play method. This needs to be executed on a timer. * @private */ goog.fx.css3.Transition.prototype.play_ = function() { // This measurement of the DOM element causes the browser to recalculate its // initial state before the transition starts. goog.style.getSize(this.element_); goog.style.transition.set(this.element_, this.transitions_); goog.style.setStyle(this.element_, this.finalStyle_); this.timerId_ = goog.Timer.callOnce( goog.bind(this.stop_, this, false), this.duration_ * 1000); }; /** @override */ goog.fx.css3.Transition.prototype.stop = function() { if (!this.isPlaying()) return; this.stop_(true); }; /** * Helper method for stop method. * @param {boolean} stopped If the transition was stopped. * @private */ goog.fx.css3.Transition.prototype.stop_ = function(stopped) { goog.style.transition.removeAll(this.element_); // Clear the timer. goog.Timer.clear(this.timerId_); // Make sure that we have reached the final style. goog.style.setStyle(this.element_, this.finalStyle_); this.endTime = goog.now(); this.setStateStopped(); if (stopped) { this.onStop(); } else { this.onFinish(); } this.onEnd(); }; /** @override */ goog.fx.css3.Transition.prototype.disposeInternal = function() { this.stop(); goog.fx.css3.Transition.base(this, 'disposeInternal'); }; /** * Pausing CSS3 Transitions in not supported. * @override */ goog.fx.css3.Transition.prototype.pause = function() { goog.asserts.assert(false, 'Css3 transitions does not support pause action.'); };