Skip to content

Commit

Permalink
Merge branch 'main' into fix-yoyo-wrong-by-calculateElapsedPortion
Browse files Browse the repository at this point in the history
* main:
  code formatting
  update tests.yml: use npm ci instead of npm i for reproducible builds
  Update tests.yml: update setup-node action version
  Update tests.yml to use the latest LTS version of Node.js
  #697: Added a section in the user-guide regarding the new "setNow" functionality.
  #697: Added the ability to override the internal "now" function using the "setNow" function.
  fix: Fixed error when registered tweens are not completed in order
  fix: Fixed error when registered tweens are not completed in order
  test: add test tween unit
  feature: implement group-level onComplete callback, triggering both group and individual tween completion callbacks
  • Loading branch information
trusktr committed Jan 11, 2025
2 parents a1e04c4 + 20079e6 commit 6be3b9d
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 15 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: build and tests
name: build and test

on: [push]

jobs:
build:
build-and-test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [lts/*]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm clean-install
- run: npm test
26 changes: 25 additions & 1 deletion dist/tween.amd.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,13 @@ define(['exports'], (function (exports) { 'use strict';
},
});

var now = function () { return performance.now(); };
var _nowFunc = function () { return performance.now(); };
var now = function () {
return _nowFunc();
};
function setNow(nowFunction) {
_nowFunc = nowFunction;
}

/**
* Controlling groups of tweens
Expand Down Expand Up @@ -296,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;
}());

Expand Down Expand Up @@ -442,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;
};
Expand Down Expand Up @@ -1132,6 +1154,7 @@ define(['exports'], (function (exports) { 'use strict';
Group: Group,
Interpolation: Interpolation,
now: now,
setNow: setNow,
Sequence: Sequence,
nextId: nextId,
Tween: Tween,
Expand Down Expand Up @@ -1391,6 +1414,7 @@ define(['exports'], (function (exports) { 'use strict';
exports.now = now;
exports.remove = remove;
exports.removeAll = removeAll;
exports.setNow = setNow;
exports.update = update;

Object.defineProperty(exports, '__esModule', { value: true });
Expand Down
26 changes: 25 additions & 1 deletion dist/tween.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,13 @@ var Easing = Object.freeze({
},
});

var now = function () { return performance.now(); };
var _nowFunc = function () { return performance.now(); };
var now = function () {
return _nowFunc();
};
function setNow(nowFunction) {
_nowFunc = nowFunction;
}

/**
* Controlling groups of tweens
Expand Down Expand Up @@ -298,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;
}());

Expand Down Expand Up @@ -444,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;
};
Expand Down Expand Up @@ -1134,6 +1156,7 @@ var exports$1 = {
Group: Group,
Interpolation: Interpolation,
now: now,
setNow: setNow,
Sequence: Sequence,
nextId: nextId,
Tween: Tween,
Expand Down Expand Up @@ -1393,4 +1416,5 @@ exports.nextId = nextId;
exports.now = now;
exports.remove = remove;
exports.removeAll = removeAll;
exports.setNow = setNow;
exports.update = update;
6 changes: 5 additions & 1 deletion dist/tween.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ declare class Tween<T extends UnknownProps = any> {
*/
constructor(object: T, group: true);
getId(): number;
getCompleteCallback(): ((object: T) => void) | undefined;
isPlaying(): boolean;
isPaused(): boolean;
getDuration(): number;
Expand Down Expand Up @@ -181,9 +182,11 @@ 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;
declare function setNow(nowFunction: Function): void;

/**
* Utils
Expand Down Expand Up @@ -470,6 +473,7 @@ declare const exports: {
};
};
now: () => number;
setNow: typeof setNow;
Sequence: typeof Sequence;
nextId: typeof Sequence.nextId;
Tween: typeof Tween;
Expand Down Expand Up @@ -719,4 +723,4 @@ declare const exports: {
};
};

export { Easing, Group, Interpolation, Sequence, Tween, VERSION, add, exports as default, getAll, nextId, now, remove, removeAll, update };
export { Easing, Group, Interpolation, Sequence, Tween, VERSION, add, exports as default, getAll, nextId, now, remove, removeAll, setNow, update };
27 changes: 25 additions & 2 deletions dist/tween.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,13 @@ var Easing = Object.freeze({
},
});

var now = function () { return performance.now(); };
var _nowFunc = function () { return performance.now(); };
var now = function () {
return _nowFunc();
};
function setNow(nowFunction) {
_nowFunc = nowFunction;
}

/**
* Controlling groups of tweens
Expand Down Expand Up @@ -294,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;
}());

Expand Down Expand Up @@ -440,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;
};
Expand Down Expand Up @@ -1130,6 +1152,7 @@ var exports = {
Group: Group,
Interpolation: Interpolation,
now: now,
setNow: setNow,
Sequence: Sequence,
nextId: nextId,
Tween: Tween,
Expand Down Expand Up @@ -1376,4 +1399,4 @@ var exports = {
update: update,
};

export { Easing, Group, Interpolation, Sequence, Tween, VERSION, add, exports as default, getAll, nextId, now, remove, removeAll, update };
export { Easing, Group, Interpolation, Sequence, Tween, VERSION, add, exports as default, getAll, nextId, now, remove, removeAll, setNow, update };
26 changes: 25 additions & 1 deletion dist/tween.umd.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,13 @@
},
});

var now = function () { return performance.now(); };
var _nowFunc = function () { return performance.now(); };
var now = function () {
return _nowFunc();
};
function setNow(nowFunction) {
_nowFunc = nowFunction;
}

/**
* Controlling groups of tweens
Expand Down Expand Up @@ -300,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;
}());

Expand Down Expand Up @@ -446,6 +465,9 @@
Tween.prototype.getId = function () {
return this._id;
};
Tween.prototype.getCompleteCallback = function () {
return this._onCompleteCallback;
};
Tween.prototype.isPlaying = function () {
return this._isPlaying;
};
Expand Down Expand Up @@ -1136,6 +1158,7 @@
Group: Group,
Interpolation: Interpolation,
now: now,
setNow: setNow,
Sequence: Sequence,
nextId: nextId,
Tween: Tween,
Expand Down Expand Up @@ -1395,6 +1418,7 @@
exports.now = now;
exports.remove = remove;
exports.removeAll = removeAll;
exports.setNow = setNow;
exports.update = update;

Object.defineProperty(exports, '__esModule', { value: true });
Expand Down
6 changes: 6 additions & 0 deletions docs/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,12 @@ Note that the interpolation function is global to all properties that are tweene

Check [06_array_interpolation](../examples/06_array_interpolation.html) for an example.

## Changing the Definition of "Now"

When working with tweening, you inevitably rely on a definition of what "now" is. By default, Tween.js uses performance.now, which is a reliable and precise approach. However, if you need to adjust the flow of time—for instance, to slow it down or manipulate it for a custom purpose—you may encounter discrepancies between your internal definition of "now" and what Tween.js considers "now."

To address this, a new function, setNow, has been introduced. This function allows you to redefine the internal "now" used by Tween.js. You can pass a custom function to setNow, which will replace the default definition. This provides greater flexibility and enables synchronization with your specific requirements for time control.

## Getting the best performance

While Tween.js tries to be performant on its own, nothing prevents you from using it in a way that is counterperformant. Here are some of the ways you can avoid slowing down your projects when using Tween.js (or when animating in the web, in general).
Expand Down
2 changes: 1 addition & 1 deletion scripts/write-version.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fs from 'fs'
import pkg from '../package.json' assert {type: 'json'}
import pkg from '../package.json' with {type: 'json'}

const {version} = pkg

Expand Down
12 changes: 12 additions & 0 deletions src/Group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
}
}
20 changes: 18 additions & 2 deletions src/Index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import Easing from './Easing'
import Group from './Group'
import Interpolation from './Interpolation'
import now from './Now'
import now, {setNow} from './Now'
import Sequence from './Sequence'
import Tween from './Tween'
import VERSION from './Version'
Expand Down Expand Up @@ -273,13 +273,29 @@ const update = TWEEN.update.bind(TWEEN)

// NOTE! Make sure both lists of exports below are kept in sync:

export {Easing, Group, Interpolation, now, Sequence, nextId, Tween, VERSION, getAll, removeAll, add, remove, update}
export {
Easing,
Group,
Interpolation,
now,
setNow,
Sequence,
nextId,
Tween,
VERSION,
getAll,
removeAll,
add,
remove,
update,
}

const exports = {
Easing,
Group,
Interpolation,
now,
setNow,
Sequence,
nextId,
Tween,
Expand Down
10 changes: 9 additions & 1 deletion src/Now.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
const now = (): number => performance.now()
let _nowFunc: Function = () => performance.now()

const now = (): number => {
return _nowFunc()
}

export function setNow(nowFunction: Function) {
_nowFunc = nowFunction
}

export default now
Loading

0 comments on commit 6be3b9d

Please sign in to comment.