📄 animations.js
字号:
/// the dynamic properties are JavaScript expressions and not abitrary statements (i.e.
/// you can't include things like "return foo;"), although you can include anything
/// inside an anonymous function definition that you immediately invoke (i.e.,
/// "(function() { return foo; })()"). A dynamic property can be set in the generic
/// XML animation description by appending Script onto any legitimate property name
/// (for example, instead of Height="70" we could use
/// HeightScript="$find('MyBehavior').get_element().offsetHeight"). Any exceptions
/// raised when setting dynamic properties (including both JavaScript evaluation errors
/// and other exceptions raised by property setters) will only be propogated when
/// debugging.
/// </field>
/// <remarks>
/// Animations need to be as fast as possible - even in debug mode. Don't add validation code to
/// methods involved in every step of the animation.
/// </remarks>
/// <animation>Animation</animation>
$AA.Animation.initializeBase(this);
// Length of the animation in seconds
this._duration = 1;
// Number of steps per second
this._fps = 25;
// Target Sys.UI.DomElement of the animation
this._target = null;
// Tick event handler
this._tickHandler = null;
// Animation timer
this._timer = null;
// Percentage of the animation already played
this._percentComplete = 0;
// Percentage of the animation to play on each step
this._percentDelta = null;
// Reference to the animation that owns this animation (currently only set in
// ParallelAnimation.add). This concept of ownership allows an entire animation
// subtree to be driven off a single timer so all the operations are properly
// synchronized.
this._owner = null;
// Reference to the animation that contains this as a child (this is set
// in ParentAnimation.add). The primary use of the parent animation is in
// resolving the animation target when one isn't specified.
this._parentAnimation = null;
// The DynamicProperties collection is used to associate JavaScript expressions with
// properties. The expressions are evaluated just before the animation is played
// everytime (in the base onStart method). See the additional information in the
// XML <field> comment above.
this.DynamicProperties = { };
// Set the target, duration, and fps if they were provided in the constructor
if (target) {
this.set_target(target);
}
if (duration) {
this.set_duration(duration);
}
if (fps) {
this.set_fps(fps);
}
}
$AA.Animation.prototype = {
dispose : function() {
/// <summary>
/// Dispose the animation
/// </summary>
/// <returns />
if (this._timer) {
this._timer.dispose();
this._timer = null;
}
this._tickHandler = null;
this._target = null;
$AA.Animation.callBaseMethod(this, 'dispose');
},
play : function() {
/// <summary>
/// Play the animation from the beginning or where it was left off when paused.
/// </summary>
/// <returns />
/// <remarks>
/// If this animation is the child of another, you must call <code>play</code> on its parent instead.
/// </remarks>
// If ownership of this animation has been claimed, then we'll require the parent to
// handle playing the animation (this is very important because then the entire animation
// tree runs on the same timer and updates consistently)
if (!this._owner) {
var resume = true;
if (!this._timer) {
resume = false;
if (!this._tickHandler) {
this._tickHandler = Function.createDelegate(this, this._onTimerTick);
}
this._timer = new Sys.Timer();
this._timer.add_tick(this._tickHandler);
this.onStart();
this._timer.set_interval(1000 / this._fps);
this._percentDelta = 100 / (this._duration * this._fps);
this._updatePercentComplete(0, true);
}
this._timer.set_enabled(true);
this.raisePropertyChanged('isPlaying');
if (!resume) {
this.raisePropertyChanged('isActive');
}
}
},
pause : function() {
/// <summary>
/// Pause the animation if it is playing. Calling <code>play</code> will resume where
/// the animation left off.
/// </summary>
/// <returns />
/// <remarks>
/// If this animation is the child of another, you must call <code>pause</code> on its parent instead.
/// </remarks>
if (!this._owner) {
if (this._timer) {
this._timer.set_enabled(false);
this.raisePropertyChanged('isPlaying');
}
}
},
stop : function(finish) {
/// <summary>
/// Stop playing the animation.
/// </summary>
/// <param name="finish" type="Boolean" mayBeNull="true" optional="true">
/// Whether or not stopping the animation should leave the target element in a state
/// consistent with the animation playing completely by performing the last step.
/// The default value is true.
/// </param>
/// <returns />
/// <remarks>
/// If this animation is the child of another, you must call <code>stop</code> on
/// its parent instead.
/// </remarks>
if (!this._owner) {
var t = this._timer;
this._timer = null;
if (t) {
t.dispose();
if (this._percentComplete !== 100) {
this._percentComplete = 100;
this.raisePropertyChanged('percentComplete');
if (finish || finish === undefined) {
this.onStep(100);
}
}
this.onEnd();
this.raisePropertyChanged('isPlaying');
this.raisePropertyChanged('isActive');
}
}
},
onStart : function() {
/// <summary>
/// The <code>onStart</code> method is called just before the animation is played each time.
/// </summary>
/// <returns />
this.raiseStarted();
// Initialize any dynamic properties
for (var property in this.DynamicProperties) {
try {
// Invoke the property's setter on the evaluated expression
this[property](eval(this.DynamicProperties[property]));
} catch(ex) {
// Propogate any exceptions if we're debugging, otherwise eat them
if ( Sys.Debug.isDebug) {
throw ex;
}
}
}
},
onStep : function(percentage) {
/// <summary>
/// The <code>onStep</code> method is called repeatedly to progress the animation through each frame
/// </summary>
/// <param name="percentage" type="Number">Percentage of the animation already complete</param>
/// <returns />
this.setValue(this.getAnimatedValue(percentage));
},
onEnd : function() {
/// <summary>
/// The <code>onEnd</code> method is called just after the animation is played each time.
/// </summary>
/// <returns />
this.raiseEnded();
},
getAnimatedValue : function(percentage) {
/// <summary>
/// Determine the state of the animation after the given percentage of its duration has elapsed
/// </summary>
/// <param name="percentage" type="Number">Percentage of the animation already complete</param>
/// <returns type="Object">
/// State of the animation after the given percentage of its duration has elapsed that will
/// be passed to <code>setValue</code>
/// </returns>
throw Error.notImplemented();
},
setValue : function(value) {
/// <summary>
/// Set the current state of the animation
/// </summary>
/// <param name="value" type="Object">Current state of the animation (as retreived from <code>getAnimatedValue</code>)</param>
/// <returns />
throw Error.notImplemented();
},
interpolate : function(start, end, percentage) {
/// <summary>
/// The <code>interpolate</code> function is used to find the appropriate value between starting and
/// ending values given the current percentage.
/// </summary>
/// <param name="start" type="Number">
/// Start of the range to interpolate
/// </param>
/// <param name="end" type="Number">
/// End of the range to interpolate
/// </param>
/// <param name="percentage" type="Number">
/// Percentage completed in the range to interpolate
/// </param>
/// <returns type="Number">
/// Value the desired percentage between the start and end values
/// </returns>
/// <remarks>
/// In the future, we hope to make several implementations of this available so we can dynamically
/// change the apparent speed of the animations, although it may make more sense to modify the
/// <code>_updatePercentComplete</code> function instead.
/// </remarks>
return start + (end - start) * (percentage / 100);
},
_onTimerTick : function() {
/// <summary>
/// Handler for the tick event to move the animation along through its duration
/// </summary>
/// <returns />
this._updatePercentComplete(this._percentComplete + this._percentDelta, true);
},
_updatePercentComplete : function(percentComplete, animate) {
/// <summary>
/// Update the animation and its target given the current percentage of its duration that
/// has already elapsed
/// </summary>
/// <param name="percentComplete" type="Number">
/// Percentage of the animation duration that has already elapsed
/// </param>
/// <param name="animate" type="Boolean" mayBeNull="true" optional="true">
/// Whether or not updating the animation should visually modify the animation's target
/// </param>
/// <returns />
if (percentComplete > 100) {
percentComplete = 100;
}
this._percentComplete = percentComplete;
this.raisePropertyChanged('percentComplete');
if (animate) {
this.onStep(percentComplete);
}
if (percentComplete === 100) {
this.stop(false);
}
},
setOwner : function(owner) {
/// <summary>
/// Make this animation the child of another animation
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -