mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
collide updates
This commit is contained in:
@ -1,64 +0,0 @@
|
||||
/* Forked from VelocityJS, MIT License: https://github.com/julianshapiro/velocity | Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {Collide} from './collide'
|
||||
import {animationProcess} from './animation-process'
|
||||
|
||||
|
||||
export function animationStart(elements, options, propertiesMap) {
|
||||
|
||||
if (!elements || !elements.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/* The length of the element set (in the form of a nodeList or an array of elements) is defaulted to 1 in case a
|
||||
single raw DOM element is passed in (which doesn't contain a length property). */
|
||||
var elementsLength = elements.length;
|
||||
var elementsIndex = 0;
|
||||
var eleData;
|
||||
|
||||
|
||||
/**********************************
|
||||
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. */
|
||||
var callUnitConversionData = {
|
||||
lastParent: null,
|
||||
lastPosition: null,
|
||||
lastFontSize: null,
|
||||
lastPercentToPxWidth: null,
|
||||
lastPercentToPxHeight: null,
|
||||
lastEmToPx: null,
|
||||
remToPx: null,
|
||||
vwToPx: null,
|
||||
vhToPx: null
|
||||
};
|
||||
|
||||
/* A container for all the ensuing tween data and metadata associated with this call. This container gets pushed to the page-wide
|
||||
Collide.State.calls array that is processed during animation ticking. */
|
||||
var call = [];
|
||||
|
||||
|
||||
/**************************
|
||||
Element Set Iteration
|
||||
**************************/
|
||||
|
||||
var promises = [];
|
||||
|
||||
if (elements && elements.length) {
|
||||
for (var i = 0, l = elements.length; i < l; i++) {
|
||||
if (elements[i]) {
|
||||
|
||||
promises.push(
|
||||
animationProcess('start', elements, i, options, propertiesMap, callUnitConversionData, call)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
@ -1,8 +1,11 @@
|
||||
import * as util from 'ionic/util/util'
|
||||
import {Collide} from './collide'
|
||||
import {animationStart} from './animation-start'
|
||||
import {processElement} from './process-element'
|
||||
import {animationStop} from './animation-stop'
|
||||
import {startTick} from './tick'
|
||||
|
||||
const data = Collide.data;
|
||||
|
||||
|
||||
export class Animation {
|
||||
constructor() {
|
||||
@ -19,34 +22,150 @@ export class Animation {
|
||||
}
|
||||
}
|
||||
|
||||
_setupElements(clearCache) {
|
||||
/**********************************
|
||||
Animation Call-Wide Variables
|
||||
**********************************/
|
||||
|
||||
/*************
|
||||
Actions
|
||||
*************/
|
||||
/* 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
|
||||
};
|
||||
|
||||
start() {
|
||||
let promise = animationStart(this._elements, this._options, this._properties);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
_queueAnimation() {
|
||||
/* Switch on the element's animating flag. */
|
||||
for (var i = 0, ii = this._elements.length, element; i < ii && (element = this._elements[i]); i++) {
|
||||
data(element).isAnimating = true;
|
||||
|
||||
/*********************
|
||||
Auto-Dequeuing
|
||||
*********************/
|
||||
|
||||
/* To fire the first non-custom-queue entry on an element, the element
|
||||
must be dequeued if its queue stack consists *solely* of the current call. (This can be determined by checking
|
||||
for the 'inprogress' item that is prepended to active queue stack arrays.) Regardless, whenever the element's
|
||||
queue is further appended with additional items -- including delay()'s calls, the queue's
|
||||
first entry is automatically fired. This behavior contrasts that of custom queues, which never auto-fire. */
|
||||
/* Note: When an element set is being subjected to a non-parallel Collide call, the animation will not begin until
|
||||
each one of the elements in the set has reached the end of its individually pre-existing queue chain. */
|
||||
if (this._options.queue === '' && Collide.queue(element)[0] !== 'inprogress') {
|
||||
Collide.dequeue(element);
|
||||
}
|
||||
}
|
||||
|
||||
/* Once the final element in this call's element set has been processed, push the call array onto
|
||||
Collide.State.calls for the animation tick to immediately begin processing. */
|
||||
/* Add the current call plus its associated metadata (the element set and the call's options) onto the global call container.
|
||||
Anything on this call container is subjected to tick() processing. */
|
||||
Collide.State.calls.push([ this._call,
|
||||
this._elements,
|
||||
this._options,
|
||||
null,
|
||||
this._resolve ]);
|
||||
|
||||
startTick();
|
||||
}
|
||||
|
||||
return promise;
|
||||
start() {
|
||||
// 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 !== 'start');
|
||||
|
||||
this._lastType = 'start';
|
||||
|
||||
this._queueAnimation();
|
||||
return this._promise;
|
||||
}
|
||||
|
||||
stop() {
|
||||
// immediately stop where it's at
|
||||
animationStop(this._elements, 'stop');
|
||||
}
|
||||
|
||||
percent(ratio) {
|
||||
this._options.percentComplete = parseFloat(ratio);
|
||||
animationStart(this._elements, this._options, this._properties);
|
||||
finish() {
|
||||
// immediately go to the end of the 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) {
|
||||
for (var i = 0, ii = this._elements.length; i < ii; i++) {
|
||||
eleData = data(this._elements[i]);
|
||||
if (eleData && eleData.isAnimating) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************
|
||||
|
||||
/************
|
||||
Options
|
||||
***********************/
|
||||
************/
|
||||
options(val) {
|
||||
this._options = val || {};
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ export function completeCall(callIndex, isStopped) {
|
||||
eleData.rootPropertyValueCache = {};
|
||||
|
||||
/* If any 3D transform subproperty is at its default value (regardless of unit type), remove it. */
|
||||
for (var j = 0, transforms3DLength = CSS.Lists.transforms3D.length; j < transforms3DLength; j++) {
|
||||
for (var j = 0, jj = CSS.Lists.transforms3D.length; j < jj; j++) {
|
||||
var transformName = CSS.Lists.transforms3D[j];
|
||||
var defaultValue = /^scale/.test(transformName) ? 1 : 0;
|
||||
var currentValue = eleData.transformCache[transformName];
|
||||
@ -154,7 +154,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, callsLength = Collide.State.calls.length; j < callsLength; j++) {
|
||||
for (var j = 0, jj = Collide.State.calls.length; j < jj; j++) {
|
||||
if (Collide.State.calls[j] !== false) {
|
||||
remainingCallsExist = true;
|
||||
break;
|
||||
|
@ -19,14 +19,16 @@ const data = Collide.data;
|
||||
3) Pushing: Consolidation of the tween data followed by its push onto the global in-progress calls container.
|
||||
*/
|
||||
|
||||
export function animationProcess(action, elements, elementsIndex, options, propertiesMap, callUnitConversionData, call) {
|
||||
var resolve;
|
||||
var promise = new Promise(function(res) {
|
||||
resolve = res;
|
||||
});
|
||||
|
||||
var element = elements[elementsIndex];
|
||||
export function processElement(action, animation, elementIndex, clearCache) {
|
||||
var elements = animation._elements;
|
||||
var elementsLength = elements.length;
|
||||
var element = elements[elementIndex];
|
||||
|
||||
var opts = animation._options;
|
||||
var propertiesMap = animation._properties;
|
||||
var callUnitConversionData = animation._unitConversion;
|
||||
var call = animation._call;
|
||||
var resolve = animation._resolve;
|
||||
|
||||
|
||||
/*************************
|
||||
@ -37,9 +39,6 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
Element-Wide Variables
|
||||
***************************/
|
||||
|
||||
/* The runtime opts object is the extension of the current call's options and Collide's page-wide option defaults. */
|
||||
var opts = util.extend({}, Collide.defaults, options);
|
||||
|
||||
/* A container for the processed data associated with each property in the propertyMap.
|
||||
(Each property in the map produces its own 'tween'.) */
|
||||
var tweensContainer = {};
|
||||
@ -143,7 +142,7 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
*******************/
|
||||
|
||||
/* The begin callback is fired once per call -- not once per elemenet -- and is passed the full raw DOM element set as both its context and its first argument. */
|
||||
if (opts.begin && elementsIndex === 0) {
|
||||
if (opts.begin && elementIndex === 0) {
|
||||
/* We throw callbacks in a setTimeout so that thrown errors don't halt the execution of Collide itself. */
|
||||
try {
|
||||
opts.begin.call(elements, elements);
|
||||
@ -219,94 +218,6 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
if (Collide.debug) console.log("tweensContainer (scroll): ", tweensContainer.scroll, element);
|
||||
|
||||
|
||||
/******************************************
|
||||
Tween Data Construction (for Reverse)
|
||||
******************************************/
|
||||
|
||||
/* Reverse acts like a 'start' action in that a property map is animated toward. The only difference is
|
||||
that the property map used for reverse is the inverse of the map used in the previous call. Thus, we manipulate
|
||||
the previous call to construct our new map: use the previous map's end values as our new map's start values. Copy over all other data. */
|
||||
/* Note: Reverse can be directly called via the 'reverse' parameter, or it can be indirectly triggered via the loop option. (Loops are composed of multiple reverses.) */
|
||||
/* Note: Reverse calls do not need to be consecutively chained onto a currently-animating element in order to operate on cached values;
|
||||
there is no harm to reverse being called on a potentially stale data cache since reverse's behavior is simply defined
|
||||
as reverting to the element's values as they were prior to the previous *Collide* call. */
|
||||
} else if (action === 'reverse') {
|
||||
/* Abort if there is no prior animation data to reverse to. */
|
||||
if (!data(element).tweensContainer) {
|
||||
/* Dequeue the element so that this queue entry releases itself immediately, allowing subsequent queue entries to run. */
|
||||
Collide.dequeue(element, opts.queue);
|
||||
return;
|
||||
|
||||
} else {
|
||||
/*********************
|
||||
Options Parsing
|
||||
*********************/
|
||||
|
||||
/* If the element was hidden via the display option in the previous call,
|
||||
revert display to 'auto' prior to reversal so that the element is visible again. */
|
||||
if (data(element).opts.display === 'none') {
|
||||
data(element).opts.display = 'auto';
|
||||
}
|
||||
|
||||
if (data(element).opts.visibility === 'hidden') {
|
||||
data(element).opts.visibility = 'visible';
|
||||
}
|
||||
|
||||
/* If the loop option was set in the previous call, disable it so that 'reverse' calls aren't recursively generated.
|
||||
Further, remove the previous call's callback options; typically, users do not want these to be refired. */
|
||||
data(element).opts.loop = false;
|
||||
data(element).opts.begin = null;
|
||||
data(element).opts.complete = null;
|
||||
|
||||
/* Since we're extending an opts object that has already been extended with the defaults options object,
|
||||
we remove non-explicitly-defined properties that are auto-assigned values. */
|
||||
if (!options.easing) {
|
||||
delete opts.easing;
|
||||
}
|
||||
|
||||
if (!options.duration) {
|
||||
delete opts.duration;
|
||||
}
|
||||
|
||||
/* The opts object used for reversal is an extension of the options object optionally passed into this
|
||||
reverse call plus the options used in the previous Collide call. */
|
||||
opts = util.extend({}, data(element).opts, opts);
|
||||
|
||||
/*************************************
|
||||
Tweens Container Reconstruction
|
||||
*************************************/
|
||||
|
||||
/* Create a deepy copy (indicated via the true flag) of the previous call's tweensContainer. */
|
||||
var lastTweensContainer = util.extend(true, {}, data(element).tweensContainer);
|
||||
|
||||
/* Manipulate the previous tweensContainer by replacing its end values and currentValues with its start values. */
|
||||
for (var lastTween in lastTweensContainer) {
|
||||
/* In addition to tween data, tweensContainers contain an element property that we ignore here. */
|
||||
if (lastTween !== 'element') {
|
||||
var lastStartValue = lastTweensContainer[lastTween].startValue;
|
||||
|
||||
lastTweensContainer[lastTween].startValue = lastTweensContainer[lastTween].currentValue = lastTweensContainer[lastTween].endValue;
|
||||
lastTweensContainer[lastTween].endValue = lastStartValue;
|
||||
|
||||
/* Easing is the only option that embeds into the individual tween data (since it can be defined on a per-property basis).
|
||||
Accordingly, every property's easing value must be updated when an options object is passed in with a reverse call.
|
||||
The side effect of this extensibility is that all per-property easing values are forcefully reset to the new value. */
|
||||
if (!util.isEmptyObject(options)) {
|
||||
lastTweensContainer[lastTween].easing = opts.easing;
|
||||
}
|
||||
|
||||
if (Collide.debug) console.log("reverse tweensContainer (" + lastTween + "): " + JSON.stringify(lastTweensContainer[lastTween]), element);
|
||||
}
|
||||
}
|
||||
|
||||
tweensContainer = lastTweensContainer;
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
Start: Tween Data Construction
|
||||
*********************************/
|
||||
|
||||
} else if (action === 'start') {
|
||||
|
||||
/****************************
|
||||
@ -325,8 +236,11 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
/* The per-element isAnimating flag is used to indicate whether it's safe (i.e. the data isn't stale)
|
||||
to transfer over end values to use as start values. If it's set to true and there is a previous
|
||||
Collide call to pull values from, do so. */
|
||||
if (data(element).tweensContainer && data(element).isAnimating === true) {
|
||||
lastTweensContainer = data(element).tweensContainer;
|
||||
var eleData = data(element);
|
||||
if (clearCache) {
|
||||
eleData.tweensContainer = undefined;
|
||||
} else if (eleData.tweensContainer && eleData.isAnimating === true) {
|
||||
lastTweensContainer = eleData.tweensContainer;
|
||||
}
|
||||
|
||||
|
||||
@ -379,11 +293,11 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
/* If functions were passed in as values, pass the function the current element as its context,
|
||||
plus the element's index and the element set's size as arguments. Then, assign the returned value. */
|
||||
if (typeof endValue === 'function') {
|
||||
endValue = endValue.call(element, elementsIndex, elementsLength);
|
||||
endValue = endValue.call(element, elementIndex, elementsLength);
|
||||
}
|
||||
|
||||
if (typeof startValue === 'function') {
|
||||
startValue = startValue.call(element, elementsIndex, elementsLength);
|
||||
startValue = startValue.call(element, elementIndex, elementsLength);
|
||||
}
|
||||
|
||||
/* Allow startValue to be left as undefined to indicate to the ensuing code that its value was not forcefed. */
|
||||
@ -412,17 +326,17 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
|
||||
/* Inject the RGB component tweens into propertiesMap. */
|
||||
for (var i = 0; i < colorComponents.length; i++) {
|
||||
var dataArray = [ endValueRGB[i] ];
|
||||
var dataArray = [ endValueRGB[i] ];
|
||||
|
||||
if (easing) {
|
||||
dataArray.push(easing);
|
||||
}
|
||||
if (easing) {
|
||||
dataArray.push(easing);
|
||||
}
|
||||
|
||||
if (startValueRGB !== undefined) {
|
||||
dataArray.push(startValueRGB[i]);
|
||||
}
|
||||
if (startValueRGB !== undefined) {
|
||||
dataArray.push(startValueRGB[i]);
|
||||
}
|
||||
|
||||
propertiesMap[property + colorComponents[i]] = dataArray;
|
||||
propertiesMap[property + colorComponents[i]] = dataArray;
|
||||
}
|
||||
|
||||
/* Remove the intermediary shorthand property entry now that we've processed it. */
|
||||
@ -470,10 +384,12 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
startValue = 0;
|
||||
}
|
||||
|
||||
|
||||
/* If values have been transferred from the previous Collide call, extract the endValue and rootPropertyValue
|
||||
for all of the current call's properties that were *also* animated in the previous call. */
|
||||
/* Note: Value transferring can optionally be disabled by the user via the _cacheValues option. */
|
||||
if (opts._cacheValues && lastTweensContainer && lastTweensContainer[property]) {
|
||||
|
||||
if (startValue === undefined) {
|
||||
startValue = lastTweensContainer[property].endValue + lastTweensContainer[property].unitType;
|
||||
}
|
||||
@ -680,6 +596,7 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
break;
|
||||
}
|
||||
|
||||
var currentValue = startValue;
|
||||
|
||||
/*********************************************
|
||||
parsePropertyValue(), tweensContainer Push
|
||||
@ -689,13 +606,15 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
tweensContainer[property] = {
|
||||
rootPropertyValue: rootPropertyValue,
|
||||
startValue: startValue,
|
||||
currentValue: startValue,
|
||||
currentValue: currentValue,
|
||||
endValue: endValue,
|
||||
unitType: endValueUnitType,
|
||||
easing: easing
|
||||
};
|
||||
|
||||
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. */
|
||||
@ -720,20 +639,6 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
data(element).tweensContainer = tweensContainer;
|
||||
data(element).opts = opts;
|
||||
}
|
||||
|
||||
/* Switch on the element's animating flag. */
|
||||
data(element).isAnimating = true;
|
||||
|
||||
/* Once the final element in this call's element set has been processed, push the call array onto
|
||||
Collide.State.calls for the animation tick to immediately begin processing. */
|
||||
if (elementsIndex === elementsLength - 1) {
|
||||
/* Add the current call plus its associated metadata (the element set and the call's options) onto the global call container.
|
||||
Anything on this call container is subjected to tick() processing. */
|
||||
Collide.State.calls.push([ call, elements, opts, null, resolve ]);
|
||||
|
||||
} else {
|
||||
elementsIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
} // END: buildQueue
|
||||
@ -768,21 +673,4 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
Auto-Dequeuing
|
||||
*********************/
|
||||
|
||||
/* To fire the first non-custom-queue entry on an element, the element
|
||||
must be dequeued if its queue stack consists *solely* of the current call. (This can be determined by checking
|
||||
for the 'inprogress' item that is prepended to active queue stack arrays.) Regardless, whenever the element's
|
||||
queue is further appended with additional items -- including delay()'s calls, the queue's
|
||||
first entry is automatically fired. This behavior contrasts that of custom queues, which never auto-fire. */
|
||||
/* Note: When an element set is being subjected to a non-parallel Collide call, the animation will not begin until
|
||||
each one of the elements in the set has reached the end of its individually pre-existing queue chain. */
|
||||
if ((opts.queue === '' || opts.queue === 'fx') && Collide.queue(element)[0] !== 'inprogress') {
|
||||
Collide.dequeue(element);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
@ -77,13 +77,14 @@ function tick(timestamp) {
|
||||
timeStart = Collide.State.calls[i][3] = timeCurrent - 16;
|
||||
}
|
||||
|
||||
/* The tween's completion percentage is relative to the tween's start time, not the tween's start value
|
||||
(which would result in unpredictable tween durations since JavaScript's timers are not particularly accurate).
|
||||
Accordingly, we ensure that percentComplete does not exceed 1. */
|
||||
var percentComplete;
|
||||
if (opts.percentComplete !== undefined) {
|
||||
percentComplete = opts.percentComplete;
|
||||
percentComplete = Math.max(Math.min(opts.percentComplete, 1), 0);
|
||||
|
||||
} else {
|
||||
/* The tween's completion percentage is relative to the tween's start time, not the tween's start value
|
||||
(which would result in unpredictable tween durations since JavaScript's timers are not particularly accurate).
|
||||
Accordingly, we ensure that percentComplete does not exceed 1. */
|
||||
percentComplete = Math.min((timeCurrent - timeStart) / opts.duration, 1);
|
||||
}
|
||||
|
||||
@ -93,13 +94,14 @@ function tick(timestamp) {
|
||||
**********************/
|
||||
|
||||
/* For every call, iterate through each of the elements in its set. */
|
||||
for (var j = 0, callLength = call.length; j < callLength; j++) {
|
||||
var tweensContainer = call[j],
|
||||
element = tweensContainer.element;
|
||||
for (var j = 0, jj = call.length; j < jj; j++) {
|
||||
var tweensContainer = call[j];
|
||||
var element = tweensContainer.element;
|
||||
var eleData = Collide.data(element);
|
||||
|
||||
/* Check to see if this element has been deleted midway through the animation by checking for the
|
||||
continued existence of its data cache. If it's gone, skip animating this element. */
|
||||
if (!Collide.data(element)) {
|
||||
if (!eleData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -114,7 +116,6 @@ function tick(timestamp) {
|
||||
(Otherwise, display's 'none' value is set in completeCall() once the animation has completed.) */
|
||||
if (opts.display !== undefined && opts.display !== null && opts.display !== 'none') {
|
||||
if (opts.display === 'flex') {
|
||||
var flexValues = [ '-webkit-box', '-moz-box', '-ms-flexbox', '-webkit-flex' ];
|
||||
|
||||
for (var f = 0; f < flexValues.length; f++) {
|
||||
CSS.setPropertyValue(element, 'display', flexValues[f]);
|
||||
@ -139,11 +140,13 @@ function tick(timestamp) {
|
||||
|
||||
/* Note: In addition to property tween data, tweensContainer contains a reference to its associated element. */
|
||||
if (property !== 'element') {
|
||||
var tween = tweensContainer[property],
|
||||
currentValue,
|
||||
/* Easing can either be a pre-genereated function or a string that references a pre-registered easing
|
||||
on the Collide.Easings object. In either case, return the appropriate easing *function*. */
|
||||
easing = typeof tween.easing === 'string' ? Collide.Easings[tween.easing] : tween.easing;
|
||||
var tween = tweensContainer[property];
|
||||
|
||||
var currentValue;
|
||||
|
||||
/* Easing can either be a pre-genereated function or a string that references a pre-registered easing
|
||||
on the Collide.Easings object. In either case, return the appropriate easing *function*. */
|
||||
var easing = (typeof tween.easing === 'string' ? Collide.Easings[tween.easing] : tween.easing);
|
||||
|
||||
/******************************
|
||||
Current Value Calculation
|
||||
@ -185,7 +188,7 @@ function tick(timestamp) {
|
||||
subsequently chained animations using the same hookRoot but a different hook can use this cached rootPropertyValue. */
|
||||
if (CSS.Hooks.registered[property]) {
|
||||
var hookRoot = CSS.Hooks.getRoot(property),
|
||||
rootPropertyValueCache = Collide.data(element).rootPropertyValueCache[hookRoot];
|
||||
rootPropertyValueCache = eleData.rootPropertyValueCache[hookRoot];
|
||||
|
||||
if (rootPropertyValueCache) {
|
||||
tween.rootPropertyValue = rootPropertyValueCache;
|
||||
@ -214,9 +217,9 @@ function tick(timestamp) {
|
||||
if (CSS.Hooks.registered[property]) {
|
||||
/* Since adjustedSetData contains normalized data ready for DOM updating, the rootPropertyValue needs to be re-extracted from its normalized form. ?? */
|
||||
if (CSS.Normalizations.registered[hookRoot]) {
|
||||
Collide.data(element).rootPropertyValueCache[hookRoot] = CSS.Normalizations.registered[hookRoot]('extract', null, adjustedSetData[1]);
|
||||
eleData.rootPropertyValueCache[hookRoot] = CSS.Normalizations.registered[hookRoot]('extract', null, adjustedSetData[1]);
|
||||
} else {
|
||||
Collide.data(element).rootPropertyValueCache[hookRoot] = adjustedSetData[1];
|
||||
eleData.rootPropertyValueCache[hookRoot] = adjustedSetData[1];
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +242,7 @@ function tick(timestamp) {
|
||||
CSS.flushTransformCache(element);
|
||||
}
|
||||
|
||||
} // END: for (var j = 0, callLength = call.length; j < callLength; j++)
|
||||
} // END: for (var j = 0, jj = call.length; j < jj; j++)
|
||||
|
||||
|
||||
/* The non-'none' display value is only applied to an element once -- when its associated call is first ticked through.
|
||||
@ -276,3 +279,5 @@ function tick(timestamp) {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const flexValues = [ '-webkit-box', '-moz-box', '-ms-flexbox', '-webkit-flex' ];
|
||||
|
@ -4,7 +4,7 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style="position: absolute; top: 20px; left: 300px;">
|
||||
<div style="position: absolute; top: 300px; left: 0px;">
|
||||
|
||||
<div class="red square" style="position:absolute; width:100px; height:100px; background:red; top: 0; left: 0;"></div>
|
||||
<div class="green square" style="position:absolute; width:100px; height:100px; background:green; top: 0; left: 100px;"></div>
|
||||
|
@ -1,7 +1,10 @@
|
||||
import {Component, Decorator, View as NgView, NgElement, bootstrap} from 'angular2/angular2';
|
||||
import {Animation} from 'ionic/ionic';
|
||||
|
||||
|
||||
let opacity = 0.2;
|
||||
let rotateZ = '180deg';
|
||||
let translateX = '100px';
|
||||
let scale = 0.6;
|
||||
|
||||
@Component({ selector: '[ion-app]' })
|
||||
@NgView({
|
||||
@ -10,21 +13,22 @@ import {Animation} from 'ionic/ionic';
|
||||
class IonicApp {
|
||||
constructor() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
fadeOut() {
|
||||
console.debug('fadeOut');
|
||||
this.animation = new Animation();
|
||||
this.animation.elements( document.querySelectorAll('.square') );
|
||||
|
||||
this.animation.duration(2000);
|
||||
this.animation.easing('swing');
|
||||
this.animation.duration(1000);
|
||||
this.animation.easing('linear');
|
||||
|
||||
this.animation.property('opacity', opacity);
|
||||
this.animation.property('translateX', translateX);
|
||||
this.animation.property('translateY', translateX);
|
||||
this.animation.property('rotateZ', rotateZ);
|
||||
this.animation.property('scale', scale);
|
||||
|
||||
this.animation.property('opacity', 0.2);
|
||||
this.animation.property('translateX', '100px');
|
||||
this.animation.property('translateY', '100px');
|
||||
this.animation.property('rotateZ', '180deg');
|
||||
this.animation.property('scale', '0.5');
|
||||
|
||||
let q = this.animation.start();
|
||||
|
||||
@ -34,17 +38,18 @@ class IonicApp {
|
||||
}
|
||||
|
||||
fadeIn() {
|
||||
console.debug('fadeIn');
|
||||
this.animation = new Animation();
|
||||
this.animation.elements( document.querySelectorAll('.square') );
|
||||
|
||||
this.animation.duration(2000);
|
||||
this.animation.easing('swing');
|
||||
this.animation.duration(1000);
|
||||
this.animation.easing('linear');
|
||||
|
||||
this.animation.property('opacity', 1);
|
||||
this.animation.property('translateX', '0px');
|
||||
this.animation.property('translateY', '0px');
|
||||
this.animation.property('rotateZ', '0deg');
|
||||
this.animation.property('scale', '1');
|
||||
this.animation.property('translateX', 0);
|
||||
this.animation.property('translateY', 0);
|
||||
this.animation.property('rotateZ', 0);
|
||||
this.animation.property('scale', 1);
|
||||
|
||||
let q = this.animation.start();
|
||||
|
||||
@ -58,26 +63,22 @@ class IonicApp {
|
||||
}
|
||||
|
||||
percent(ev) {
|
||||
let ratio = parseFloat(ev.srcElement.value) / 100;
|
||||
console.log('percent ratio', ratio);
|
||||
let percentComplete = parseFloat(ev.srcElement.value) / 100;
|
||||
|
||||
this.animation = new Animation();
|
||||
this.animation.elements( document.querySelectorAll('.square') );
|
||||
if (!this.percentAnimation) {
|
||||
this.percentAnimation = new Animation();
|
||||
this.percentAnimation.elements( document.querySelectorAll('.square') );
|
||||
|
||||
this.animation.duration(2000);
|
||||
this.animation.easing('swing');
|
||||
this.percentAnimation.property('opacity', opacity);
|
||||
this.percentAnimation.property('translateX', translateX);
|
||||
this.percentAnimation.property('translateY', translateX);
|
||||
this.percentAnimation.property('rotateZ', rotateZ);
|
||||
this.percentAnimation.property('scale', scale);
|
||||
|
||||
this.animation.property('opacity', 0.2);
|
||||
this.animation.property('translateX', '100px');
|
||||
this.animation.property('translateY', '100px');
|
||||
this.animation.property('rotateZ', '180deg');
|
||||
this.animation.property('scale', '0.5');
|
||||
this.percentAnimation.ready();
|
||||
}
|
||||
|
||||
this.animation.percent(ratio);
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.animation.stop();
|
||||
this.percentAnimation.percent(percentComplete);
|
||||
}
|
||||
|
||||
velocityStart() {
|
||||
|
@ -50,7 +50,7 @@ export class Tab extends NavControllerBase {
|
||||
this.config = Tab.config.invoke(this);
|
||||
this.setHidden = setHidden
|
||||
|
||||
this.tabId = util.uid()
|
||||
this.tabId = util.nextUid()
|
||||
setId('tab-content-' + this.tabId)
|
||||
setLabelby('tab-item-' + this.tabId)
|
||||
setRole('tabpanel')
|
||||
|
@ -4,16 +4,33 @@ export function clamp(min, n, max) {
|
||||
return Math.max(min, Math.min(n, max));
|
||||
}
|
||||
|
||||
export function extend(dest) {
|
||||
for (var i = 1, ii = arguments.length; i < ii; i++) {
|
||||
var source = arguments[i] || {};
|
||||
for (var key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
dest[key] = source[key];
|
||||
export function extend(dst) {
|
||||
return baseExtend(dst, [].slice.call(arguments, 1), false);
|
||||
}
|
||||
|
||||
export function merge(dst) {
|
||||
return baseExtend(dst, [].slice.call(arguments, 1), true);
|
||||
}
|
||||
|
||||
function baseExtend(dst, objs, deep) {
|
||||
for (var i = 0, ii = objs.length; i < ii; ++i) {
|
||||
var obj = objs[i];
|
||||
if (!isObject(obj) && !isFunction(obj)) continue;
|
||||
var keys = Object.keys(obj);
|
||||
for (var j = 0, jj = keys.length; j < jj; j++) {
|
||||
var key = keys[j];
|
||||
var src = obj[key];
|
||||
|
||||
if (deep && isObject(src)) {
|
||||
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
|
||||
baseExtend(dst[key], [src], true);
|
||||
} else {
|
||||
dst[key] = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
export function defaults(dest) {
|
||||
@ -41,9 +58,9 @@ export function pascalCaseToDashCase(str = '') {
|
||||
})
|
||||
}
|
||||
|
||||
let _uid = 0
|
||||
export function uid() {
|
||||
return _uid++
|
||||
let uid = 0
|
||||
export function nextUid() {
|
||||
return ++uid;
|
||||
}
|
||||
|
||||
export class Log {
|
||||
|
Reference in New Issue
Block a user