From f28f0694f20b1e48ac1650dc2d850cf7b087468b Mon Sep 17 00:00:00 2001 From: Joe Pea Date: Thu, 25 Jul 2024 17:30:02 -0700 Subject: [PATCH] feat: do not automatically add/remove a tween to/from its associated group feat: the `tween.group(group)` method now has a reciprocal `tween.remove()` method that will remove a tween from its associated group, and unassociate the group. `tween.group()` without an arg is no longer valid, see breaking changes and migration below. fix: when a tween is stopped before its end time, do not allow its update method to continue, therefore preventing logic (f.e. repeat logic) from being triggered docs: improved the docs, adding some missing information, removing all examples of the global `TWEEN` group which has been deprecated, and adding docs on how to manage groups of tweens. Also updated samples to use `import` syntax for importing Tween, avoiding the use of the `TWEEN` UMD global variable which has been deprecated. feat: A new `Group.allStopped()` method returns true if all tweens in a group are not playing (i.e. stopped, and not paused), otherwise false. Useful for stopping an animation loop once all tweens in a group have finished their animation. BREAKING: - Tweens are no longer automatically added or removed from groups by default when you call any Tween methods such as `start()`, `stop()`, or `pause()`, and the `preserve` parameter to `Group.update()` now defaults to `true` and is deprecated to be removed in a future major version. - MIGRATION: To keep old behavior for a while, explicitly call `group.update()` with `false` for the second parameter. To migrate forward, do not rely on automatic add/remove of tweens, and instead add/remove tweens to/from groups manually. - `Group.update()` no longer returns a boolean indicating if all tweens have been removed. - MIGRATION: Don't rely on auto-add/remove to/from groups. This boolean return was previously useful for stopping an animation loop once all tweens were finished animating. Instead, use the new `Group.allStopped()` method to check if all tweens in a group are stopped in order to determine whether or not to continue an animation loop. - The second `group` parameter to `Tween.constructor` now defaults to `undefined` instead of the global `TWEEN` group. Additionally it accepts a value of `true` to restore the old default behavior. The `true` value is deprecated and will be removed in a future major version. - MIGRATION: For the time being the parameter can be set to `true` to restore the old behavior. To migrate forward, use `tween.group(group)` or `group.add(tween)` instead. - The argless `tween.group()` signature has been removed. - MIGRATION: Use `group.add(tween)` or `group.remove(tween)` instead. `tween.group(TWEEN)`, `TWEEN.add(tween)`, and `TWEEN.remove(tween)` will also work for now, but they are deprecated and will be removed in a future major version. - `Group.update`'s second parameter `preserve` defaults to `true` now, and is deprecated to be removed in a future major version, at which point tweens of a group will no longer be automatically added/remove to/from a group when calling any Tween methods such as `start()`, `pause()`, or `stop()`. - MIGRATION: For now, explicitly set the parameter to `false` to restore old default behavior when calling `group.update()`. To migrate forward, do not rely on the automatic add/remove behavior, and instead manually add or remove tweens to or from groups. - To make the fix for `tween.update()` to be a no-op for stopped tweens, we had to break an undocumented feature that allowed tweens to move backward in time (https://github.com/tweenjs/tween.js/pull/271). - MIGRATION: To move tweens backward in time after they have already completed, first call `tween.start(startTime)` then proceed to call `tween.update(time)` in reverse order as before (see the unit test with "go backward in time" in its name). Without calling `tween.start()` nothing will happen because stopped/completed tweens will now always return early from `update()`, as they are considered to be no longer running. --- README.md | 294 +++++---- README_zh-CN.md | 12 +- dist/tween.amd.js | 573 ++++++++++++++++-- dist/tween.cjs | 573 ++++++++++++++++-- dist/tween.d.ts | 569 ++++++++++++++++- dist/tween.esm.js | 573 ++++++++++++++++-- dist/tween.umd.js | 573 ++++++++++++++++-- docs/user_guide.md | 195 +++--- docs/user_guide_zh-CN.md | 44 +- examples/00_hello_world.html | 27 +- examples/01_bars.html | 104 ++-- examples/02_black_and_red.html | 85 +-- examples/03_graphs.html | 75 +-- examples/04_simplest.html | 38 +- examples/05_video_and_time.html | 22 +- examples/06_array_interpolation.html | 131 +--- examples/07_dynamic_to.html | 50 +- examples/07a_dynamic_to_two_array_values.html | 122 ++-- .../07b_dynamic_to_an_array_of_values.html | 129 ++-- examples/08_repeat.html | 43 +- examples/09_relative_values.html | 39 +- examples/09_relative_values.js | 29 + examples/10_yoyo.html | 114 +--- examples/10_yoyo.js | 102 ++++ examples/11_stop_all_chained_tweens.html | 29 +- examples/12_graphs_custom_functions.html | 35 +- examples/13_relative_start_time.html | 37 +- examples/14_pause_tween.html | 36 +- examples/15_complex_properties.html | 47 +- examples/16_animate_an_array_of_values.html | 37 +- examples/17_generate_pow.html | 54 +- examples/18_start_from_current_values.html | 39 +- .../plain-javascript-modules/animate.js | 17 +- .../plain-javascript-modules/index.js | 8 +- .../plain-typescript-modules/animate.js | 17 +- .../plain-typescript-modules/animate.ts | 17 +- .../plain-typescript-modules/index.js | 21 +- .../plain-typescript-modules/index.ts | 13 +- .../plain-typescript-modules/tsconfig.json | 3 +- examples/js/createGraph.js | 23 +- examples/js/createPath.js | 101 +++ examples/js/toPhysicalPx.js | 1 + src/Group.ts | 75 ++- src/Index.ts | 471 ++++++++++++++ src/Tween.ts | 76 ++- src/tests.ts | 359 ++++++----- 46 files changed, 4607 insertions(+), 1425 deletions(-) create mode 100644 examples/09_relative_values.js create mode 100644 examples/10_yoyo.js create mode 100644 examples/js/createPath.js create mode 100644 examples/js/toPhysicalPx.js diff --git a/README.md b/README.md index 4c825fd9..c881f761 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,6 @@ More languages: [English](./README.md), [简体中文](./README_zh-CN.md) --- ```html - -
- -``` - -Or from unpkg.com: - -```html - -``` - -Note that unpkg.com supports a semver version in the URL, where the `^` in the URL tells unpkg to give you the latest version 20.x.x. - -## Build and include in your project with script tag - -Currently npm is required to build the project. - -```bash -git clone https://github.com/tweenjs/tween.js -cd tween.js -npm install -npm run build -``` - -This will create some builds in the `dist` directory. There are currently two different builds of the library: - -- UMD : `tween.umd.js` -- ES6 Module : `tween.es.js` - -You are now able to copy tween.umd.js into your project, then include it with -a script tag, which will add TWEEN to the global scope, - -```html - -``` - -or import TWEEN as a JavaScript module, - -```html - -``` - -where `path/to` is replaced with the location where you placed the file. - -## With `npm install` and `import` from `node_modules` - -You can add tween.js as an npm dependency: - -```bash -npm install @tweenjs/tween.js -``` - -### With a build tool - -If you are using [Node.js](https://nodejs.org/), [Parcel](https://parceljs.org/), [Webpack](https://webpack.js.org/), [Rollup](https://rollupjs.org/), [Vite](https://vitejs.dev/), or another build tool, then you can now use the following to include tween.js: - -```javascript -import * as TWEEN from '@tweenjs/tween.js' -``` - -### Without a build tool - -You can import from `node_modules` if you serve node_modules as part of your website, using an `importmap` script tag. First, assuming `node_modules` is at the root of your website, you can write an import map: - -```html - -``` - -Now in any of your module scripts you can import it by its package name: - -```javascript -import * as TWEEN from '@tweenjs/tween.js' -``` - # Features -- Does one thing and one thing only: tween properties +- Does one thing only and does it well: tweens properties of an object - Doesn't take care of CSS units (e.g. appending `px`) - Doesn't interpolate colors - Easing functions are reusable outside of Tween - Can also use custom easing functions - -# Documentation - -- [User guide](./docs/user_guide.md) -- [Contributor guide](./docs/contributor_guide.md) -- [Tutorial](https://web.archive.org/web/20220601192930/http://learningthreejs.com/blog/2011/08/17/tweenjs-for-smooth-animation/) using tween.js with three.js -- Also: [libtween](https://github.com/jsm174/libtween), a port of tween.js to C by [jsm174](https://github.com/jsm174) +- Doesn't make its own animation loop, making it flexible for integration into + any animation loop. # Examples @@ -350,6 +256,184 @@ import * as TWEEN from '@tweenjs/tween.js' +# Installation + +The recommended method is to use `import` syntax. Here we've listed various +install methods starting roughly with the most recommended first and least +desirable last. Evaluate all of the following methods to pick what is most +suitable for your project. + +## With `npm install` and `import` from `node_modules` + +You can add tween.js as an npm dependency: + +```bash +npm install @tweenjs/tween.js +``` + +### Without a build tool + +#### Installed locally + +You can import from `node_modules` if you serve `node_modules` as part of your +website, using a standard `importmap` script tag. First, assuming `node_modules` +is at the root of your website, you can write an import map like so in your HTML +file: + +```html + +``` + +Now in any of your module scripts you can import Tween.js by its package name: + +```html + +``` + +#### Import from CDN + +Note that, without the `importmap`, you can import directly from a CDN as with the first example above, like so: + +```html + +``` + +You can also link your `importmap` to the CDN instead of a local `node_modules` folder, if you prefer that: + +```html + + + +``` + +### With a build tool + +If you are using [Node.js](https://nodejs.org/), +[Parcel](https://parceljs.org/), [Webpack](https://webpack.js.org/), +[Rollup](https://rollupjs.org/), [Vite](https://vitejs.dev/), or another build +tool, then you can install `@tweenjs/tween.js` with `npm install +@tweenjs/tween.js`, and `import` the library into your JavaScript (or +TypeScript) file, and the build tool will know how to find the source code from +`node_modules` without needing to create an `importmap` script: + +```javascript +import * as TWEEN from '@tweenjs/tween.js' +``` + +However, note that this approach requires always running a build tool for your +app to work, while the `importmap` approach will simply work without any build +tools as a simple static HTML site. + +## Manual build + +Another approach is to download the source code with git, manually build the +library, then place the output in your project. Node.js is required for this. + +```bash +git clone https://github.com/tweenjs/tween.js +cd tween.js +npm install +npm run build +``` + +This will create some builds in the `dist` directory. There are currently two different builds of the library: + +- ES6 Module in `/dist/tween.esm.js` (recommended) +- UMD in `/dist/tween.umd.js` (deprecated, will be removed in a future major version) + +You are now able to copy one of those two files into your project, and use like this (recommended): + +```html + +``` + +or (deprecated, to be removed in future major): + +```html + + +``` + +where `path/to` is replaced with the location where you placed the file. + +> [!Note] +> You can also download these files from unpkg, for example here: +> https://unpkg.com/browse/@tweenjs/tween.js@23.1.3/dist/ + +## Global variable from CDN (deprecated) + +> [!Note] +> This method is deprecated and will be removed in a future major version! + +Install a global `TWEEN` variable from a content-delivery network (CDN) using the UMD file. + +From cdnjs: + +```html + +``` + +Or from unpkg.com: + +```html + +``` + +Then use the `TWEEN` variable in any script: + +```html + +``` + +> [!Note] +> unpkg.com supports a semver version in the URL, where the `^` in the +> URL tells unpkg to give you the latest version 20.x.x. + +## CommonJS (deprecated) + +Skip this section if you don't know what CommonJS is! + +> [!Note] +> This method is deprecated and will be removed in a future major version! + +Any of the above methods work in older systems that still use CommonJS. Repeat +any of the above methods but using `dist/tween.cjs` instead of +`dist/tween.esm.js` or `dist/tween.umd.js`. + +# Documentation + +- [User guide](./docs/user_guide.md) +- [Contributor guide](./docs/contributor_guide.md) +- [Tutorial](https://web.archive.org/web/20220601192930/http://learningthreejs.com/blog/2011/08/17/tweenjs-for-smooth-animation/) using tween.js with three.js +- Also: [libtween](https://github.com/jsm174/libtween), a port of tween.js to C by [jsm174](https://github.com/jsm174) + # Tests You need to install `npm` first--this comes with node.js, so install that one first. Then, cd to `tween.js`'s (or wherever you cloned the repo) directory and run: @@ -364,7 +448,11 @@ To run the tests run: npm test ``` -If you want to add any feature or change existing features, you _must_ run the tests to make sure you didn't break anything else. Any pull request (PR) needs to have updated passing tests for feature changes (or new passing tests for new features or fixes) in `src/tests.ts` a PR to be accepted. See [contributing](CONTRIBUTING.md) for more information. +If you want to add any feature or change existing features, you _must_ run the +tests to make sure you didn't break anything else. Any pull request (PR) needs +to have updated passing tests for feature changes (or new passing tests for new +features or fixes) in `src/tests.ts` to be accepted. See +[contributing](CONTRIBUTING.md) for more information. # People diff --git a/README_zh-CN.md b/README_zh-CN.md index 5d1cd077..a2f8d782 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -12,7 +12,7 @@ --- ```html - +
@@ -59,13 +59,13 @@ cdnjs: ```html - + ``` 或者 unpkg.com: ```html - + ``` 请注意,unpkg.com 支持 URL 中的 semver 版本,其中 URL 中的 `^` 告诉 unpkg 为你提供最新版本 20.x.x。 @@ -84,7 +84,7 @@ npm run build 这将在 `dist` 目录中创建一些构建。 目前有两种不同的库版本: - UMD : `tween.umd.js` -- ES6 Module : `tween.es.js` +- ES6 Module : `tween.esm.js` 你现在可以将 tween.umd.js 复制到你的项目中,然后将其包含在一个 script 标签,它将 TWEEN 添加到全局范围, @@ -96,7 +96,7 @@ npm run build ```html ``` @@ -126,7 +126,7 @@ import * as TWEEN from '@tweenjs/tween.js' diff --git a/dist/tween.amd.js b/dist/tween.amd.js index 3fcdafba..6ef77a17 100644 --- a/dist/tween.amd.js +++ b/dist/tween.amd.js @@ -225,33 +225,61 @@ define(['exports'], (function (exports) { 'use strict'; */ var Group = /** @class */ (function () { function Group() { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } this._tweens = {}; this._tweensAddedDuringUpdate = {}; + this.add.apply(this, tweens); } Group.prototype.getAll = function () { var _this = this; - return Object.keys(this._tweens).map(function (tweenId) { - return _this._tweens[tweenId]; - }); + return Object.keys(this._tweens).map(function (tweenId) { return _this._tweens[tweenId]; }); }; Group.prototype.removeAll = function () { this._tweens = {}; }; - Group.prototype.add = function (tween) { - this._tweens[tween.getId()] = tween; - this._tweensAddedDuringUpdate[tween.getId()] = tween; + Group.prototype.add = function () { + var _a; + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _b = 0, tweens_1 = tweens; _b < tweens_1.length; _b++) { + var tween = tweens_1[_b]; + // Remove from any other group first, a tween can only be in one group at a time. + // @ts-expect-error library internal access + (_a = tween._group) === null || _a === void 0 ? void 0 : _a.remove(tween); + // @ts-expect-error library internal access + tween._group = this; + this._tweens[tween.getId()] = tween; + this._tweensAddedDuringUpdate[tween.getId()] = tween; + } + }; + Group.prototype.remove = function () { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _a = 0, tweens_2 = tweens; _a < tweens_2.length; _a++) { + var tween = tweens_2[_a]; + // @ts-expect-error library internal access + tween._group = undefined; + delete this._tweens[tween.getId()]; + delete this._tweensAddedDuringUpdate[tween.getId()]; + } }; - Group.prototype.remove = function (tween) { - delete this._tweens[tween.getId()]; - delete this._tweensAddedDuringUpdate[tween.getId()]; + /** Return true if all tweens in the group are not paused or playing. */ + Group.prototype.allStopped = function () { + return this.getAll().every(function (tween) { return !tween.isPlaying(); }); }; Group.prototype.update = function (time, preserve) { if (time === void 0) { time = now(); } - if (preserve === void 0) { preserve = false; } + if (preserve === void 0) { preserve = true; } var tweenIds = Object.keys(this._tweens); - if (tweenIds.length === 0) { - return false; - } + if (tweenIds.length === 0) + return; // Tweens are updated in "batches". If you add a new tween during an // update, then the new tween will be updated in the next batch. // If you remove a tween during an update, it may or may not be updated. @@ -262,13 +290,11 @@ define(['exports'], (function (exports) { 'use strict'; for (var i = 0; i < tweenIds.length; i++) { var tween = this._tweens[tweenIds[i]]; var autoStart = !preserve; - if (tween && tween.update(time, autoStart) === false && !preserve) { - delete this._tweens[tweenIds[i]]; - } + if (tween && tween.update(time, autoStart) === false && !preserve) + this.remove(tween); } tweenIds = Object.keys(this._tweensAddedDuringUpdate); } - return true; }; return Group; }()); @@ -377,10 +403,7 @@ define(['exports'], (function (exports) { 'use strict'; * Thank you all, you're awesome! */ var Tween = /** @class */ (function () { - function Tween(_object, _group) { - if (_group === void 0) { _group = mainGroup; } - this._object = _object; - this._group = _group; + function Tween(object, group) { this._isPaused = false; this._pauseStart = 0; this._valuesStart = {}; @@ -405,6 +428,16 @@ define(['exports'], (function (exports) { 'use strict'; this._isChainStopped = false; this._propertiesAreSetUp = false; this._goToEnd = false; + this._object = object; + if (typeof group === 'object') { + this._group = group; + group.add(this); + } + // Use "true" to restore old behavior (will be removed in future release). + else if (group === true) { + this._group = mainGroup; + mainGroup.add(this); + } } Tween.prototype.getId = function () { return this._id; @@ -443,8 +476,6 @@ define(['exports'], (function (exports) { 'use strict'; if (this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.add(this); this._repeat = this._initialRepeat; if (this._reversed) { // If we were reversed (f.e. using the yoyo feature) then we need to @@ -561,8 +592,6 @@ define(['exports'], (function (exports) { 'use strict'; if (!this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.remove(this); this._isPlaying = false; this._isPaused = false; if (this._onStopCallback) { @@ -582,8 +611,6 @@ define(['exports'], (function (exports) { 'use strict'; } this._isPaused = true; this._pauseStart = time; - // eslint-disable-next-line - this._group && this._group.remove(this); return this; }; Tween.prototype.resume = function (time) { @@ -594,8 +621,6 @@ define(['exports'], (function (exports) { 'use strict'; this._isPaused = false; this._startTime += time - this._pauseStart; this._pauseStart = 0; - // eslint-disable-next-line - this._group && this._group.add(this); return this; }; Tween.prototype.stopChainedTweens = function () { @@ -605,8 +630,19 @@ define(['exports'], (function (exports) { 'use strict'; return this; }; Tween.prototype.group = function (group) { - if (group === void 0) { group = mainGroup; } - this._group = group; + if (!group) { + console.warn('tween.group() without args has been removed, use group.add(tween) instead.'); + return this; + } + group.add(this); + return this; + }; + /** + * Removes the tween from whichever group it is in. + */ + Tween.prototype.remove = function () { + var _a; + (_a = this._group) === null || _a === void 0 ? void 0 : _a.remove(this); return this; }; Tween.prototype.delay = function (amount) { @@ -685,12 +721,11 @@ define(['exports'], (function (exports) { 'use strict'; if (this._isPaused) return true; var property; - var endTime = this._startTime + this._duration; if (!this._goToEnd && !this._isPlaying) { - if (time > endTime) - return false; if (autoStart) this.start(time, true); + else + return false; } this._goToEnd = false; if (time < this._startTime) { @@ -854,10 +889,245 @@ define(['exports'], (function (exports) { 'use strict'; // Modules and CommonJS, without build hacks, and so as not to break the // existing API. // https://github.com/rollup/rollup/issues/1961#issuecomment-423037881 + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var getAll = TWEEN.getAll.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var removeAll = TWEEN.removeAll.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var add = TWEEN.add.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var remove = TWEEN.remove.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var update = TWEEN.update.bind(TWEEN); var exports$1 = { Easing: Easing, @@ -868,10 +1138,245 @@ define(['exports'], (function (exports) { 'use strict'; nextId: nextId, Tween: Tween, VERSION: VERSION, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ getAll: getAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ removeAll: removeAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ add: add, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ remove: remove, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ update: update, }; diff --git a/dist/tween.cjs b/dist/tween.cjs index 5133e646..7143837e 100644 --- a/dist/tween.cjs +++ b/dist/tween.cjs @@ -227,33 +227,61 @@ var now = function () { return performance.now(); }; */ var Group = /** @class */ (function () { function Group() { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } this._tweens = {}; this._tweensAddedDuringUpdate = {}; + this.add.apply(this, tweens); } Group.prototype.getAll = function () { var _this = this; - return Object.keys(this._tweens).map(function (tweenId) { - return _this._tweens[tweenId]; - }); + return Object.keys(this._tweens).map(function (tweenId) { return _this._tweens[tweenId]; }); }; Group.prototype.removeAll = function () { this._tweens = {}; }; - Group.prototype.add = function (tween) { - this._tweens[tween.getId()] = tween; - this._tweensAddedDuringUpdate[tween.getId()] = tween; + Group.prototype.add = function () { + var _a; + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _b = 0, tweens_1 = tweens; _b < tweens_1.length; _b++) { + var tween = tweens_1[_b]; + // Remove from any other group first, a tween can only be in one group at a time. + // @ts-expect-error library internal access + (_a = tween._group) === null || _a === void 0 ? void 0 : _a.remove(tween); + // @ts-expect-error library internal access + tween._group = this; + this._tweens[tween.getId()] = tween; + this._tweensAddedDuringUpdate[tween.getId()] = tween; + } + }; + Group.prototype.remove = function () { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _a = 0, tweens_2 = tweens; _a < tweens_2.length; _a++) { + var tween = tweens_2[_a]; + // @ts-expect-error library internal access + tween._group = undefined; + delete this._tweens[tween.getId()]; + delete this._tweensAddedDuringUpdate[tween.getId()]; + } }; - Group.prototype.remove = function (tween) { - delete this._tweens[tween.getId()]; - delete this._tweensAddedDuringUpdate[tween.getId()]; + /** Return true if all tweens in the group are not paused or playing. */ + Group.prototype.allStopped = function () { + return this.getAll().every(function (tween) { return !tween.isPlaying(); }); }; Group.prototype.update = function (time, preserve) { if (time === void 0) { time = now(); } - if (preserve === void 0) { preserve = false; } + if (preserve === void 0) { preserve = true; } var tweenIds = Object.keys(this._tweens); - if (tweenIds.length === 0) { - return false; - } + if (tweenIds.length === 0) + return; // Tweens are updated in "batches". If you add a new tween during an // update, then the new tween will be updated in the next batch. // If you remove a tween during an update, it may or may not be updated. @@ -264,13 +292,11 @@ var Group = /** @class */ (function () { for (var i = 0; i < tweenIds.length; i++) { var tween = this._tweens[tweenIds[i]]; var autoStart = !preserve; - if (tween && tween.update(time, autoStart) === false && !preserve) { - delete this._tweens[tweenIds[i]]; - } + if (tween && tween.update(time, autoStart) === false && !preserve) + this.remove(tween); } tweenIds = Object.keys(this._tweensAddedDuringUpdate); } - return true; }; return Group; }()); @@ -379,10 +405,7 @@ var mainGroup = new Group(); * Thank you all, you're awesome! */ var Tween = /** @class */ (function () { - function Tween(_object, _group) { - if (_group === void 0) { _group = mainGroup; } - this._object = _object; - this._group = _group; + function Tween(object, group) { this._isPaused = false; this._pauseStart = 0; this._valuesStart = {}; @@ -407,6 +430,16 @@ var Tween = /** @class */ (function () { this._isChainStopped = false; this._propertiesAreSetUp = false; this._goToEnd = false; + this._object = object; + if (typeof group === 'object') { + this._group = group; + group.add(this); + } + // Use "true" to restore old behavior (will be removed in future release). + else if (group === true) { + this._group = mainGroup; + mainGroup.add(this); + } } Tween.prototype.getId = function () { return this._id; @@ -445,8 +478,6 @@ var Tween = /** @class */ (function () { if (this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.add(this); this._repeat = this._initialRepeat; if (this._reversed) { // If we were reversed (f.e. using the yoyo feature) then we need to @@ -563,8 +594,6 @@ var Tween = /** @class */ (function () { if (!this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.remove(this); this._isPlaying = false; this._isPaused = false; if (this._onStopCallback) { @@ -584,8 +613,6 @@ var Tween = /** @class */ (function () { } this._isPaused = true; this._pauseStart = time; - // eslint-disable-next-line - this._group && this._group.remove(this); return this; }; Tween.prototype.resume = function (time) { @@ -596,8 +623,6 @@ var Tween = /** @class */ (function () { this._isPaused = false; this._startTime += time - this._pauseStart; this._pauseStart = 0; - // eslint-disable-next-line - this._group && this._group.add(this); return this; }; Tween.prototype.stopChainedTweens = function () { @@ -607,8 +632,19 @@ var Tween = /** @class */ (function () { return this; }; Tween.prototype.group = function (group) { - if (group === void 0) { group = mainGroup; } - this._group = group; + if (!group) { + console.warn('tween.group() without args has been removed, use group.add(tween) instead.'); + return this; + } + group.add(this); + return this; + }; + /** + * Removes the tween from whichever group it is in. + */ + Tween.prototype.remove = function () { + var _a; + (_a = this._group) === null || _a === void 0 ? void 0 : _a.remove(this); return this; }; Tween.prototype.delay = function (amount) { @@ -687,12 +723,11 @@ var Tween = /** @class */ (function () { if (this._isPaused) return true; var property; - var endTime = this._startTime + this._duration; if (!this._goToEnd && !this._isPlaying) { - if (time > endTime) - return false; if (autoStart) this.start(time, true); + else + return false; } this._goToEnd = false; if (time < this._startTime) { @@ -856,10 +891,245 @@ var TWEEN = mainGroup; // Modules and CommonJS, without build hacks, and so as not to break the // existing API. // https://github.com/rollup/rollup/issues/1961#issuecomment-423037881 +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var getAll = TWEEN.getAll.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var removeAll = TWEEN.removeAll.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var add = TWEEN.add.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var remove = TWEEN.remove.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var update = TWEEN.update.bind(TWEEN); var exports$1 = { Easing: Easing, @@ -870,10 +1140,245 @@ var exports$1 = { nextId: nextId, Tween: Tween, VERSION: VERSION, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ getAll: getAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ removeAll: removeAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ add: add, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ remove: remove, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ update: update, }; diff --git a/dist/tween.d.ts b/dist/tween.d.ts index 76e29eb1..66185d64 100644 --- a/dist/tween.d.ts +++ b/dist/tween.d.ts @@ -43,22 +43,6 @@ declare const Interpolation: { }; }; -/** - * Controlling groups of tweens - * - * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components. - * In these cases, you may want to create your own smaller groups of tween - */ -declare class Group { - private _tweens; - private _tweensAddedDuringUpdate; - getAll(): Array>; - removeAll(): void; - add(tween: Tween): void; - remove(tween: Tween): void; - update(time?: number, preserve?: boolean): boolean; -} - /** * Tween.js - Licensed under the MIT license * https://github.com/tweenjs/tween.js @@ -68,9 +52,7 @@ declare class Group { * Thank you all, you're awesome! */ -declare class Tween { - private _object; - private _group; +declare class Tween { private _isPaused; private _pauseStart; private _valuesStart; @@ -100,7 +82,20 @@ declare class Tween { private _id; private _isChainStopped; private _propertiesAreSetUp; - constructor(_object: T, _group?: Group | false); + private _object; + private _group?; + /** + * @param object - The object whose properties this Tween will animate. + * @param group - The object whose properties this Tween will animate. + */ + constructor(object: T, group?: Group); + /** + * @deprecated The group parameter is now deprecated, instead use `new + * Tween(object)` then `group.add(tween)` to add a tween to a group. Use + * `new Tween(object, true)` to restore the old behavior for now, but this + * will be removed in the future. + */ + constructor(object: T, group: true); getId(): number; isPlaying(): boolean; isPaused(): boolean; @@ -116,7 +111,20 @@ declare class Tween { pause(time?: number): this; resume(time?: number): this; stopChainedTweens(): this; - group(group?: Group): this; + /** + * Removes the tween from the current group it is in, if any, then adds the + * tween to the specified `group`. + */ + group(group: Group): this; + /** + * @deprecated The argless call signature has been removed. Use + * `tween.group(group)` or `group.add(tween)`, instead. + */ + group(): this; + /** + * Removes the tween from whichever group it is in. + */ + remove(): this; delay(amount?: number): this; repeat(times?: number): this; repeatDelay(amount?: number): this; @@ -143,6 +151,33 @@ declare class Tween { } type UnknownProps = Record; +/** + * Controlling groups of tweens + * + * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components. + * In these cases, you may want to create your own smaller groups of tween + */ +declare class Group { + private _tweens; + private _tweensAddedDuringUpdate; + constructor(...tweens: Tween[]); + getAll(): Array; + removeAll(): void; + add(...tweens: Tween[]): void; + remove(...tweens: Tween[]): void; + /** Return true if all tweens in the group are not paused or playing. */ + allStopped(): boolean; + update(time?: number): void; + /** + * @deprecated The `preserve` parameter is now defaulted to `true` and will + * be removed in a future major release, at which point all tweens of a + * group will always be preserved when calling update. To migrate, always + * use `group.add(tween)` or `group.remove(tween)` to manually add or remove + * tweens, and do not rely on tweens being automatically added or removed. + */ + update(time?: number, preserve?: boolean): void; +} + declare const now: () => number; /** @@ -156,11 +191,249 @@ declare class Sequence { declare const VERSION = "23.1.3"; declare const nextId: typeof Sequence.nextId; -declare const getAll: () => Tween[]; +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ +declare const getAll: () => Tween[]; +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ declare const removeAll: () => void; -declare const add: (tween: Tween) => void; -declare const remove: (tween: Tween) => void; -declare const update: (time?: number, preserve?: boolean) => boolean; +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ +declare const add: (...tweens: Tween[]) => void; +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ +declare const remove: (...tweens: Tween[]) => void; +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ +declare const update: { + (time?: number | undefined): void; + (time?: number | undefined, preserve?: boolean | undefined): void; +}; declare const exports: { Easing: Readonly<{ @@ -196,11 +469,249 @@ declare const exports: { nextId: typeof Sequence.nextId; Tween: typeof Tween; VERSION: string; - getAll: () => Tween[]; + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ + getAll: () => Tween[]; + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ removeAll: () => void; - add: (tween: Tween) => void; - remove: (tween: Tween) => void; - update: (time?: number, preserve?: boolean) => boolean; + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ + add: (...tweens: Tween[]) => void; + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ + remove: (...tweens: Tween[]) => void; + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ + update: { + (time?: number | undefined): void; + (time?: number | undefined, preserve?: boolean | undefined): void; + }; }; export { Easing, Group, Interpolation, Sequence, Tween, VERSION, add, exports as default, getAll, nextId, now, remove, removeAll, update }; diff --git a/dist/tween.esm.js b/dist/tween.esm.js index 1ec97cab..6807f891 100644 --- a/dist/tween.esm.js +++ b/dist/tween.esm.js @@ -223,33 +223,61 @@ var now = function () { return performance.now(); }; */ var Group = /** @class */ (function () { function Group() { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } this._tweens = {}; this._tweensAddedDuringUpdate = {}; + this.add.apply(this, tweens); } Group.prototype.getAll = function () { var _this = this; - return Object.keys(this._tweens).map(function (tweenId) { - return _this._tweens[tweenId]; - }); + return Object.keys(this._tweens).map(function (tweenId) { return _this._tweens[tweenId]; }); }; Group.prototype.removeAll = function () { this._tweens = {}; }; - Group.prototype.add = function (tween) { - this._tweens[tween.getId()] = tween; - this._tweensAddedDuringUpdate[tween.getId()] = tween; + Group.prototype.add = function () { + var _a; + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _b = 0, tweens_1 = tweens; _b < tweens_1.length; _b++) { + var tween = tweens_1[_b]; + // Remove from any other group first, a tween can only be in one group at a time. + // @ts-expect-error library internal access + (_a = tween._group) === null || _a === void 0 ? void 0 : _a.remove(tween); + // @ts-expect-error library internal access + tween._group = this; + this._tweens[tween.getId()] = tween; + this._tweensAddedDuringUpdate[tween.getId()] = tween; + } + }; + Group.prototype.remove = function () { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _a = 0, tweens_2 = tweens; _a < tweens_2.length; _a++) { + var tween = tweens_2[_a]; + // @ts-expect-error library internal access + tween._group = undefined; + delete this._tweens[tween.getId()]; + delete this._tweensAddedDuringUpdate[tween.getId()]; + } }; - Group.prototype.remove = function (tween) { - delete this._tweens[tween.getId()]; - delete this._tweensAddedDuringUpdate[tween.getId()]; + /** Return true if all tweens in the group are not paused or playing. */ + Group.prototype.allStopped = function () { + return this.getAll().every(function (tween) { return !tween.isPlaying(); }); }; Group.prototype.update = function (time, preserve) { if (time === void 0) { time = now(); } - if (preserve === void 0) { preserve = false; } + if (preserve === void 0) { preserve = true; } var tweenIds = Object.keys(this._tweens); - if (tweenIds.length === 0) { - return false; - } + if (tweenIds.length === 0) + return; // Tweens are updated in "batches". If you add a new tween during an // update, then the new tween will be updated in the next batch. // If you remove a tween during an update, it may or may not be updated. @@ -260,13 +288,11 @@ var Group = /** @class */ (function () { for (var i = 0; i < tweenIds.length; i++) { var tween = this._tweens[tweenIds[i]]; var autoStart = !preserve; - if (tween && tween.update(time, autoStart) === false && !preserve) { - delete this._tweens[tweenIds[i]]; - } + if (tween && tween.update(time, autoStart) === false && !preserve) + this.remove(tween); } tweenIds = Object.keys(this._tweensAddedDuringUpdate); } - return true; }; return Group; }()); @@ -375,10 +401,7 @@ var mainGroup = new Group(); * Thank you all, you're awesome! */ var Tween = /** @class */ (function () { - function Tween(_object, _group) { - if (_group === void 0) { _group = mainGroup; } - this._object = _object; - this._group = _group; + function Tween(object, group) { this._isPaused = false; this._pauseStart = 0; this._valuesStart = {}; @@ -403,6 +426,16 @@ var Tween = /** @class */ (function () { this._isChainStopped = false; this._propertiesAreSetUp = false; this._goToEnd = false; + this._object = object; + if (typeof group === 'object') { + this._group = group; + group.add(this); + } + // Use "true" to restore old behavior (will be removed in future release). + else if (group === true) { + this._group = mainGroup; + mainGroup.add(this); + } } Tween.prototype.getId = function () { return this._id; @@ -441,8 +474,6 @@ var Tween = /** @class */ (function () { if (this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.add(this); this._repeat = this._initialRepeat; if (this._reversed) { // If we were reversed (f.e. using the yoyo feature) then we need to @@ -559,8 +590,6 @@ var Tween = /** @class */ (function () { if (!this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.remove(this); this._isPlaying = false; this._isPaused = false; if (this._onStopCallback) { @@ -580,8 +609,6 @@ var Tween = /** @class */ (function () { } this._isPaused = true; this._pauseStart = time; - // eslint-disable-next-line - this._group && this._group.remove(this); return this; }; Tween.prototype.resume = function (time) { @@ -592,8 +619,6 @@ var Tween = /** @class */ (function () { this._isPaused = false; this._startTime += time - this._pauseStart; this._pauseStart = 0; - // eslint-disable-next-line - this._group && this._group.add(this); return this; }; Tween.prototype.stopChainedTweens = function () { @@ -603,8 +628,19 @@ var Tween = /** @class */ (function () { return this; }; Tween.prototype.group = function (group) { - if (group === void 0) { group = mainGroup; } - this._group = group; + if (!group) { + console.warn('tween.group() without args has been removed, use group.add(tween) instead.'); + return this; + } + group.add(this); + return this; + }; + /** + * Removes the tween from whichever group it is in. + */ + Tween.prototype.remove = function () { + var _a; + (_a = this._group) === null || _a === void 0 ? void 0 : _a.remove(this); return this; }; Tween.prototype.delay = function (amount) { @@ -683,12 +719,11 @@ var Tween = /** @class */ (function () { if (this._isPaused) return true; var property; - var endTime = this._startTime + this._duration; if (!this._goToEnd && !this._isPlaying) { - if (time > endTime) - return false; if (autoStart) this.start(time, true); + else + return false; } this._goToEnd = false; if (time < this._startTime) { @@ -852,10 +887,245 @@ var TWEEN = mainGroup; // Modules and CommonJS, without build hacks, and so as not to break the // existing API. // https://github.com/rollup/rollup/issues/1961#issuecomment-423037881 +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var getAll = TWEEN.getAll.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var removeAll = TWEEN.removeAll.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var add = TWEEN.add.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var remove = TWEEN.remove.bind(TWEEN); +/** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var update = TWEEN.update.bind(TWEEN); var exports = { Easing: Easing, @@ -866,10 +1136,245 @@ var exports = { nextId: nextId, Tween: Tween, VERSION: VERSION, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ getAll: getAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ removeAll: removeAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ add: add, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ remove: remove, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ update: update, }; diff --git a/dist/tween.umd.js b/dist/tween.umd.js index bffcc54d..98027a7a 100644 --- a/dist/tween.umd.js +++ b/dist/tween.umd.js @@ -229,33 +229,61 @@ */ var Group = /** @class */ (function () { function Group() { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } this._tweens = {}; this._tweensAddedDuringUpdate = {}; + this.add.apply(this, tweens); } Group.prototype.getAll = function () { var _this = this; - return Object.keys(this._tweens).map(function (tweenId) { - return _this._tweens[tweenId]; - }); + return Object.keys(this._tweens).map(function (tweenId) { return _this._tweens[tweenId]; }); }; Group.prototype.removeAll = function () { this._tweens = {}; }; - Group.prototype.add = function (tween) { - this._tweens[tween.getId()] = tween; - this._tweensAddedDuringUpdate[tween.getId()] = tween; + Group.prototype.add = function () { + var _a; + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _b = 0, tweens_1 = tweens; _b < tweens_1.length; _b++) { + var tween = tweens_1[_b]; + // Remove from any other group first, a tween can only be in one group at a time. + // @ts-expect-error library internal access + (_a = tween._group) === null || _a === void 0 ? void 0 : _a.remove(tween); + // @ts-expect-error library internal access + tween._group = this; + this._tweens[tween.getId()] = tween; + this._tweensAddedDuringUpdate[tween.getId()] = tween; + } + }; + Group.prototype.remove = function () { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + for (var _a = 0, tweens_2 = tweens; _a < tweens_2.length; _a++) { + var tween = tweens_2[_a]; + // @ts-expect-error library internal access + tween._group = undefined; + delete this._tweens[tween.getId()]; + delete this._tweensAddedDuringUpdate[tween.getId()]; + } }; - Group.prototype.remove = function (tween) { - delete this._tweens[tween.getId()]; - delete this._tweensAddedDuringUpdate[tween.getId()]; + /** Return true if all tweens in the group are not paused or playing. */ + Group.prototype.allStopped = function () { + return this.getAll().every(function (tween) { return !tween.isPlaying(); }); }; Group.prototype.update = function (time, preserve) { if (time === void 0) { time = now(); } - if (preserve === void 0) { preserve = false; } + if (preserve === void 0) { preserve = true; } var tweenIds = Object.keys(this._tweens); - if (tweenIds.length === 0) { - return false; - } + if (tweenIds.length === 0) + return; // Tweens are updated in "batches". If you add a new tween during an // update, then the new tween will be updated in the next batch. // If you remove a tween during an update, it may or may not be updated. @@ -266,13 +294,11 @@ for (var i = 0; i < tweenIds.length; i++) { var tween = this._tweens[tweenIds[i]]; var autoStart = !preserve; - if (tween && tween.update(time, autoStart) === false && !preserve) { - delete this._tweens[tweenIds[i]]; - } + if (tween && tween.update(time, autoStart) === false && !preserve) + this.remove(tween); } tweenIds = Object.keys(this._tweensAddedDuringUpdate); } - return true; }; return Group; }()); @@ -381,10 +407,7 @@ * Thank you all, you're awesome! */ var Tween = /** @class */ (function () { - function Tween(_object, _group) { - if (_group === void 0) { _group = mainGroup; } - this._object = _object; - this._group = _group; + function Tween(object, group) { this._isPaused = false; this._pauseStart = 0; this._valuesStart = {}; @@ -409,6 +432,16 @@ this._isChainStopped = false; this._propertiesAreSetUp = false; this._goToEnd = false; + this._object = object; + if (typeof group === 'object') { + this._group = group; + group.add(this); + } + // Use "true" to restore old behavior (will be removed in future release). + else if (group === true) { + this._group = mainGroup; + mainGroup.add(this); + } } Tween.prototype.getId = function () { return this._id; @@ -447,8 +480,6 @@ if (this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.add(this); this._repeat = this._initialRepeat; if (this._reversed) { // If we were reversed (f.e. using the yoyo feature) then we need to @@ -565,8 +596,6 @@ if (!this._isPlaying) { return this; } - // eslint-disable-next-line - this._group && this._group.remove(this); this._isPlaying = false; this._isPaused = false; if (this._onStopCallback) { @@ -586,8 +615,6 @@ } this._isPaused = true; this._pauseStart = time; - // eslint-disable-next-line - this._group && this._group.remove(this); return this; }; Tween.prototype.resume = function (time) { @@ -598,8 +625,6 @@ this._isPaused = false; this._startTime += time - this._pauseStart; this._pauseStart = 0; - // eslint-disable-next-line - this._group && this._group.add(this); return this; }; Tween.prototype.stopChainedTweens = function () { @@ -609,8 +634,19 @@ return this; }; Tween.prototype.group = function (group) { - if (group === void 0) { group = mainGroup; } - this._group = group; + if (!group) { + console.warn('tween.group() without args has been removed, use group.add(tween) instead.'); + return this; + } + group.add(this); + return this; + }; + /** + * Removes the tween from whichever group it is in. + */ + Tween.prototype.remove = function () { + var _a; + (_a = this._group) === null || _a === void 0 ? void 0 : _a.remove(this); return this; }; Tween.prototype.delay = function (amount) { @@ -689,12 +725,11 @@ if (this._isPaused) return true; var property; - var endTime = this._startTime + this._duration; if (!this._goToEnd && !this._isPlaying) { - if (time > endTime) - return false; if (autoStart) this.start(time, true); + else + return false; } this._goToEnd = false; if (time < this._startTime) { @@ -858,10 +893,245 @@ // Modules and CommonJS, without build hacks, and so as not to break the // existing API. // https://github.com/rollup/rollup/issues/1961#issuecomment-423037881 + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var getAll = TWEEN.getAll.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var removeAll = TWEEN.removeAll.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var add = TWEEN.add.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var remove = TWEEN.remove.bind(TWEEN); + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ var update = TWEEN.update.bind(TWEEN); var exports$1 = { Easing: Easing, @@ -872,10 +1142,245 @@ nextId: nextId, Tween: Tween, VERSION: VERSION, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ getAll: getAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ removeAll: removeAll, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ add: add, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ remove: remove, + /** + * @deprecated The global TWEEN Group will be removed in a following major + * release. To migrate, create a `new Group()` instead of using `TWEEN` as a + * group. + * + * Old code: + * + * ```js + * import * as TWEEN from '@tweenjs/tween.js' + * + * //... + * + * const tween = new TWEEN.Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * TWEEN.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + * + * New code: + * + * ```js + * import {Tween, Group} from '@tweenjs/tween.js' + * + * //... + * + * const tween = new Tween(obj) + * const tween2 = new TWEEN.Tween(obj2) + * + * //... + * + * const group = new Group() + * group.add(tween) + * group.add(tween2) + * + * //... + * + * requestAnimationFrame(function loop(time) { + * group.update(time) + * requestAnimationFrame(loop) + * }) + * ``` + */ update: update, }; diff --git a/docs/user_guide.md b/docs/user_guide.md index 4f2061c5..999813aa 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -6,17 +6,21 @@ _**NOTE** This is a work in progress. If you find that something is unclear or m ## What is a tween? How do they work? Why do you want to use them? -A tween (from [_in-between_](http://en.wikipedia.org/wiki/Inbetweening)) is a concept that allows you to change the values of the properties of an object in a smooth way. You just tell it which properties you want to change, which final values should they have when the tween finishes running, and how long should this take, and the tweening engine will take care of finding the intermediate values from the starting to the ending point. For example, suppose you have a `position` object with `x` and `y` coordinates: +A tween (from [_in-between_](http://en.wikipedia.org/wiki/Inbetweening)) is a concept that allows you to change the values of the properties of an object in a smooth way. You just tell it which properties you want to change, which final values should they have when the tween finishes running, and how long should this take, and the tweening engine will take care of finding the intermediate values from the starting to the ending point. + +For example, suppose you have a `position` object with `x` and `y` coordinates: ```javascript -var position = {x: 100, y: 0} +const position = {x: 100, y: 0} ``` If you wanted to change the `x` value from `100` to `200`, you'd do this: ```javascript +import {Tween} from '@tweenjs/tween.js' + // Create a tween for position first -var tween = new TWEEN.Tween(position) +const tween = new Tween(position) // Then tell the tween we want to animate the x property over 1000 milliseconds tween.to({x: 200}, 1000) @@ -29,7 +33,7 @@ Actually this won't do anything yet. The tween has been created but it's not act tween.start() ``` -Finally in order to run as smoothly as possible you should call the `TWEEN.update` function in the same main loop you're using for animating. This generally looks like this: +Finally in order to run as smoothly as possible you should call the `tween.update()` function in the same main loop you're using for animating. This generally looks like this: ```javascript animate() @@ -37,12 +41,12 @@ animate() function animate() { requestAnimationFrame(animate) // [...] - TWEEN.update() + tween.update() // [...] } ``` -This will take care of updating all active tweens; after 1 second (i.e. 1000 milliseconds) `position.x` will be `200`. +After 1 second (i.e. 1000 milliseconds) `position.x` will be `200`. But unless you print the value of `x` to the console, you can't see its value changing. You might want to use the `onUpdate` callback: @@ -57,13 +61,13 @@ This function will be called each time the tween is updated; how often this happ So far we've only used tweens to print values to the console, but you could use it for things such as animating positions of three.js objects: ```javascript -var tween = new TWEEN.Tween(cube.position).to({x: 100, y: 100, z: 100}, 10000).start() +const tween = new Tween(cube.position).to({x: 100, y: 100, z: 100}, 10000).start() animate() function animate() { requestAnimationFrame(animate) - TWEEN.update() + tween.update() threeRenderer.render(scene, camera) } @@ -74,7 +78,7 @@ In this case, because the three.js renderer will look at the object's position b You might have noticed something different here too: we're chaining the tween function calls! Each tween function returns the tween instance, so you can rewrite the following code: ```javascript -var tween = new TWEEN.Tween(position) +const tween = new Tween(position) tween.to({x: 200}, 1000) tween.start() ``` @@ -82,14 +86,14 @@ tween.start() into this ```javascript -var tween = new TWEEN.Tween(position).to({x: 200}, 1000).start() +const tween = new Tween(position).to({x: 200}, 1000).start() ``` You'll see this a lot in the examples, so it's good to be familiar with it! Check [04-simplest](../examples/04_simplest.html) for a working example. ## Animating with tween.js -Tween.js doesn't run by itself. You need to tell it when to run, by explicitly calling the `update` method. The recommended method is to do this inside your main animation loop, which should be called with `requestAnimationFrame` for getting the best graphics performance: +Tween.js doesn't run by itself. You need to tell it when to run, by explicitly calling the `update` method of each tween, or the `update` method of a `Group` that has multiple tweens (more on Groups below). The recommended method is to do this inside your main animation loop, which should be called with `requestAnimationFrame` for getting the best graphics performance: We've seen this example before: @@ -99,7 +103,7 @@ animate() function animate() { requestAnimationFrame(animate) // [...] - TWEEN.update() + tween.update() // [...] } ``` @@ -109,17 +113,17 @@ If called without parameters, `update` will determine the current time in order However you can also pass an explicit time parameter to `update`. Thus, ```javascript -TWEEN.update(100) +tween.update(100) ``` means "update with time = 100 milliseconds". You can use this to make sure that all the time-dependent functions in your code are using the very same time value. For example, suppose you've got a player and want to run tweens in sync. Your `animate` code could look like this: ```javascript -var currentTime = player.currentTime -TWEEN.update(currentTime) +let currentTime = player.currentTime +tween.update(currentTime) ``` -We use explicit time values for the unit tests. You can have a look at [tests.ts](../src/tests.ts) to see how we call TWEEN.update() with different values in order to simulate time passing. +We use explicit time values for the unit tests. You can have a look at [tests.ts](../src/tests.ts) to see how we call `tween.update()` with different values in order to simulate time passing. ## Controlling a tween @@ -127,13 +131,13 @@ We use explicit time values for the unit tests. You can have a look at [tests.ts So far we've learnt about the `Tween.start` method, but there are more methods that control individual tweens. Probably the most important one is the `start` counterpart: `stop`. If you want to cancel a tween, just call this method over an individual tween: -``` -tween.stop(); +```js +tween.stop() ``` Stopping a tween that was never started or that has already been stopped has no effect. No errors are thrown either. -The `start` method also accepts a `time` argument. If you use it, the tween won't start until that particular moment in time; otherwise it will start as soon as possible (i.e. on the next call to `TWEEN.update`). +The `start` method also accepts a `time` argument. If you use it, the tween won't start until that particular moment in time; otherwise it will start as soon as possible (i.e. on the next call to `tween.update()`). The `start` method accepts a second boolean argument: when `true`, a tween that we previously used will start from the values in the target object, instead of starting from the beginning. Useful for stopping a tween, then starting another one that will continue from the current location. @@ -145,12 +149,10 @@ beginning. ### `update` -Individual tweens have an `update` method. This is in fact called by `TWEEN.update` for tweens that have been constructed with only one argument. - -In the following example, the second argument tells the new Tween not to add itself to the default group (`TWEEN` is an instance of `TWEEN.Group`). If the tween is not associated with a group (note that a group can be associated by passing it in as the second arg to the constructor), then the tween needs to be updated manually using its `updated` method like so: +Individual tweens have an `update` method to so that they can be updated over time in an animation loop, and on each update they will apply updated values to their target object. ```js -const tween = new TWEEN.Tween(someObject, false).to(/*...*/).start() +const tween = new Tween(someObject).to(/*...*/).start() function animate(time) { tween.update(time) @@ -158,9 +160,27 @@ function animate(time) { } ``` -> **Note** You don't need to call `tween.update()` directly if you're using `TWEEN.update()` as a way to control all tweens by default, however we recommend that you either [make your own groups of tweens](#controlling-groups-of-tweens) or manually update your tweens directly as in the last example. The concept of using groups or individually-controlled tweens is much like the practice of avoiding use of global variables in your JavaScript code: it prevents one component from accidentally ruining the behavior of some other unrelated component. +### `pause` + +While an tween is running (i.e. it has already been `start`ed and may have +already been `update`d numerous times) it can be paused. Even if `update()` is +called while the tween is paused, its time will not move forward. `isPlaying` +will still be true while a tween is `paused` and its `update()` method continues +to track time progression (you can continue to call `update()` while a tween is +paused). + +```js +tween.start() + +function animate() { + tween.update() + requestAnimationFrame(animate) +} +animate() -Using `TWEEN` to control your tweens is like using globals: and it is only good for simple cases (f.e. small demos, prototypes, etc) but it may not scale well for big apps that may have different parts that need to animate tweens on differing schedules. +// at any time while the tween is running +tween.pause() +``` ### `chain` @@ -243,76 +263,82 @@ See the other `dynamic to` examples for more ideas. > **Warning** When `dynamic` is set to `false`, Tween makes a copy of the object passed into `tween.to()` and will never modify it (hence updating the original object from the outside is not dynamic). When `dynamic` is `true`, Tween uses the original object as the source of values during animation (every update reads the values, hence they can be modified dynamically) but note that **in dynamic mode, Tween will modify any interpolation arrays of the object passed into `tween.to()` which may cause side-effects on any external code that may also rely on the same object**. -## Controlling _all_ the tweens - -The following methods are found in the TWEEN global object, and you generally won't need to use most of them, except for `update`. `TWEEN` is effectively an instance of `TWEEN.Group`, and by default all new Tweens are associated to this global `Group` unless otherwise specified (see the next section on grouping tweens with your own Groups). - -### `TWEEN.update(time)` - -We've already talked about this method. It is used to update all the active tweens. +## Controlling groups of tweens -If `time` is not specified, it will use the current time. +Sometimes you want to update multiple tweens at once, which can be useful when +grouping a set of tweens into a logical component in your application. You can +do this with a `Group`. -### `TWEEN.getAll` and `TWEEN.removeAll` +First add multiple tweens to a group: -Used to get a reference to the active `tweens` array and to remove all of them from the array with just one call, respectively. +```js +import {Group, Tween} from '@tweenjs/tween.js' -### `TWEEN.add(tween)` and `TWEEN.remove(tween)` +const tween1 = new Tween(obj1).to(...).start() +const tween2 = new Tween(obj2).to(...).start() -Used to add a tween to the list of active tweens, or to remove a specific one from the list, respectively. +const group = new Group() +group.add(tween1) +group.add(tween2) +``` -These methods are usually used internally only, but are exposed just in case you want to do something _funny_. +Then call `group.update()` in your animation loop instead of on individual +tweens: -## Controlling groups of tweens +```js +animate() -Using the `TWEEN` singleton to manage your tweens can cause issues in large apps with many components. In these cases, you may want to create your own smaller groups of tweens. +function animate() { + requestAnimationFrame(animate) + // [...] + group.update() + // [...] +} +``` -#### Example: cross-component conflict +Note that a tween can only belong to a single group. Adding a tween to a group +automatically removes it from any previous group. -A conflict can occur if you have multiple components using `TWEEN`, and each component wants to manage its own set of tweens. If one component calls `TWEEN.update()` or `TWEEN.removeAll()` the tweens of other components will also be updated or removed. +### `group.getAll()` -#### Creating your own tween groups +Returns an array of all tweens added to a group. -To solve this, each component can make their own instance of `TWEEN.Group` (which is what the global `TWEEN` object uses internally). These groups can be passed in as a second optional parameter when instantiating a new tween: +### `group.add(tween)` -```javascript -var groupA = new TWEEN.Group() -var groupB = new TWEEN.Group() +Add a tween to a group. -var tweenA = new TWEEN.Tween({x: 1}, groupA).to({x: 10}, 100).start() +### `group.remove(tween)` -var tweenB = new TWEEN.Tween({x: 1}, groupB).to({x: 10}, 100).start() +Remove a tween from a group. -var tweenC = new TWEEN.Tween({x: 1}).to({x: 10}, 100).start() +### `group.removeAll()` -groupA.update() // only updates tweenA -groupB.update() // only updates tweenB -TWEEN.update() // only updates tweenC +Remove all tween from a group. -groupA.removeAll() // only removes tweenA -groupB.removeAll() // only removes tweenB -TWEEN.removeAll() // only removes tweenC -``` +### `group.update(time?)` -In this way, each component can handle creating, updating, and destroying its own set of tweens. +Update all tweens in a group, with an optional time value. If time value is not +supplied, it default to the current time. ## Changing the easing function (AKA make it bouncy) Tween.js will perform the interpolation between values (i.e. the easing) in a linear manner, so the change will be directly proportional to the elapsed time. This is predictable but also quite uninteresting visually wise. Worry not--this behaviour can be easily changed using the `easing` method. For example: ```javascript -tween.easing(TWEEN.Easing.Quadratic.In) +import {Tween, Easing} from '@tweenjs/tween.js' +// ... +tween.easing(Easing.Quadratic.In) ``` -This will result in the tween slowly starting to change towards the final value, accelerating towards the middle, and then quickly reaching its final value. In contrast, `TWEEN.Easing.Quadratic.Out` would start changing quickly towards the value, but then slow down as it approaches the final value. +This will result in the tween slowly starting to change towards the final value, accelerating towards the middle, and then quickly reaching its final value. In contrast, `Easing.Quadratic.Out` would start changing quickly towards the value, but then slow down as it approaches the final value. -### Available easing functions: `TWEEN.Easing` +### Available `Easing` functions There are a few existing easing functions provided with tween.js. They are grouped by the type of equation they represent: Linear, Quadratic, Cubic, Quartic, Quintic, Sinusoidal, Exponential, Circular, Elastic, Back and Bounce, and then by the easing type: In, Out and InOut. Probably the names won't be saying anything to you unless you're familiar with these concepts already, so it is probably the time to check the [Graphs](../examples/03_graphs.html) example, which graphs all the curves in one page so you can compare how they look at a glance. -TWEEN.Easing also has a function called generatePow(). This function generates easing functions for different curves depending on arguments. You can check the relevance of the arguments to curves in the [example of pow easing](../examples/17_generate_pow.html) page. +`Easing` also has a function called `generatePow()`. This function generates easing functions for different curves depending on arguments. You can check the relevance of the arguments to curves in the [example of pow easing](../examples/17_generate_pow.html) page. _Credit where credit is due:_ these functions are derived from the original set of equations that Robert Penner graciously made available as free software a few years ago, but have been optimised to play nicely with JavaScript. @@ -357,7 +383,7 @@ Another powerful feature is to be able to run your own functions at specific tim For example, suppose you're trying to animate some object whose properties can't be accessed directly but require you to call a setter instead. You can use an `update` callback to read the new updated values and then manually call the setters. All callbacks are passed the tweened object as the only parameter. ```javascript -var trickyObjTween = new TWEEN.Tween({ +const trickyObjTween = new Tween({ propertyA: trickyObj.getPropertyA(), propertyB: trickyObj.getPropertyB(), }) @@ -371,7 +397,7 @@ var trickyObjTween = new TWEEN.Tween({ Or imagine you want to play a sound when a tween is started. You can use a `start` callback: ```javascript -var tween = new TWEEN.Tween(obj).to({x: 100}).onStart(function () { +const tween = new Tween(obj).to({x: 100}).onStart(function () { sound.play() }) ``` @@ -421,7 +447,7 @@ To clarify when `onStart`, `onEveryStart` and `onRepeat` are called, consider: ```javascript const obj = {x: 0} -const t = new TWEEN.Tween(obj) +const t = new Tween(obj) .to({x: 5}, 5) .repeat(Infinity) .onStart(() => { @@ -437,7 +463,7 @@ const t = new TWEEN.Tween(obj) for (let ticks = 0; ticks < 22; ticks += 1) { console.log('Tick', ticks) - TWEEN.update(ticks) + t.update(ticks) console.log(obj) console.log() @@ -529,13 +555,13 @@ onEveryStart { x: 5 } ### `isPlaying` -`true` when started (even if paused). +`tween.isPlaying` is `true` when a tween is started, even if it is paused. -When a tween is stopped, `isPlaying` and `isPaused` will both be `false`. +When a tween is stopped, `isPlaying` and `isPaused` will both be `false`, so `!tween.isPlaying()` can be used to detect if a tween is stopped (regardless if the tween has completed). ### `isPaused` -`true` when paused. `isPlaying` will also be `true`. If a tween is started, but not paused, `isPlaying` will be `true` and `isPaused` will be `false`. +`tween.isPaused` is `true` when a tween is paused. `isPlaying` will also be `true`. If a tween is started, but not paused, `isPlaying` will be `true` and `isPaused` will be `false`. ## Advanced tweening @@ -545,7 +571,7 @@ You can also use relative values when using the `to` method. When the tween is s ```javascript // This will make the `x` property be 100, always -var absoluteTween = new TWEEN.Tween(absoluteObj).to({x: 100}) +const absoluteTween = new Tween(absoluteObj).to({x: 100}) // Suppose absoluteObj.x is 0 now absoluteTween.start() // Makes x go to 100 @@ -557,7 +583,7 @@ absoluteTween.start() // Makes x go to 100 // This will make the `x` property be 100 units more, // relative to the actual value when it starts -var relativeTween = new TWEEN.Tween(relativeObj).to({x: '+100'}) +const relativeTween = new Tween(relativeObj).to({x: '+100'}) // Suppose relativeObj.x is 0 now relativeTween.start() // Makes x go to 0 +100 = 100 @@ -573,8 +599,8 @@ Check [09_relative_values](../examples/09_relative_values.html) for an example. Tween.js can also change properties across nested objects. For example: ```javascript -var nestedObject = {scale: {x: 0, y: 0}, alpha: 0} -var tween = new TWEEN.Tween(nestedObject).to({scale: {x: 100, y: 100}, alpha: 1}) +const nestedObject = {scale: {x: 0, y: 0}, alpha: 0} +const tween = new Tween(nestedObject).to({scale: {x: 100, y: 100}, alpha: 1}) ``` ### Tweening to arrays of values @@ -582,7 +608,7 @@ var tween = new TWEEN.Tween(nestedObject).to({scale: {x: 100, y: 100}, alpha: 1} In addition to tweening to an absolute or a relative value, you can also have Tween.js change properties across a series of values. To do this, you just need to specify an array of values instead of a single value for a property. For example: ```javascript -var tween = new TWEEN.Tween(relativeObj).to({x: [0, -100, 100]}) +const tween = new Tween(relativeObj).to({x: [0, -100, 100]}) ``` will make `x` go from its initial value to 0, -100 and 100. @@ -595,17 +621,20 @@ The way these values are calculated is as follows: For example, when the tween has just started (progress is 0), the interpolation function will return the first value in the array. When the tween is halfway, the interpolation function will return a value approximately in the middle of the array, and when the tween is at the end, the interpolation function will return the last value. -You can change the interpolation function with the `interpolation` method. For example: +You can change the interpolation mode by passing an `Interpolation` function +into the `tween.interpolation` method. For example: ```javascript -tween.interpolation(TWEEN.Interpolation.Bezier) +import {Interpolation} from '@tweenjs/tween.js' +// ... +tween.interpolation(Interpolation.Bezier) ``` The following values are available: -- TWEEN.Interpolation.Linear -- TWEEN.Interpolation.Bezier -- TWEEN.Interpolation.CatmullRom +- `Interpolation.Linear` +- `Interpolation.Bezier` +- `Interpolation.CatmullRom` The default is `Linear`. @@ -622,8 +651,8 @@ While Tween.js tries to be performant on its own, nothing prevents you from usin When you try to animate the position of an element in the page, the easiest solution is to animate the `top` and `left` style properties, like this: ```javascript -var element = document.getElementById('myElement') -var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { +const element = document.getElementById('myElement') +const tween = new Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { element.style.top = object.top + 'px' element.style.left = object.left + 'px' }) @@ -632,8 +661,8 @@ var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).o but this is really inefficient because altering these properties forces the browser to recalculate the layout on each update, and this is a very costly operation. Instead of using these, you should use `transform`, which doesn't invalidate the layout and will also be hardware accelerated when possible, like this: ```javascript -var element = document.getElementById('myElement') -var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { +const element = document.getElementById('myElement') +const tween = new Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { element.style.transform = 'translate(' + object.left + 'px, ' + object.top + 'px)' }) ``` diff --git a/docs/user_guide_zh-CN.md b/docs/user_guide_zh-CN.md index 3e6e36e6..c15247d6 100644 --- a/docs/user_guide_zh-CN.md +++ b/docs/user_guide_zh-CN.md @@ -13,14 +13,14 @@ _**NOTE** 这是一个正在进行的工作。 如果你发现某些内容不清 例如,`position` 对象拥有 `x` 和 `y` 两个坐标: ```js -var position = {x: 100, y: 0} +const position = {x: 100, y: 0} ``` 如果你想将 `x` 坐标的值从 `100` 变成 `200` ,你应该这么做: ```js // 首先为位置创建一个补间(tween) -var tween = new TWEEN.Tween(position) +const tween = new TWEEN.Tween(position) // 然后告诉 tween 我们想要在1000毫秒内以动画的形式移动 x 的位置 tween.to({x: 200}, 1000) @@ -61,7 +61,7 @@ tween.onUpdate(function (object) { 到目前为止,我们只使用 tweens 将值打印到控制台,但你可以将它用于 three.js 对象的动画位置之类的事情: ```js -var tween = new TWEEN.Tween(cube.position).to({x: 100, y: 100, z: 100}, 10000).start() +const tween = new TWEEN.Tween(cube.position).to({x: 100, y: 100, z: 100}, 10000).start() animate() @@ -78,7 +78,7 @@ function animate() { 你可能也注意到了一些不同的地方:tween.js 可以链式调用! 每个 tween 函数都会返回 tween 实例,所以你可以重写下面的代码: ```js -var tween = new TWEEN.Tween(position) +const tween = new TWEEN.Tween(position) tween.to({x: 200}, 1000) tween.start() ``` @@ -86,7 +86,7 @@ tween.start() 改成这样: ```js -var tween = new TWEEN.Tween(position).to({x: 200}, 1000).start() +const tween = new TWEEN.Tween(position).to({x: 200}, 1000).start() ``` 在将会看到很多例子,所以熟悉它是很好的!比如 [04-simplest](../examples/04_simplest.html) 这个例子。 @@ -119,7 +119,7 @@ TWEEN.update(100) 意思是“更新时间 = 100 毫秒”。你可以使用它来确保代码中的所有时间相关函数都使用相同的时间值。例如,假设你有一个播放器,并希望同步运行补间。 你的 `animate` 函数可能看起来像这样: ```js -var currentTime = player.currentTime +const currentTime = player.currentTime TWEEN.update(currentTime) ``` @@ -272,14 +272,14 @@ tween.start() 为了解决这个问题,每个组件都可以创建自己的 `TWEEN.Group` 实例(这是全局 `TWEEN` 对象在内部使用的实例)。 在实例化新补间时,这些组可以作为第二个可选参数传入: ```js -var groupA = new TWEEN.Group() -var groupB = new TWEEN.Group() +const groupA = new TWEEN.Group() +const groupB = new TWEEN.Group() -var tweenA = new TWEEN.Tween({x: 1}, groupA).to({x: 10}, 100).start() +const tweenA = new TWEEN.Tween({x: 1}, groupA).to({x: 10}, 100).start() -var tweenB = new TWEEN.Tween({x: 1}, groupB).to({x: 10}, 100).start() +const tweenB = new TWEEN.Tween({x: 1}, groupB).to({x: 10}, 100).start() -var tweenC = new TWEEN.Tween({x: 1}).to({x: 10}, 100).start() +const tweenC = new TWEEN.Tween({x: 1}).to({x: 10}, 100).start() groupA.update() // 只更新tweenA groupB.update() // 只更新tweenB @@ -351,7 +351,7 @@ tween.easing(tenStepEasing) 例如,假设你正在试图给一些不能直接访问属性的对象设置动画,但是需要你调用 setter。 你可以使用 `update` 回调来读取新的更新值,然后手动调用 setters。 所有的回调函数都将补间对象作为唯一的参数。 ```js -var trickyObjTween = new TWEEN.Tween({ +const trickyObjTween = new TWEEN.Tween({ propertyA: trickyObj.getPropertyA(), propertyB: trickyObj.getPropertyB(), }) @@ -365,7 +365,7 @@ var trickyObjTween = new TWEEN.Tween({ 或者假设你想在开始补间时播放声音。 你可以使用 `start` 回调: ```js -var tween = new TWEEN.Tween(obj).to({x: 100}).onStart(function () { +const tween = new TWEEN.Tween(obj).to({x: 100}).onStart(function () { sound.play() }) ``` @@ -540,7 +540,7 @@ onEveryStart { x: 5 } ```js // 这将使 `x` 属性始终为 100 -var absoluteTween = new TWEEN.Tween(absoluteObj).to({x: 100}) +const absoluteTween = new TWEEN.Tween(absoluteObj).to({x: 100}) // 假设 absoluteObj.x 现在为 0 absoluteTween.start() // 使 x 变为 100 @@ -551,7 +551,7 @@ absoluteTween.start() // 使 x 变为 100 // 相比之下... // 这将使 `x` 属性相对于开始时的实际值多 100 个单位 -var relativeTween = new TWEEN.Tween(relativeObj).to({x: '+100'}) +const relativeTween = new TWEEN.Tween(relativeObj).to({x: '+100'}) // 假设 relativeObj.x 现在是 0 relativeTween.start() // 使 x 变为 0 +100 = 100 @@ -567,8 +567,8 @@ relativeTween.start() // 使 x 变为 -100 +100 = 0 Tween.js 还可以跨嵌套对象更改属性。 例如: ```js -var nestedObject = {scale: {x: 0, y: 0}, alpha: 0} -var tween = new TWEEN.Tween(nestedObject).to({scale: {x: 100, y: 100}, alpha: 1}) +const nestedObject = {scale: {x: 0, y: 0}, alpha: 0} +const tween = new TWEEN.Tween(nestedObject).to({scale: {x: 100, y: 100}, alpha: 1}) ``` ### 补间值的数组 @@ -576,7 +576,7 @@ var tween = new TWEEN.Tween(nestedObject).to({scale: {x: 100, y: 100}, alpha: 1} 除了补间到绝对值或相对值之外,你还可以让 Tween.js 更改一系列值的属性。 为此,你只需为属性指定一个值数组而不是单个值。 例如: ```js -var tween = new TWEEN.Tween(relativeObj).to({x: [0, -100, 100]}) +const tween = new TWEEN.Tween(relativeObj).to({x: [0, -100, 100]}) ``` 将使 `x` 从初始值变为 0,-100 和 100。 @@ -617,8 +617,8 @@ tween.interpolation(TWEEN.Interpolation.Bezier) 当你尝试为页面中元素的位置设置动画时,最简单的解决方案是为 `top` 和 `left` 样式属性设置动画,如下所示: ```js -var element = document.getElementById('myElement') -var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { +const element = document.getElementById('myElement') +const tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { element.style.top = object.top + 'px' element.style.left = object.left + 'px' }) @@ -627,8 +627,8 @@ var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).o 但这确实效率低下,因为更改这些属性会强制浏览器在每次更新时重新计算布局,这是一项非常消耗性能的操作。你应该使用 `transform`,它不会使布局无效,并且在可能的情况下也会进行硬件加速,如下所示: ```js -var element = document.getElementById('myElement') -var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { +const element = document.getElementById('myElement') +const tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) { element.style.transform = 'translate(' + object.left + 'px, ' + object.top + 'px);' }) ``` diff --git a/examples/00_hello_world.html b/examples/00_hello_world.html index 4a966fa2..6f19267e 100644 --- a/examples/00_hello_world.html +++ b/examples/00_hello_world.html @@ -25,36 +25,39 @@

00 _ hello world

hello world! - - - diff --git a/examples/02_black_and_red.html b/examples/02_black_and_red.html index cc6bb726..6fab5d59 100644 --- a/examples/02_black_and_red.html +++ b/examples/02_black_and_red.html @@ -32,62 +32,63 @@

02 _ Black and red

} - - diff --git a/examples/03_graphs.html b/examples/03_graphs.html index dadd44ad..5c75d52f 100644 --- a/examples/03_graphs.html +++ b/examples/03_graphs.html @@ -24,74 +24,77 @@

03 _ graphs

- - - diff --git a/examples/04_simplest.html b/examples/04_simplest.html index a227256f..59e7cc55 100644 --- a/examples/04_simplest.html +++ b/examples/04_simplest.html @@ -12,31 +12,29 @@

04 _ simplest possible example

Creating a tween and doing little else apart from that :)

- - diff --git a/examples/05_video_and_time.html b/examples/05_video_and_time.html index 656cbdf0..52d17f16 100644 --- a/examples/05_video_and_time.html +++ b/examples/05_video_and_time.html @@ -17,7 +17,7 @@

05 _ video and time

style=" position: absolute; left: 0px; - top: 300px; + top: 350px; transform: translateX(50px); font-size: 100px; letter-spacing: -7px; @@ -26,9 +26,11 @@

05 _ video and time

- - - diff --git a/examples/07_dynamic_to.html b/examples/07_dynamic_to.html index 34b2c9fc..cd9c5d88 100644 --- a/examples/07_dynamic_to.html +++ b/examples/07_dynamic_to.html @@ -31,55 +31,43 @@

07 _ dynamic to object

- - - + +
diff --git a/examples/09_relative_values.js b/examples/09_relative_values.js new file mode 100644 index 00000000..75d30215 --- /dev/null +++ b/examples/09_relative_values.js @@ -0,0 +1,29 @@ +import {Tween, Group, Easing} from '@tweenjs/tween.js' + +const target1 = document.getElementById('target1') +const tween = new Tween(target1.dataset) + .to({top: '+20', left: '-20'}, 500) + .repeat(5) + .delay(500) + .easing(Easing.Exponential.In) + .onUpdate(function (object) { + object.top = Math.round(object.top) + object.left = Math.round(object.left) + updateBox(target1, object) + }) + .start() + +updateBox(target1, target1.dataset) + +animate() + +function animate(time) { + requestAnimationFrame(animate) + tween.update(time) +} + +function updateBox(box, params) { + const s = box.style + const transform = 'translate(' + params.left + 'px, ' + params.top + 'px)' + s.transform = transform +} diff --git a/examples/10_yoyo.html b/examples/10_yoyo.html index 9378887e..2045ce36 100644 --- a/examples/10_yoyo.html +++ b/examples/10_yoyo.html @@ -4,6 +4,16 @@ Tween.js / yoyo + + + +
@@ -29,110 +39,6 @@

10 _ yoyo

- - -