From 19c16e743391e5abc8b467a0ccd9604ac8f8b136 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Tue, 28 Apr 2015 10:34:47 -0500 Subject: [PATCH] collide updates --- ionic/collide/animation.js | 157 +++++++++++++++++-------------- ionic/collide/complete-call.js | 2 +- ionic/collide/process-element.js | 2 - ionic/collide/tick.js | 6 +- 4 files changed, 90 insertions(+), 77 deletions(-) diff --git a/ionic/collide/animation.js b/ionic/collide/animation.js index 306c3c0790..37b0120be3 100644 --- a/ionic/collide/animation.js +++ b/ionic/collide/animation.js @@ -3,6 +3,7 @@ import {Collide} from './collide' import {processElement} from './process-element' import {animationStop} from './animation-stop' import {startTick} from './tick' +import {dom} from 'ionic/util' const data = Collide.data; @@ -12,6 +13,8 @@ export class Animation { this._elements = null; this._options = {}; this._properties = {}; + this._resolve = null; + this._call = null; } elements(ele) { @@ -22,40 +25,69 @@ export class Animation { } } - _setupElements(clearCache) { - /********************************** - Animation Call-Wide Variables - **********************************/ + _setupElements(clearCache, onNextFrame) { - /* A container for CSS unit conversion ratios (e.g. %, rem, and em ==> px) that is used to cache ratios across all elements - being animated in a single Collide call. Calculating unit ratios necessitates DOM querying and updating, and is therefore - avoided (via caching) wherever possible. This container is call-wide instead of page-wide to avoid the risk of using stale - conversion metrics across Collide animations that are not immediately consecutively chained. */ - this._unitConversion = { - lastParent: null, - lastPosition: null, - lastFontSize: null, - lastPercentToPxWidth: null, - lastPercentToPxHeight: null, - lastEmToPx: null, - remToPx: null, - vwToPx: null, - vhToPx: null - }; - - this._call = []; - - this._options = util.extend({}, Collide.defaults, this._options); - - for (var i = 0, ii = this._elements.length; i < ii; i++) { - processElement('start', this, i, clearCache); + // ensure another animation wasnt about to start + if (this._nextAF) { + dom.rafCancel(this._nextAF); } + + if (this.isAnimating()) { + this.stop(); + } + + this._promise = new Promise(res => { + this._resolve = res; + }); + + this._call = null; + + // in the next frame, do all the DOM GETs to load element info + this._nextAF = dom.raf(() => { + /********************************** + Animation Call-Wide Variables + **********************************/ + + /* A container for CSS unit conversion ratios (e.g. %, rem, and em ==> px) that is used to cache ratios across all elements + being animated in a single Collide call. Calculating unit ratios necessitates DOM querying and updating, and is therefore + avoided (via caching) wherever possible. This container is call-wide instead of page-wide to avoid the risk of using stale + conversion metrics across Collide animations that are not immediately consecutively chained. */ + this._unitConversion = { + lastParent: null, + lastPosition: null, + lastFontSize: null, + lastPercentToPxWidth: null, + lastPercentToPxHeight: null, + lastEmToPx: null, + remToPx: null, + vwToPx: null, + vhToPx: null + }; + + this._call = []; + + this._options = util.extend({}, Collide.defaults, this._options); + + // get the elements ready + for (var i = 0, ii = this._elements.length; i < ii; i++) { + processElement('start', this, i, clearCache); + } + + onNextFrame(); + }); + } _queueAnimation() { /* Switch on the element's animating flag. */ + if (this._call === null) return; + + var eleData; for (var i = 0, ii = this._elements.length, element; i < ii && (element = this._elements[i]); i++) { - data(element).isAnimating = true; + eleData = data(element); + if (eleData) { + eleData.isAnimating = true; + } /********************* Auto-Dequeuing @@ -87,27 +119,37 @@ export class Animation { } start() { - // get the elements ready - if (this.isAnimating()) { - this.stop(); - if (this._resolve) { - this._resolve(); - } - } + var clearCache = (this._aniType !== 'start'); - this._resolve; - this._promise = new Promise(res => { - this._resolve = res; + this._setupElements(clearCache, () => { + this._aniType = 'start'; + this._queueAnimation(); }); - this._setupElements(this._lastType !== 'start'); - - this._lastType = 'start'; - - this._queueAnimation(); return this._promise; } + ready() { + var clearCache = (this._aniType !== 'percent'); + + this._setupElements(clearCache, () => { + this._aniType = 'percent'; + }); + + return this._promise; + } + + percent(percentComplete) { + // go to and stop at a specific point in the animation + if (this._aniType = 'percent') { + this._options.percentComplete = percentComplete; + + this._queueAnimation(); + + startTick(); + } + } + stop() { // immediately stop where it's at animationStop(this._elements, 'stop'); @@ -118,37 +160,6 @@ export class Animation { animationStop(this._elements, 'finish'); } - ready() { - // get the elements ready - if (this.isAnimating()) { - this.stop(); - if (this._resolve) { - this._resolve(); - } - } - - this._resolve; - this._promise = new Promise(res => { - this._resolve = res; - }); - - this._setupElements(this._lastType !== 'percent'); - - this._lastType = 'percent'; - - return this._promise; - } - - percent(percentComplete) { - // go to and stop at a specific point in the animation - // must call ready() first - this._options.percentComplete = parseFloat(percentComplete); - - this._queueAnimation(); - - startTick(); - } - isAnimating() { var eleData; if (this._elements) { diff --git a/ionic/collide/complete-call.js b/ionic/collide/complete-call.js index f46c53827c..02dd0c9edf 100644 --- a/ionic/collide/complete-call.js +++ b/ionic/collide/complete-call.js @@ -155,7 +155,7 @@ export function completeCall(callIndex, isStopped) { /* Iterate through the calls array to determine if this was the final in-progress animation. If so, set a flag to end ticking and clear the calls array. */ for (var j = 0, jj = Collide.State.calls.length; j < jj; j++) { - if (Collide.State.calls[j] !== false) { + if (Collide.State.calls[j] !== false && Collide.State.calls[j][0]) { remainingCallsExist = true; break; } diff --git a/ionic/collide/process-element.js b/ionic/collide/process-element.js index 9507fae692..42dfe709e0 100644 --- a/ionic/collide/process-element.js +++ b/ionic/collide/process-element.js @@ -613,8 +613,6 @@ export function processElement(action, animation, elementIndex, clearCache) { }; if (Collide.debug) console.log('tweensContainer (' + property + '): ' + JSON.stringify(tweensContainer[property]), element); - - console.log('processElement parsePropertyValue: startValue', startValue, 'currentValue', currentValue, 'endValue', endValue); } /* Along with its property data, store a reference to the element itself onto tweensContainer. */ diff --git a/ionic/collide/tick.js b/ionic/collide/tick.js index c575fd48af..b9f93fadec 100644 --- a/ionic/collide/tick.js +++ b/ionic/collide/tick.js @@ -65,6 +65,10 @@ function tick(timestamp) { firstTick = !!timeStart, tweenDummyValue = null; + if (!call) { + continue; + } + /* If timeStart is undefined, then this is the first time that this call has been processed by tick(). We assign timeStart now so that its value is as close to the real animation start time as possible. (Conversely, had timeStart been defined when this call was added to Collide.State.calls, the delay @@ -79,7 +83,7 @@ function tick(timestamp) { var percentComplete; if (opts.percentComplete !== undefined) { - percentComplete = Math.max(Math.min(opts.percentComplete, 1), 0); + percentComplete = Math.max(Math.min(parseFloat(opts.percentComplete), 1), 0); } else { /* The tween's completion percentage is relative to the tween's start time, not the tween's start value