From ce021e521f580caca6580fbf56caca5b79b555ca Mon Sep 17 00:00:00 2001 From: Donal Linehan Date: Thu, 4 Jul 2024 18:27:48 +0100 Subject: [PATCH] Add animation queue --- README.md | 53 +++++++++++++++++++++++++++ src/__tests__/queue.ts | 81 ++++++++++++++++++++++++++++++++++++++++++ src/queue.ts | 51 ++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/__tests__/queue.ts create mode 100644 src/queue.ts diff --git a/README.md b/README.md index 7d004b8..64bdd54 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,40 @@ parallelSequence parallelSequence.start(); ``` +### Queue of Animations + +```javascript +import { Animate, Queue, Easing } from 'nimate'; + +// Create individual animations +const animate1 = new Animate({ + from: { x: 0, y: 0 }, + to: { x: 100, y: 50 }, + duration: 1000, + easing: Easing.easeInOutQuad, +}); + +const animate2 = new Animate({ + from: { x: 100, y: 50 }, + to: { x: 200, y: 100 }, + duration: 1000, + easing: Easing.easeInOutQuad, +}); + +// Create a queue and add animations +const queue = new Queue(); +queue.add(animate1); +queue.add(animate2); + +// Attach event listeners +queue + .on('start', (animation) => console.log('Queue Animation Start', animation)) + .on('update', (value, animation) => console.log('Queue Animation Update:', value, animation)) + .on('complete', (animation) => console.log('Queue Animation Complete', animation)) + .on('stop', (animation) => console.log('Queue Animation Stop', animation)) + .on('complete', () => console.log('All animations in the queue are complete')); +``` + ## 📚 API ### `Animate` @@ -167,3 +201,22 @@ Creates a sequence of animations. - `update`: Emitted on each update with the current value. - `complete`: Emitted when the sequence completes. - `stop`: Emitted when the sequence is stopped. + +### `Queue` + +Creates a queue of animations that are executed sequentially. + +#### Methods + +- `add(animation: Animate)`: Adds an `Animate` instance to the queue. +- `clear()`: Clears the queue and stops any currently running animation. +- `stop()`: Stops the currently running animation without clearing the queue. + +#### Events + +- `start`: Emitted when an animation in the queue starts. +- `update`: Emitted on each update with the current value and animation. +- `complete`: Emitted when an animation in the queue completes. +- `stop`: Emitted when an animation in the queue is stopped. +- `complete`: Emitted when all animations in the queue are complete. +``` diff --git a/src/__tests__/queue.ts b/src/__tests__/queue.ts new file mode 100644 index 0000000..ceb7f74 --- /dev/null +++ b/src/__tests__/queue.ts @@ -0,0 +1,81 @@ +import { Animate } from '../animate'; +import { Queue } from '../queue'; +import { easing as e } from '../easing'; + +describe('Queue', () => { + it('should add animations to the queue and start the first one immediately', done => { + const animate1 = new Animate({ + from: 0, + to: 100, + duration: 50, + easing: e.linear, + }); + + const animate2 = new Animate({ + from: 0, + to: 100, + duration: 50, + easing: e.linear, + }); + + const queue = new Queue(); + + queue.add(animate1); + queue.add(animate2); + + let completeCount = 0; + + queue.on('complete', () => { + completeCount++; + if (completeCount === 2) { + expect(completeCount).toBe(2); + done(); + } + }); + }); + + it('should handle stop correctly', done => { + const animate1 = new Animate({ + from: 0, + to: 100, + duration: 50, + easing: e.linear, + }); + + animate1.on('stop', () => { + done(); + }); + + const queue = new Queue(); + + queue.add(animate1); + + queue.stop(); + }); + + it('should clear the queue and stop the current animation', done => { + const animate1 = new Animate({ + from: 0, + to: 100, + duration: 100, + easing: e.linear, + }); + + const animate2 = new Animate({ + from: 0, + to: 100, + duration: 100, + easing: e.linear, + }); + + const queue = new Queue(); + + queue.add(animate1); + queue.add(animate2); + + queue.clear(); + + expect(queue['animations'].length).toBe(0); + done(); + }); +}); diff --git a/src/queue.ts b/src/queue.ts new file mode 100644 index 0000000..a26cb22 --- /dev/null +++ b/src/queue.ts @@ -0,0 +1,51 @@ +import EventEmitter from 'eventemitter3'; +import { Animate } from './animate'; + +export class Queue extends EventEmitter { + private animations: Animate[] = []; + + constructor() { + super(); + } + + public add(animation: Animate) { + this.animations.push(animation); + animation.on('start', () => this.emit('start', animation)); + animation.on('update', (value: any) => this.emit('update', value, animation)); + animation.on('complete', () => this.onAnimationComplete(animation)); + animation.on('stop', () => this.emit('stop', animation)); + + // If this is the first animation added and no other animation is running, start it immediately + if (this.animations.length === 1) { + this.startNextAnimation(); + } + } + + private startNextAnimation() { + if (this.animations.length > 0) { + const animation = this.animations[0]; + animation.start(); + } else { + this.emit('complete'); // Emit complete event when all animations in the queue have completed + } + } + + private onAnimationComplete(animation: Animate) { + this.emit('complete', animation); + this.animations.shift(); // Remove the completed animation from the queue + this.startNextAnimation(); // Start the next animation in the queue + } + + public clear() { + if (this.animations.length > 0) { + this.animations[0].stop(); + } + this.animations = []; + } + + public stop() { + if (this.animations.length > 0) { + this.animations[0].stop(); + } + } +}