mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 11:41:20 +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 {Collide} from './collide'
|
||||||
import {animationStart} from './animation-start'
|
import {processElement} from './process-element'
|
||||||
import {animationStop} from './animation-stop'
|
import {animationStop} from './animation-stop'
|
||||||
import {startTick} from './tick'
|
import {startTick} from './tick'
|
||||||
|
|
||||||
|
const data = Collide.data;
|
||||||
|
|
||||||
|
|
||||||
export class Animation {
|
export class Animation {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -19,34 +22,150 @@ export class Animation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setupElements(clearCache) {
|
||||||
|
/**********************************
|
||||||
|
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
|
||||||
Actions
|
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() {
|
this._call = [];
|
||||||
let promise = animationStart(this._elements, this._options, this._properties);
|
|
||||||
|
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();
|
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() {
|
stop() {
|
||||||
|
// immediately stop where it's at
|
||||||
animationStop(this._elements, 'stop');
|
animationStop(this._elements, 'stop');
|
||||||
}
|
}
|
||||||
|
|
||||||
percent(ratio) {
|
finish() {
|
||||||
this._options.percentComplete = parseFloat(ratio);
|
// immediately go to the end of the animation
|
||||||
animationStart(this._elements, this._options, this._properties);
|
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();
|
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
|
||||||
***********************/
|
************/
|
||||||
options(val) {
|
options(val) {
|
||||||
this._options = val || {};
|
this._options = val || {};
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ export function completeCall(callIndex, isStopped) {
|
|||||||
eleData.rootPropertyValueCache = {};
|
eleData.rootPropertyValueCache = {};
|
||||||
|
|
||||||
/* If any 3D transform subproperty is at its default value (regardless of unit type), remove it. */
|
/* 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 transformName = CSS.Lists.transforms3D[j];
|
||||||
var defaultValue = /^scale/.test(transformName) ? 1 : 0;
|
var defaultValue = /^scale/.test(transformName) ? 1 : 0;
|
||||||
var currentValue = eleData.transformCache[transformName];
|
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.
|
/* 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. */
|
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) {
|
if (Collide.State.calls[j] !== false) {
|
||||||
remainingCallsExist = true;
|
remainingCallsExist = true;
|
||||||
break;
|
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.
|
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) {
|
export function processElement(action, animation, elementIndex, clearCache) {
|
||||||
var resolve;
|
var elements = animation._elements;
|
||||||
var promise = new Promise(function(res) {
|
|
||||||
resolve = res;
|
|
||||||
});
|
|
||||||
|
|
||||||
var element = elements[elementsIndex];
|
|
||||||
var elementsLength = elements.length;
|
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
|
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.
|
/* A container for the processed data associated with each property in the propertyMap.
|
||||||
(Each property in the map produces its own 'tween'.) */
|
(Each property in the map produces its own 'tween'.) */
|
||||||
var tweensContainer = {};
|
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. */
|
/* 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. */
|
/* We throw callbacks in a setTimeout so that thrown errors don't halt the execution of Collide itself. */
|
||||||
try {
|
try {
|
||||||
opts.begin.call(elements, elements);
|
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);
|
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') {
|
} 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)
|
/* 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
|
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. */
|
Collide call to pull values from, do so. */
|
||||||
if (data(element).tweensContainer && data(element).isAnimating === true) {
|
var eleData = data(element);
|
||||||
lastTweensContainer = data(element).tweensContainer;
|
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,
|
/* 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. */
|
plus the element's index and the element set's size as arguments. Then, assign the returned value. */
|
||||||
if (typeof endValue === 'function') {
|
if (typeof endValue === 'function') {
|
||||||
endValue = endValue.call(element, elementsIndex, elementsLength);
|
endValue = endValue.call(element, elementIndex, elementsLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof startValue === 'function') {
|
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. */
|
/* Allow startValue to be left as undefined to indicate to the ensuing code that its value was not forcefed. */
|
||||||
@ -470,10 +384,12 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
|||||||
startValue = 0;
|
startValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If values have been transferred from the previous Collide call, extract the endValue and rootPropertyValue
|
/* 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. */
|
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. */
|
/* Note: Value transferring can optionally be disabled by the user via the _cacheValues option. */
|
||||||
if (opts._cacheValues && lastTweensContainer && lastTweensContainer[property]) {
|
if (opts._cacheValues && lastTweensContainer && lastTweensContainer[property]) {
|
||||||
|
|
||||||
if (startValue === undefined) {
|
if (startValue === undefined) {
|
||||||
startValue = lastTweensContainer[property].endValue + lastTweensContainer[property].unitType;
|
startValue = lastTweensContainer[property].endValue + lastTweensContainer[property].unitType;
|
||||||
}
|
}
|
||||||
@ -680,6 +596,7 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var currentValue = startValue;
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
parsePropertyValue(), tweensContainer Push
|
parsePropertyValue(), tweensContainer Push
|
||||||
@ -689,13 +606,15 @@ export function animationProcess(action, elements, elementsIndex, options, prope
|
|||||||
tweensContainer[property] = {
|
tweensContainer[property] = {
|
||||||
rootPropertyValue: rootPropertyValue,
|
rootPropertyValue: rootPropertyValue,
|
||||||
startValue: startValue,
|
startValue: startValue,
|
||||||
currentValue: startValue,
|
currentValue: currentValue,
|
||||||
endValue: endValue,
|
endValue: endValue,
|
||||||
unitType: endValueUnitType,
|
unitType: endValueUnitType,
|
||||||
easing: easing
|
easing: easing
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Collide.debug) console.log('tweensContainer (' + property + '): ' + JSON.stringify(tweensContainer[property]), element);
|
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. */
|
/* 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).tweensContainer = tweensContainer;
|
||||||
data(element).opts = opts;
|
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
|
} // 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;
|
timeStart = Collide.State.calls[i][3] = timeCurrent - 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var percentComplete;
|
||||||
|
if (opts.percentComplete !== undefined) {
|
||||||
|
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
|
/* 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).
|
(which would result in unpredictable tween durations since JavaScript's timers are not particularly accurate).
|
||||||
Accordingly, we ensure that percentComplete does not exceed 1. */
|
Accordingly, we ensure that percentComplete does not exceed 1. */
|
||||||
var percentComplete;
|
|
||||||
if (opts.percentComplete !== undefined) {
|
|
||||||
percentComplete = opts.percentComplete;
|
|
||||||
} else {
|
|
||||||
percentComplete = Math.min((timeCurrent - timeStart) / opts.duration, 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 every call, iterate through each of the elements in its set. */
|
||||||
for (var j = 0, callLength = call.length; j < callLength; j++) {
|
for (var j = 0, jj = call.length; j < jj; j++) {
|
||||||
var tweensContainer = call[j],
|
var tweensContainer = call[j];
|
||||||
element = tweensContainer.element;
|
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
|
/* 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. */
|
continued existence of its data cache. If it's gone, skip animating this element. */
|
||||||
if (!Collide.data(element)) {
|
if (!eleData) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +116,6 @@ function tick(timestamp) {
|
|||||||
(Otherwise, display's 'none' value is set in completeCall() once the animation has completed.) */
|
(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 !== undefined && opts.display !== null && opts.display !== 'none') {
|
||||||
if (opts.display === 'flex') {
|
if (opts.display === 'flex') {
|
||||||
var flexValues = [ '-webkit-box', '-moz-box', '-ms-flexbox', '-webkit-flex' ];
|
|
||||||
|
|
||||||
for (var f = 0; f < flexValues.length; f++) {
|
for (var f = 0; f < flexValues.length; f++) {
|
||||||
CSS.setPropertyValue(element, 'display', flexValues[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. */
|
/* Note: In addition to property tween data, tweensContainer contains a reference to its associated element. */
|
||||||
if (property !== 'element') {
|
if (property !== 'element') {
|
||||||
var tween = tweensContainer[property],
|
var tween = tweensContainer[property];
|
||||||
currentValue,
|
|
||||||
|
var currentValue;
|
||||||
|
|
||||||
/* Easing can either be a pre-genereated function or a string that references a pre-registered easing
|
/* 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*. */
|
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 easing = (typeof tween.easing === 'string' ? Collide.Easings[tween.easing] : tween.easing);
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
Current Value Calculation
|
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. */
|
subsequently chained animations using the same hookRoot but a different hook can use this cached rootPropertyValue. */
|
||||||
if (CSS.Hooks.registered[property]) {
|
if (CSS.Hooks.registered[property]) {
|
||||||
var hookRoot = CSS.Hooks.getRoot(property),
|
var hookRoot = CSS.Hooks.getRoot(property),
|
||||||
rootPropertyValueCache = Collide.data(element).rootPropertyValueCache[hookRoot];
|
rootPropertyValueCache = eleData.rootPropertyValueCache[hookRoot];
|
||||||
|
|
||||||
if (rootPropertyValueCache) {
|
if (rootPropertyValueCache) {
|
||||||
tween.rootPropertyValue = rootPropertyValueCache;
|
tween.rootPropertyValue = rootPropertyValueCache;
|
||||||
@ -214,9 +217,9 @@ function tick(timestamp) {
|
|||||||
if (CSS.Hooks.registered[property]) {
|
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. ?? */
|
/* 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]) {
|
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 {
|
} else {
|
||||||
Collide.data(element).rootPropertyValueCache[hookRoot] = adjustedSetData[1];
|
eleData.rootPropertyValueCache[hookRoot] = adjustedSetData[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +242,7 @@ function tick(timestamp) {
|
|||||||
CSS.flushTransformCache(element);
|
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.
|
/* 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>
|
</head>
|
||||||
<body>
|
<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="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>
|
<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 {Component, Decorator, View as NgView, NgElement, bootstrap} from 'angular2/angular2';
|
||||||
import {Animation} from 'ionic/ionic';
|
import {Animation} from 'ionic/ionic';
|
||||||
|
|
||||||
|
let opacity = 0.2;
|
||||||
|
let rotateZ = '180deg';
|
||||||
|
let translateX = '100px';
|
||||||
|
let scale = 0.6;
|
||||||
|
|
||||||
@Component({ selector: '[ion-app]' })
|
@Component({ selector: '[ion-app]' })
|
||||||
@NgView({
|
@NgView({
|
||||||
@ -10,21 +13,22 @@ import {Animation} from 'ionic/ionic';
|
|||||||
class IonicApp {
|
class IonicApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fadeOut() {
|
fadeOut() {
|
||||||
|
console.debug('fadeOut');
|
||||||
this.animation = new Animation();
|
this.animation = new Animation();
|
||||||
this.animation.elements( document.querySelectorAll('.square') );
|
this.animation.elements( document.querySelectorAll('.square') );
|
||||||
|
|
||||||
this.animation.duration(2000);
|
this.animation.duration(1000);
|
||||||
this.animation.easing('swing');
|
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();
|
let q = this.animation.start();
|
||||||
|
|
||||||
@ -34,17 +38,18 @@ class IonicApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fadeIn() {
|
fadeIn() {
|
||||||
|
console.debug('fadeIn');
|
||||||
this.animation = new Animation();
|
this.animation = new Animation();
|
||||||
this.animation.elements( document.querySelectorAll('.square') );
|
this.animation.elements( document.querySelectorAll('.square') );
|
||||||
|
|
||||||
this.animation.duration(2000);
|
this.animation.duration(1000);
|
||||||
this.animation.easing('swing');
|
this.animation.easing('linear');
|
||||||
|
|
||||||
this.animation.property('opacity', 1);
|
this.animation.property('opacity', 1);
|
||||||
this.animation.property('translateX', '0px');
|
this.animation.property('translateX', 0);
|
||||||
this.animation.property('translateY', '0px');
|
this.animation.property('translateY', 0);
|
||||||
this.animation.property('rotateZ', '0deg');
|
this.animation.property('rotateZ', 0);
|
||||||
this.animation.property('scale', '1');
|
this.animation.property('scale', 1);
|
||||||
|
|
||||||
let q = this.animation.start();
|
let q = this.animation.start();
|
||||||
|
|
||||||
@ -58,26 +63,22 @@ class IonicApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
percent(ev) {
|
percent(ev) {
|
||||||
let ratio = parseFloat(ev.srcElement.value) / 100;
|
let percentComplete = parseFloat(ev.srcElement.value) / 100;
|
||||||
console.log('percent ratio', ratio);
|
|
||||||
|
|
||||||
this.animation = new Animation();
|
if (!this.percentAnimation) {
|
||||||
this.animation.elements( document.querySelectorAll('.square') );
|
this.percentAnimation = new Animation();
|
||||||
|
this.percentAnimation.elements( document.querySelectorAll('.square') );
|
||||||
|
|
||||||
this.animation.duration(2000);
|
this.percentAnimation.property('opacity', opacity);
|
||||||
this.animation.easing('swing');
|
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.percentAnimation.ready();
|
||||||
this.animation.property('translateX', '100px');
|
|
||||||
this.animation.property('translateY', '100px');
|
|
||||||
this.animation.property('rotateZ', '180deg');
|
|
||||||
this.animation.property('scale', '0.5');
|
|
||||||
|
|
||||||
this.animation.percent(ratio);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
this.percentAnimation.percent(percentComplete);
|
||||||
this.animation.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
velocityStart() {
|
velocityStart() {
|
||||||
|
@ -50,7 +50,7 @@ export class Tab extends NavControllerBase {
|
|||||||
this.config = Tab.config.invoke(this);
|
this.config = Tab.config.invoke(this);
|
||||||
this.setHidden = setHidden
|
this.setHidden = setHidden
|
||||||
|
|
||||||
this.tabId = util.uid()
|
this.tabId = util.nextUid()
|
||||||
setId('tab-content-' + this.tabId)
|
setId('tab-content-' + this.tabId)
|
||||||
setLabelby('tab-item-' + this.tabId)
|
setLabelby('tab-item-' + this.tabId)
|
||||||
setRole('tabpanel')
|
setRole('tabpanel')
|
||||||
|
@ -4,16 +4,33 @@ export function clamp(min, n, max) {
|
|||||||
return Math.max(min, Math.min(n, max));
|
return Math.max(min, Math.min(n, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extend(dest) {
|
export function extend(dst) {
|
||||||
for (var i = 1, ii = arguments.length; i < ii; i++) {
|
return baseExtend(dst, [].slice.call(arguments, 1), false);
|
||||||
var source = arguments[i] || {};
|
}
|
||||||
for (var key in source) {
|
|
||||||
if (source.hasOwnProperty(key)) {
|
export function merge(dst) {
|
||||||
dest[key] = source[key];
|
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) {
|
export function defaults(dest) {
|
||||||
@ -41,9 +58,9 @@ export function pascalCaseToDashCase(str = '') {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let _uid = 0
|
let uid = 0
|
||||||
export function uid() {
|
export function nextUid() {
|
||||||
return _uid++
|
return ++uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Log {
|
export class Log {
|
||||||
|
Reference in New Issue
Block a user