diff --git a/dist/tween.amd.js b/dist/tween.amd.js index ee33f1dd..85ceb1ea 100644 --- a/dist/tween.amd.js +++ b/dist/tween.amd.js @@ -302,6 +302,19 @@ define(['exports'], (function (exports) { 'use strict'; tweenIds = Object.keys(this._tweensAddedDuringUpdate); } }; + Group.prototype.onComplete = function (callback) { + var group = this.getAll(); + group.forEach(function (tween) { + var prevCallback = tween.getCompleteCallback(); + tween.onComplete(function () { + prevCallback === null || prevCallback === void 0 ? void 0 : prevCallback(tween); + // After the onComplete callback completes, _isPlaying is updated to false, so if the total number of completed tweens is -1, then they are all complete. + var completedGroup = group.filter(function (tween) { return !tween.isPlaying(); }); + if (completedGroup.length === group.length - 1) + callback(group); + }); + }); + }; return Group; }()); @@ -448,6 +461,9 @@ define(['exports'], (function (exports) { 'use strict'; Tween.prototype.getId = function () { return this._id; }; + Tween.prototype.getCompleteCallback = function () { + return this._onCompleteCallback; + }; Tween.prototype.isPlaying = function () { return this._isPlaying; }; diff --git a/dist/tween.cjs b/dist/tween.cjs index bcbd0bef..924fcea8 100644 --- a/dist/tween.cjs +++ b/dist/tween.cjs @@ -304,6 +304,19 @@ var Group = /** @class */ (function () { tweenIds = Object.keys(this._tweensAddedDuringUpdate); } }; + Group.prototype.onComplete = function (callback) { + var group = this.getAll(); + group.forEach(function (tween) { + var prevCallback = tween.getCompleteCallback(); + tween.onComplete(function () { + prevCallback === null || prevCallback === void 0 ? void 0 : prevCallback(tween); + // After the onComplete callback completes, _isPlaying is updated to false, so if the total number of completed tweens is -1, then they are all complete. + var completedGroup = group.filter(function (tween) { return !tween.isPlaying(); }); + if (completedGroup.length === group.length - 1) + callback(group); + }); + }); + }; return Group; }()); @@ -450,6 +463,9 @@ var Tween = /** @class */ (function () { Tween.prototype.getId = function () { return this._id; }; + Tween.prototype.getCompleteCallback = function () { + return this._onCompleteCallback; + }; Tween.prototype.isPlaying = function () { return this._isPlaying; }; diff --git a/dist/tween.d.ts b/dist/tween.d.ts index d1c2d202..36f7c930 100644 --- a/dist/tween.d.ts +++ b/dist/tween.d.ts @@ -98,6 +98,7 @@ declare class Tween { */ constructor(object: T, group: true); getId(): number; + getCompleteCallback(): ((object: T) => void) | undefined; isPlaying(): boolean; isPaused(): boolean; getDuration(): number; @@ -181,6 +182,7 @@ declare class Group { * tweens, and do not rely on tweens being automatically added or removed. */ update(time?: number, preserve?: boolean): void; + onComplete(callback: (object: Tween[]) => void): void; } declare const now: () => number; diff --git a/dist/tween.esm.js b/dist/tween.esm.js index 8daaffca..709871d1 100644 --- a/dist/tween.esm.js +++ b/dist/tween.esm.js @@ -300,6 +300,19 @@ var Group = /** @class */ (function () { tweenIds = Object.keys(this._tweensAddedDuringUpdate); } }; + Group.prototype.onComplete = function (callback) { + var group = this.getAll(); + group.forEach(function (tween) { + var prevCallback = tween.getCompleteCallback(); + tween.onComplete(function () { + prevCallback === null || prevCallback === void 0 ? void 0 : prevCallback(tween); + // After the onComplete callback completes, _isPlaying is updated to false, so if the total number of completed tweens is -1, then they are all complete. + var completedGroup = group.filter(function (tween) { return !tween.isPlaying(); }); + if (completedGroup.length === group.length - 1) + callback(group); + }); + }); + }; return Group; }()); @@ -446,6 +459,9 @@ var Tween = /** @class */ (function () { Tween.prototype.getId = function () { return this._id; }; + Tween.prototype.getCompleteCallback = function () { + return this._onCompleteCallback; + }; Tween.prototype.isPlaying = function () { return this._isPlaying; }; diff --git a/dist/tween.umd.js b/dist/tween.umd.js index dd511ca8..50f3ae3b 100644 --- a/dist/tween.umd.js +++ b/dist/tween.umd.js @@ -306,6 +306,19 @@ tweenIds = Object.keys(this._tweensAddedDuringUpdate); } }; + Group.prototype.onComplete = function (callback) { + var group = this.getAll(); + group.forEach(function (tween) { + var prevCallback = tween.getCompleteCallback(); + tween.onComplete(function () { + prevCallback === null || prevCallback === void 0 ? void 0 : prevCallback(tween); + // After the onComplete callback completes, _isPlaying is updated to false, so if the total number of completed tweens is -1, then they are all complete. + var completedGroup = group.filter(function (tween) { return !tween.isPlaying(); }); + if (completedGroup.length === group.length - 1) + callback(group); + }); + }); + }; return Group; }()); @@ -452,6 +465,9 @@ Tween.prototype.getId = function () { return this._id; }; + Tween.prototype.getCompleteCallback = function () { + return this._onCompleteCallback; + }; Tween.prototype.isPlaying = function () { return this._isPlaying; }; diff --git a/src/Group.ts b/src/Group.ts index 1fbae2a7..3b503f65 100644 --- a/src/Group.ts +++ b/src/Group.ts @@ -84,4 +84,16 @@ export default class Group { tweenIds = Object.keys(this._tweensAddedDuringUpdate) } } + onComplete(callback: (object: Tween[]) => void) { + const group = this.getAll() + group.forEach(tween => { + const prevCallback = tween.getCompleteCallback() + tween.onComplete(() => { + prevCallback?.(tween) + // After the onComplete callback completes, _isPlaying is updated to false, so if the total number of completed tweens is -1, then they are all complete. + const completedGroup = group.filter(tween => !tween.isPlaying()) + if (completedGroup.length === group.length - 1) callback(group) + }) + }) + } } diff --git a/src/Tween.ts b/src/Tween.ts index fed7745e..4b536ac0 100644 --- a/src/Tween.ts +++ b/src/Tween.ts @@ -83,6 +83,10 @@ export class Tween { return this._id } + getCompleteCallback(): ((object: T) => void) | undefined { + return this._onCompleteCallback + } + isPlaying(): boolean { return this._isPlaying } diff --git a/src/tests.ts b/src/tests.ts index 43d0202e..6cf1324f 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -2060,6 +2060,70 @@ export const tests = { test.ok(group.getAll() instanceof Array) test.done() }, + 'Custom group.onComplete() should be triggered when all Tweens in the group have reached their completion, and the child Tween.onComplete() should also be fired'( + test: Test, + ): void { + TWEEN.removeAll() + + const t = new TWEEN.Tween({x: 1}), + t2 = new TWEEN.Tween({x: 1}), + t3 = new TWEEN.Tween({x: 1}), + group = new TWEEN.Group() + let groupCounter = 0, + childCounter = 0, + childCounter2 = 0, + childCounter3 = 0 + + group.add(t) + group.add(t2) + group.add(t3) + + t.to({x: 2}, 1000) + t2.to({x: 2}, 2000) + t3.to({x: 2}, 3000) + + t.onComplete(function (): void { + childCounter++ + }) + t2.onComplete(function (): void { + childCounter2++ + }) + t3.onComplete(function (): void { + childCounter3++ + }) + group.onComplete(function (): void { + groupCounter++ + }) + + t.start(0) + t2.start(0) + t3.start(0) + + group.update(0) + test.deepEqual(groupCounter, 0) + test.deepEqual(childCounter, 0) + test.deepEqual(childCounter2, 0) + test.deepEqual(childCounter3, 0) + + group.update(1000) + test.deepEqual(groupCounter, 0) + test.deepEqual(childCounter, 1) + test.deepEqual(childCounter2, 0) + test.deepEqual(childCounter3, 0) + + group.update(2000) + test.deepEqual(childCounter, 1) + test.deepEqual(groupCounter, 0) + test.deepEqual(childCounter2, 1) + test.deepEqual(childCounter3, 0) + + group.update(3000) + test.deepEqual(groupCounter, 1) + test.deepEqual(childCounter, 1) + test.deepEqual(childCounter2, 1) + test.deepEqual(childCounter3, 1) + test.done() + }, 'Custom group stores tweens instead of global TWEEN group'(test: Test): void { const group = new TWEEN.Group()