child animations init

This commit is contained in:
Adam Bradley
2015-04-28 11:59:38 -05:00
parent 19c16e7433
commit 08a5fd9fad
3 changed files with 219 additions and 106 deletions

View File

@@ -10,11 +10,20 @@ const data = Collide.data;
export class Animation {
constructor() {
this.parent = null;
this._elements = null;
this._options = {};
this._properties = {};
this._resolve = null;
this._call = null;
this.children = [];
}
addChild(animation) {
animation.parent = this;
this.children.push(animation);
return this;
}
elements(ele) {
@@ -23,6 +32,7 @@ export class Animation {
} else {
this._elements = !ele.length ? [ele] : ele;
}
return this;
}
_setupElements(clearCache, onNextFrame) {
@@ -36,89 +46,108 @@ export class Animation {
this.stop();
}
this._promise = new Promise(res => {
this._resolve = res;
});
if (this._elements && this._elements.length) {
this._promise = new Promise(res => {
this._resolve = res;
});
this._call = null;
this._call = null;
// in the next frame, do all the DOM GETs to load element info
this._nextAF = dom.raf(() => {
/**********************************
Animation Call-Wide Variables
**********************************/
// 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
};
/* 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._call = [];
this._options = util.extend({}, Collide.defaults, this._options);
var opts = util.extend({}, Collide.defaults);
// get the elements ready
for (var i = 0, ii = this._elements.length; i < ii; i++) {
processElement('start', this, i, clearCache);
}
if (this.parent && this.parent._options) {
opts = util.extend(opts, this.parent._options);
}
onNextFrame();
});
this._options = util.extend(opts, this._options);
// get the elements ready
for (var i = 0, ii = this._elements.length; i < ii; i++) {
processElement('start', this, i, clearCache);
}
onNextFrame();
});
} else {
this._promise = Promise.resolve();
}
}
_queueAnimation() {
/* Switch on the element's animating flag. */
if (this._call === null) return;
if (this._elements) {
if (this._call === null) return;
var eleData;
for (var i = 0, ii = this._elements.length, element; i < ii && (element = this._elements[i]); i++) {
eleData = data(element);
if (eleData) {
eleData.isAnimating = true;
var eleData;
for (var i = 0, ii = this._elements.length, element; i < ii && (element = this._elements[i]); i++) {
eleData = data(element);
if (eleData) {
eleData.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);
}
}
/*********************
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 ]);
}
/* 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();
}
start() {
var promises = [];
for (var i = 0; i < this.children.length; i++) {
promises.push(
this.children[i].start()
);
}
var clearCache = (this._aniType !== 'start');
this._setupElements(clearCache, () => {
@@ -126,38 +155,54 @@ export class Animation {
this._queueAnimation();
});
return this._promise;
promises.push(this._promise);
return Promise.all(promises);
}
ready() {
var promises = [];
for (var i = 0; i < this.children.length; i++) {
promises.push(
this.children[i].ready()
);
}
var clearCache = (this._aniType !== 'percent');
this._setupElements(clearCache, () => {
this._aniType = 'percent';
});
return this._promise;
promises.push(this._promise);
return Promise.all(promises);
}
percent(percentComplete) {
// go to and stop at a specific point in the animation
if (this._aniType = 'percent') {
this._options.percentComplete = percentComplete;
this._queueAnimation();
for (var i = 0; i < this.children.length; i++) {
this.children[i].percent(percentComplete);
}
startTick();
this._queueAnimation();
}
}
stop() {
// immediately stop where it's at
animationStop(this._elements, 'stop');
return this;
}
finish() {
// immediately go to the end of the animation
animationStop(this._elements, 'finish');
return this;
}
isAnimating() {
@@ -179,48 +224,57 @@ export class Animation {
************/
options(val) {
this._options = val || {};
return this;
}
option(key, val) {
this._options[key] = val;
return this;
}
removeOption(key) {
delete this._options[key];
return this;
}
duration(val) {
this._options.duration = val;
return this;
}
easing(val) {
this._options.easing = val;
return this;
}
/**************************
/***************
Properties
**************************/
***************/
properties(val) {
this._properties = val || {};
return this;
}
property(key, val) {
this._properties[key] = val;
return this;
}
removeProperty(key) {
delete this._properties[key];
return this;
}
/**************************
/*********
Misc
**************************/
*********/
debug(val) {
Collide.debug = !!val;
return this;
}
}

View File

@@ -4,7 +4,7 @@
</head>
<body>
<div style="position: absolute; top: 300px; left: 0px;">
<div style="position: absolute; top: 300px; left: 50px;">
<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>
@@ -12,20 +12,27 @@
</div>
<div style="position: absolute; top: 400px; left: 50px;">
<div class="yellow square2" style="position:absolute; width:100px; height:100px; background:yellow; top: 0; left: 0;"></div>
<div class="purple square2" style="position:absolute; width:100px; height:100px; background:purple; top: 0; left: 100px;"></div>
<div class="maroon square2" style="position:absolute; width:100px; height:100px; background:maroon; top: 0; left: 200px;"></div>
</div>
<p>
<input type="range" (input)="percent($event)" value="0" min="0" max="100" style="width:200px">
</p>
<p>
<button class="button button-primary" (click)="fadeOut($event)">Fade Out</button>
<button class="button button-primary" (click)="fadeIn($event)">Fade In</button>
<button class="button button-primary" (click)="stop($event)">Stop</button>
<button class="button button-primary" (click)="fadeOut($event)">Out</button>
<button class="button button-primary" (click)="fadeIn($event)">In</button>
</p>
<p>
<!-- <p>
<button class="button button-primary" (click)="velocityStart($event)">Velocity Start</button>
</p>
</p> -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.js"></script>

View File

@@ -11,26 +11,42 @@ let scale = 0.6;
templateUrl: 'main.html'
})
class IonicApp {
constructor() {
}
fadeOut() {
console.debug('fadeOut');
this.animation = new Animation();
this.animation.elements( document.querySelectorAll('.square') );
this.animation.duration(1000);
this.animation.easing('linear');
var animation = new Animation();
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);
animation.duration(1000);
animation.easing('linear');
let q = this.animation.start();
var row1 = new Animation();
row1.elements( document.querySelectorAll('.square') );
row1.property('opacity', opacity)
.property('translateX', translateX)
.property('translateY', translateX)
.property('rotateZ', rotateZ)
.property('scale', scale);
animation.addChild(row1);
var row2 = new Animation();
row2.elements( document.querySelectorAll('.square2') );
row2.property('opacity', opacity);
row2.property('translateX', '-100px');
row2.property('translateY', '-100px');
row2.property('rotateZ', '-180deg');
row2.property('scale', 0.4);
animation.addChild(row2);
let q = animation.start();
q.then(()=> {
console.log('fade out complete')
@@ -39,19 +55,38 @@ class IonicApp {
fadeIn() {
console.debug('fadeIn');
this.animation = new Animation();
this.animation.elements( document.querySelectorAll('.square') );
this.animation.duration(1000);
this.animation.easing('linear');
var animation = new Animation();
animation.elements();
this.animation.property('opacity', 1);
this.animation.property('translateX', 0);
this.animation.property('translateY', 0);
this.animation.property('rotateZ', 0);
this.animation.property('scale', 1);
animation.duration(1000);
animation.easing('linear');
let q = this.animation.start();
var row1 = new Animation();
row1.elements( document.querySelectorAll('.square') );
row1.property('opacity', 1);
row1.property('translateX', 0);
row1.property('translateY', 0);
row1.property('rotateZ', 0);
row1.property('scale', 1);
animation.addChild(row1);
var row2 = new Animation();
row2.elements( document.querySelectorAll('.square2') );
row2.property('opacity', 1);
row2.property('translateX', 0);
row2.property('translateY', 0);
row2.property('rotateZ', 0);
row2.property('scale', 1);
animation.addChild(row2);
let q = animation.start();
q.then(()=> {
console.log('fade in complete')
@@ -67,13 +102,30 @@ class IonicApp {
if (!this.percentAnimation) {
this.percentAnimation = new Animation();
this.percentAnimation.elements( document.querySelectorAll('.square') );
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);
var row1 = new Animation();
row1.elements( document.querySelectorAll('.square') );
row1.property('opacity', 1);
row1.property('translateX', 0);
row1.property('translateY', 0);
row1.property('rotateZ', 0);
row1.property('scale', 1);
this.percentAnimation.addChild(row1);
var row2 = new Animation();
row2.elements( document.querySelectorAll('.square2') );
row2.property('opacity', 1);
row2.property('translateX', 0);
row2.property('translateY', 0);
row2.property('rotateZ', 0);
row2.property('scale', 1);
this.percentAnimation.addChild(row2);
this.percentAnimation.ready();
}