📄 animation.js
字号:
/*
* Isomorphic SmartClient
* Version 6.5 (2008-04-30)
* Copyright(c) 1998-2007 Isomorphic Software, Inc. All rights reserved.
* "SmartClient" is a trademark of Isomorphic Software, Inc.
*
* licensing@smartclient.com
*
* http://smartclient.com/license
*/
//> @class Animation// Class with static APIs used by the animation subsystem.// @treeLocation Client Reference/System// @visibility animation_advanced//<isc.ClassFactory.defineClass("Animation");isc.Animation.addClassProperties({ //> @classAttr Animation.interval (number : 40 : IRWA) // Interval in ms between animation events. // @visibility animation_advanced //< interval:40, registry:[], // Some standard ratio functions // These functions take a value between zero and one, representing a linear ratio and // return a value between zero and one that represents a non linear ratio. // Executed in global scope //> @classMethod Animation.smoothStart (A) // This is a static function which maps a linear ratio (value between zero and one // representing how much of an animation has elapsed) to a ratio biased such that the // starts slowly and speeds up as it approaches 1. // @visibility animation_advanced //< smoothStart : function (rawRatio) { return Math.pow(rawRatio, 2); }, //> @classMethod Animation.smoothEnd (A) // This is a static function which maps a linear ratio (value between zero and one // representing how much of an animation has elapsed) to a ratio biased such that the // animation starts moving quickly, and appears to slow down as it approaches 1. // @visibility animation_advanced //< smoothEnd : function (rawRatio) { return 1 - Math.abs(Math.pow(rawRatio-1, 2)); }, //> @classMethod Animation.smoothStartEnd (A) // This is a static function which maps a linear ratio (value between zero and one // representing how much of an animation has elapsed) to a ratio biased such that the // animation appears to accelerate from a slow start, then slow down again toward the end // of the animation. // @visibility animation_advanced //< smoothStartEnd : function (rawRatio) { return (-Math.cos(rawRatio*Math.PI) + 1) / 2.0; }, //> @classAttr Animation.animateTime (number : 1000 : IRWA) // Default total duration for animations with no specified duration. Typically animations // involving canvases will pick up their duration from the Canvas level default, so this // property is only used in rare cases. // @visibility animation_advanced // @group animation //< animateTime:1000 });isc.Animation.addClassMethods({ // Unique IDs used to identify registered animation actions generateAnimationID : function () { if (!this._animationCount) this._animationCount = 0; return "_" + (this._animationCount++); }, // Raw handler fired in the global scope by the animation timer - fires the animation // events timeoutAction : function () { if (isc.Animation) isc.Animation.fireTimer(); }, //>@type AnimationAcceleration // Acceleration effect for animations. Can either be a ratio function or a string. // Ratio functions take a value between 0 and 1 which represents how much of the // animation's duration has elapsed, and return another value between 0 and 1 indicating // how close the animation is to completion. For a completely linear animation, the // function would return the value it was passed. This allows you to bias animations to // [for example] speed up toward the end of the animation.<br> // The following strings are also supported for common ratio bias effects: // <ul> // <li>"smoothStart" - animation will speed up as time elapses // <li>"smoothEnd" - animation will slow down as time elapses // <li>"smoothStartEnd" - animation will speed up in the middle // <li>"none" - no bias</ul> // @visibility animation //< //> @classMethod Animation.registerAnimation() // Register an action to fire repeatedly for some duration of time. // // @param callback (callback) Action to fire repeatedly until the duration expires. // Passed 3 parameters for each step:<br> // - "ratio" (number between 0 and 1) indicating what fraction // of the specified duration has elapsed<br> // - "ID" (string) the unique ID for this registered animation<br> // - "earlyFinish" (boolean) If true this animation was cut // short via a call to +link{Animation.finishAnimation()} before // its duration had elapsed. // @param duration (number) Target duration for this animation in ms. The callback will // actually be called a fixed number of times based on this target // duration and the default frame interval // (isc.Animation.interval), which may result in an animation that // is longer than the target duration if some frames exceed the // interval time. The animation will be cut short if it exceeds // 3 times the target duration // @param [acceleration] (AnimationAcceleration) Acceleration bias effect for the animation. // @param [target] (object) If specified the callback will be fired in the scope of the // target passed in. // @return (string) Unique ID for the registered animation action. // @visibility animation_advanced //< registerAnimation : function (callback, duration, acceleration, target) { if (!this._animationTimer) { this._animationTimer = isc.Timer.setTimeout(this.timeoutAction, this.interval); this._startTime = isc.timeStamp(); } if (!target) target = this; if (!duration) duration = this.animateTime; if (isc.isA.String(acceleration)) { if (!isc.Animation.accelerationMap) { isc.Animation.accelerationMap = { smoothStart:isc.Animation.smoothStart, smoothEnd:isc.Animation.smoothEnd, smoothStartEnd:isc.Animation.smoothStartEnd // Support the user specifying "none" - just don't use any biasing // function - same as if they said "foo" // none:null } } acceleration = isc.Animation.accelerationMap[acceleration]; } var ID = this.generateAnimationID(); this.registry.add({ ID:ID, target:target, callback:callback, duration:duration, elapsed:0, totalFrames:Math.round(duration/this.interval), currentFrame:0, // For frame based animation (the default), don't allow animation to exceed // three times the specified duration. maxDuration:duration*3, acceleration:acceleration }); return ID; }, //> @classMethod Animation.clearAnimation() // Clear a registered animation action. Only meaningful if the regisetered animation has // not completed (i.e. the specified duration for the action has not elapsed since the // action was registered). Will un-register the action and prevent it from firing again. // @param ID (string) ID for the action to be unregistered. This is the ID returned from // Animation.registerAnimation(). // @visibility animation_advanced //< clearAnimation : function (ID) { for (var i=0; i<this.registry.length; i++) { if (this.registry[i].ID == ID) { this.registry.removeAt(i); break; } } }, //> @classMethod Animation.finishAnimation() // "Finish" a registered animation, by clearing it, and firing it with a // ratio of 1 and an additional 'earlyFinish' which will be passed to the callback. // @param ID (string) ID for the action to be finished. This is the ID returned from // Animation.registerAnimation(). // @visibility animation_advanced //< finishAnimation : function (ID) { for (var i = 0; i < this.registry.length; i++) { if (this.registry[i].ID == ID) { var entry = this.registry[i]; break; } } this.clearAnimation(ID); this.fireAction(entry, 1, true); }, // fireTimer() - this is fired every interval and handles: // - firing any animations whose total duration has not yet elapsed // - unregistering any animations whose total duration has elapsed // - setting up the timer to fire this method again after the next Animation.interval ms fireTimer : function () { var newTime = isc.timeStamp(), elapsed = (newTime - this._startTime), // Adjust for the difference between the actual elapsed time and the desired // interval so we average out to firing as close to every [interval] ms as possible interval = Math.max(0, this.interval - (elapsed - this.interval)); //this.logWarn("timer firing - elapsed is:"+ elapsed + ", so interval is:"+ interval); this._animationTimer = isc.Timer.setTimeout(this.timeoutAction, interval); this._startTime = newTime; for (var i = 0; i < this.registry.length; i++) { var entry = this.registry[i]; // We don't expect this to happen because we do a removeEmpty below if (entry == null) continue; entry.elapsed += elapsed; var nextFrame = entry.currentFrame + 1; if (!isc.Animation.timeBased && ((entry.elapsed / entry.maxDuration) > (nextFrame / entry.totalFrames) )) { nextFrame = Math.min(entry.totalFrames, Math.ceil((entry.elapsed/entry.maxDuration) * entry.totalFrames)); } entry.currentFrame = nextFrame; var unbiasedRatio = isc.Animation.timeBased ? entry.elapsed/entry.duration : entry.currentFrame/entry.totalFrames; var ratio = unbiasedRatio, acceleration = entry.acceleration; if (acceleration && isc.isA.Function(acceleration)) { try { ratio = entry.acceleration(ratio); } catch(e) { this.logWarn("Custom ratio function for animation:" + isc.Log.echoAll(entry) + "\nCaused an error:"+ (e.message ? e.message : e)); // delete it, so even if its time hasn't elapsed we don't run into this error // repeatedly until the time expires entry.acceleration = null; } } //this.logWarn("ratio:"+ ratio); // If we've fired the animation for the duration of the entry, ensure we clear it // out so we don't fire it again // Note that we are checking the unbiased ratio - the acceleration is arbitrary, so // may fail to give us a value of 1, in which case we don't want to be left with // an incompleted animation. if (unbiasedRatio >= 1) { ratio = 1; this.registry[i] = null; } var error = null; try { //this.logWarn("firing frame of animation: " + entry.ID + " with ratio: " + ratio); error = this.fireAction(entry, ratio); } catch(e) { error = e; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -