Animator.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-fx-Animator'>/**
  19. </span> * @class Ext.fx.Animator
  20. *
  21. * This class is used to run keyframe based animations, which follows the CSS3 based animation structure.
  22. * Keyframe animations differ from typical from/to animations in that they offer the ability to specify values
  23. * at various points throughout the animation.
  24. *
  25. * ## Using Keyframes
  26. *
  27. * The {@link #keyframes} option is the most important part of specifying an animation when using this
  28. * class. A key frame is a point in a particular animation. We represent this as a percentage of the
  29. * total animation duration. At each key frame, we can specify the target values at that time. Note that
  30. * you *must* specify the values at 0% and 100%, the start and ending values. There is also a {@link #keyframe}
  31. * event that fires after each key frame is reached.
  32. *
  33. * ## Example
  34. *
  35. * In the example below, we modify the values of the element at each fifth throughout the animation.
  36. *
  37. * @example
  38. * Ext.create('Ext.fx.Animator', {
  39. * target: Ext.getBody().createChild({
  40. * style: {
  41. * width: '100px',
  42. * height: '100px',
  43. * 'background-color': 'red'
  44. * }
  45. * }),
  46. * duration: 10000, // 10 seconds
  47. * keyframes: {
  48. * 0: {
  49. * opacity: 1,
  50. * backgroundColor: 'FF0000'
  51. * },
  52. * 20: {
  53. * x: 30,
  54. * opacity: 0.5
  55. * },
  56. * 40: {
  57. * x: 130,
  58. * backgroundColor: '0000FF'
  59. * },
  60. * 60: {
  61. * y: 80,
  62. * opacity: 0.3
  63. * },
  64. * 80: {
  65. * width: 200,
  66. * y: 200
  67. * },
  68. * 100: {
  69. * opacity: 1,
  70. * backgroundColor: '00FF00'
  71. * }
  72. * }
  73. * });
  74. */
  75. Ext.define('Ext.fx.Animator', {
  76. /* Begin Definitions */
  77. mixins: {
  78. observable: 'Ext.util.Observable'
  79. },
  80. requires: ['Ext.fx.Manager'],
  81. /* End Definitions */
  82. <span id='Ext-fx-Animator-property-isAnimator'> /**
  83. </span> * @property {Boolean} isAnimator
  84. * `true` in this class to identify an object as an instantiated Animator, or subclass thereof.
  85. */
  86. isAnimator: true,
  87. <span id='Ext-fx-Animator-cfg-duration'> /**
  88. </span> * @cfg {Number} duration
  89. * Time in milliseconds for the animation to last. Defaults to 250.
  90. */
  91. duration: 250,
  92. <span id='Ext-fx-Animator-cfg-delay'> /**
  93. </span> * @cfg {Number} delay
  94. * Time to delay before starting the animation. Defaults to 0.
  95. */
  96. delay: 0,
  97. /* private used to track a delayed starting time */
  98. delayStart: 0,
  99. <span id='Ext-fx-Animator-cfg-dynamic'> /**
  100. </span> * @cfg {Boolean} dynamic
  101. * Currently only for Component Animation: Only set a component's outer element size bypassing layouts. Set to true to do full layouts for every frame of the animation. Defaults to false.
  102. */
  103. dynamic: false,
  104. <span id='Ext-fx-Animator-cfg-easing'> /**
  105. </span> * @cfg {String} easing
  106. *
  107. * This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
  108. * speed over its duration.
  109. *
  110. * - backIn
  111. * - backOut
  112. * - bounceIn
  113. * - bounceOut
  114. * - ease
  115. * - easeIn
  116. * - easeOut
  117. * - easeInOut
  118. * - elasticIn
  119. * - elasticOut
  120. * - cubic-bezier(x1, y1, x2, y2)
  121. *
  122. * Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
  123. * specification. The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
  124. * be in the range [0, 1] or the definition is invalid.
  125. *
  126. * [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
  127. */
  128. easing: 'ease',
  129. <span id='Ext-fx-Animator-property-running'> /**
  130. </span> * Flag to determine if the animation has started
  131. * @property running
  132. * @type Boolean
  133. */
  134. running: false,
  135. <span id='Ext-fx-Animator-property-paused'> /**
  136. </span> * Flag to determine if the animation is paused. Only set this to true if you need to
  137. * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
  138. * @property paused
  139. * @type Boolean
  140. */
  141. paused: false,
  142. <span id='Ext-fx-Animator-property-damper'> /**
  143. </span> * @private
  144. */
  145. damper: 1,
  146. <span id='Ext-fx-Animator-cfg-iterations'> /**
  147. </span> * @cfg {Number} iterations
  148. * Number of times to execute the animation. Defaults to 1.
  149. */
  150. iterations: 1,
  151. <span id='Ext-fx-Animator-property-currentIteration'> /**
  152. </span> * Current iteration the animation is running.
  153. * @property currentIteration
  154. * @type Number
  155. */
  156. currentIteration: 0,
  157. <span id='Ext-fx-Animator-property-keyframeStep'> /**
  158. </span> * Current keyframe step of the animation.
  159. * @property keyframeStep
  160. * @type Number
  161. */
  162. keyframeStep: 0,
  163. <span id='Ext-fx-Animator-property-animKeyFramesRE'> /**
  164. </span> * @private
  165. */
  166. animKeyFramesRE: /^(from|to|\d+%?)$/,
  167. <span id='Ext-fx-Animator-cfg-target'> /**
  168. </span> * @cfg {Ext.fx.target.Target} target
  169. * The Ext.fx.target to apply the animation to. If not specified during initialization, this can be passed to the applyAnimator
  170. * method to apply the same animation to many targets.
  171. */
  172. <span id='Ext-fx-Animator-cfg-keyframes'> /**
  173. </span> * @cfg {Object} keyframes
  174. * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to'
  175. * is considered '100%'.&lt;b&gt;Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using
  176. * &quot;from&quot; or &quot;to&quot;&lt;/b&gt;. A keyframe declaration without these keyframe selectors is invalid and will not be available for
  177. * animation. The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to
  178. * be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example:
  179. &lt;pre&gt;&lt;code&gt;
  180. keyframes : {
  181. '0%': {
  182. left: 100
  183. },
  184. '40%': {
  185. left: 150
  186. },
  187. '60%': {
  188. left: 75
  189. },
  190. '100%': {
  191. left: 100
  192. }
  193. }
  194. &lt;/code&gt;&lt;/pre&gt;
  195. */
  196. constructor: function(config) {
  197. var me = this;
  198. config = Ext.apply(me, config || {});
  199. me.config = config;
  200. me.id = Ext.id(null, 'ext-animator-');
  201. me.addEvents(
  202. <span id='Ext-fx-Animator-event-beforeanimate'> /**
  203. </span> * @event beforeanimate
  204. * Fires before the animation starts. A handler can return false to cancel the animation.
  205. * @param {Ext.fx.Animator} this
  206. */
  207. 'beforeanimate',
  208. <span id='Ext-fx-Animator-event-keyframe'> /**
  209. </span> * @event keyframe
  210. * Fires at each keyframe.
  211. * @param {Ext.fx.Animator} this
  212. * @param {Number} keyframe step number
  213. */
  214. 'keyframe',
  215. <span id='Ext-fx-Animator-event-afteranimate'> /**
  216. </span> * @event afteranimate
  217. * Fires when the animation is complete.
  218. * @param {Ext.fx.Animator} this
  219. * @param {Date} startTime
  220. */
  221. 'afteranimate'
  222. );
  223. me.mixins.observable.constructor.call(me, config);
  224. me.timeline = [];
  225. me.createTimeline(me.keyframes);
  226. if (me.target) {
  227. me.applyAnimator(me.target);
  228. Ext.fx.Manager.addAnim(me);
  229. }
  230. },
  231. <span id='Ext-fx-Animator-method-sorter'> /**
  232. </span> * @private
  233. */
  234. sorter: function (a, b) {
  235. return a.pct - b.pct;
  236. },
  237. <span id='Ext-fx-Animator-method-createTimeline'> /**
  238. </span> * @private
  239. * Takes the given keyframe configuration object and converts it into an ordered array with the passed attributes per keyframe
  240. * or applying the 'to' configuration to all keyframes. Also calculates the proper animation duration per keyframe.
  241. */
  242. createTimeline: function(keyframes) {
  243. var me = this,
  244. attrs = [],
  245. to = me.to || {},
  246. duration = me.duration,
  247. prevMs, ms, i, ln, pct, anim, nextAnim, attr;
  248. for (pct in keyframes) {
  249. if (keyframes.hasOwnProperty(pct) &amp;&amp; me.animKeyFramesRE.test(pct)) {
  250. attr = {attrs: Ext.apply(keyframes[pct], to)};
  251. // CSS3 spec allow for from/to to be specified.
  252. if (pct == &quot;from&quot;) {
  253. pct = 0;
  254. }
  255. else if (pct == &quot;to&quot;) {
  256. pct = 100;
  257. }
  258. // convert % values into integers
  259. attr.pct = parseInt(pct, 10);
  260. attrs.push(attr);
  261. }
  262. }
  263. // Sort by pct property
  264. Ext.Array.sort(attrs, me.sorter);
  265. // Only an end
  266. //if (attrs[0].pct) {
  267. // attrs.unshift({pct: 0, attrs: element.attrs});
  268. //}
  269. ln = attrs.length;
  270. for (i = 0; i &lt; ln; i++) {
  271. prevMs = (attrs[i - 1]) ? duration * (attrs[i - 1].pct / 100) : 0;
  272. ms = duration * (attrs[i].pct / 100);
  273. me.timeline.push({
  274. duration: ms - prevMs,
  275. attrs: attrs[i].attrs
  276. });
  277. }
  278. },
  279. <span id='Ext-fx-Animator-property-applyAnimator'> /**
  280. </span> * Applies animation to the Ext.fx.target
  281. * @private
  282. * @param target
  283. * @type String/Object
  284. */
  285. applyAnimator: function(target) {
  286. var me = this,
  287. anims = [],
  288. timeline = me.timeline,
  289. reverse = me.reverse,
  290. ln = timeline.length,
  291. anim, easing, damper, initial, attrs, lastAttrs, i;
  292. if (me.fireEvent('beforeanimate', me) !== false) {
  293. for (i = 0; i &lt; ln; i++) {
  294. anim = timeline[i];
  295. attrs = anim.attrs;
  296. easing = attrs.easing || me.easing;
  297. damper = attrs.damper || me.damper;
  298. delete attrs.easing;
  299. delete attrs.damper;
  300. anim = new Ext.fx.Anim({
  301. target: target,
  302. easing: easing,
  303. damper: damper,
  304. duration: anim.duration,
  305. paused: true,
  306. to: attrs
  307. });
  308. anims.push(anim);
  309. }
  310. me.animations = anims;
  311. me.target = anim.target;
  312. for (i = 0; i &lt; ln - 1; i++) {
  313. anim = anims[i];
  314. anim.nextAnim = anims[i + 1];
  315. anim.on('afteranimate', function() {
  316. this.nextAnim.paused = false;
  317. });
  318. anim.on('afteranimate', function() {
  319. this.fireEvent('keyframe', this, ++this.keyframeStep);
  320. }, me);
  321. }
  322. anims[ln - 1].on('afteranimate', function() {
  323. this.lastFrame();
  324. }, me);
  325. }
  326. },
  327. <span id='Ext-fx-Animator-method-start'> /**
  328. </span> * @private
  329. * Fires beforeanimate and sets the running flag.
  330. */
  331. start: function(startTime) {
  332. var me = this,
  333. delay = me.delay,
  334. delayStart = me.delayStart,
  335. delayDelta;
  336. if (delay) {
  337. if (!delayStart) {
  338. me.delayStart = startTime;
  339. return;
  340. }
  341. else {
  342. delayDelta = startTime - delayStart;
  343. if (delayDelta &lt; delay) {
  344. return;
  345. }
  346. else {
  347. // Compensate for frame delay;
  348. startTime = new Date(delayStart.getTime() + delay);
  349. }
  350. }
  351. }
  352. if (me.fireEvent('beforeanimate', me) !== false) {
  353. me.startTime = startTime;
  354. me.running = true;
  355. me.animations[me.keyframeStep].paused = false;
  356. }
  357. },
  358. <span id='Ext-fx-Animator-method-lastFrame'> /**
  359. </span> * @private
  360. * Perform lastFrame cleanup and handle iterations
  361. * @returns a hash of the new attributes.
  362. */
  363. lastFrame: function() {
  364. var me = this,
  365. iter = me.iterations,
  366. iterCount = me.currentIteration;
  367. iterCount++;
  368. if (iterCount &lt; iter) {
  369. me.startTime = new Date();
  370. me.currentIteration = iterCount;
  371. me.keyframeStep = 0;
  372. me.applyAnimator(me.target);
  373. me.animations[me.keyframeStep].paused = false;
  374. }
  375. else {
  376. me.currentIteration = 0;
  377. me.end();
  378. }
  379. },
  380. <span id='Ext-fx-Animator-method-end'> /**
  381. </span> * Fire afteranimate event and end the animation. Usually called automatically when the
  382. * animation reaches its final frame, but can also be called manually to pre-emptively
  383. * stop and destroy the running animation.
  384. */
  385. end: function() {
  386. var me = this;
  387. me.fireEvent('afteranimate', me, me.startTime, new Date() - me.startTime);
  388. },
  389. isReady: function() {
  390. return this.paused === false &amp;&amp; this.running === false &amp;&amp; this.iterations &gt; 0;
  391. },
  392. isRunning: function() {
  393. // Explicitly return false, we don't want to be run continuously by the manager
  394. return false;
  395. }
  396. });</pre>
  397. </body>
  398. </html>