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]); } } } }