avocado-old/packages/timing/transition/result.js
2019-04-28 23:45:03 -05:00

117 lines
3.0 KiB
JavaScript

import {compose, EventEmitter} from '@avocado/core';
import easingFunctions from './easing';
const decorate = compose(
EventEmitter,
);
export default class TransitionResult extends decorate(class {}) {
constructor(subject, props, duration, easing) {
super();
// Speed might not get passed. If it doesn't, default to 100
// milliseconds.
this.duration = parseFloat(duration || .1);
this.elapsed = 0;
this._isEmittingProgress = false;
this.props = props;
this.subject = subject;
if ('function' === typeof easing) {
this.easing = easing;
}
// If easing isn't passed in as a function, attempt to look it up
// as a string key into Transition.easing. If that fails, then
// default to 'easeOutQuad'.
else {
this.easing = easingFunctions[easing] || easingFunctions['easeOutQuad'];
}
this.original = {};
this.change = {};
for (const i in this.props) {
const value = this.subject[i];
this.original[i] = value;
this.change[i] = this.props[i] - value;
}
// Set up the transition object.
this.promise = new Promise((resolve, reject) => {
this.once('stopped', () => resolve());
});
}
get isEmittingProgress() {
return this._isEmittingProgress;
}
set isEmittingProgress(isEmittingProgress) {
this._isEmittingProgress = isEmittingProgress;
}
// Immediately finish the transition. This will leave the object
// in the fully transitioned state.
skipTransition() {
// Just trick it into thinking the time passed and do one last
// tick.
this.elapsed = this.duration;
this.tick(0);
}
// Immediately stop the transition. This will leave the object in
// its current state; potentially partially transitioned.
stopTransition() {
// Let any listeners know that the transition is complete.
if (this._isEmittingProgress) {
this.emit('progress', [this.elapsed, this.duration]);
}
this.emit('stopped');
}
// Tick callback. Called repeatedly while this transition is
// running.
tick(elapsed) {
// Update the transition's elapsed time.
this.elapsed += elapsed;
// If we've overshot the duration, we'll fix it up here, so
// things never transition too far (through the end point).
if (this.elapsed >= this.duration) {
this.elapsed = this.duration;
for (const i in this.change) {
if (this.change[i]) {
this.subject[i] = this.props[i];
}
}
}
else {
// Do easing for each property that actually changed.
for (const i in this.change) {
if (this.change[i]) {
this.subject[i] = this.easing(
this.elapsed,
this.original[i],
this.change[i],
this.duration
);
}
}
}
// Stop if we're done.
if (this.elapsed === this.duration) {
this.stopTransition();
}
else {
if (this._isEmittingProgress) {
this.emit('progress', [this.elapsed, this.duration]);
}
}
}
}