Skip to content

Commit 8f71304

Browse files
authored
Merge pull request #720 from tweenjs/fix/stabilize-tween-end-time-at-completion
fix: stabilize tween end at exact completion
2 parents bec15dd + 1517f1c commit 8f71304

8 files changed

Lines changed: 28 additions & 26 deletions

File tree

‎dist/tween.amd.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -775,15 +775,15 @@ define(['exports'], (function (exports) { 'use strict';
775775
var calculateElapsedPortion = function () {
776776
if (_this._duration === 0)
777777
return 1;
778-
if (elapsedTime > totalTime) {
778+
if (time >= _this._startTime + totalTime) {
779779
return 1;
780780
}
781781
var timesRepeated = Math.trunc(elapsedTime / durationAndDelay);
782782
var timeIntoCurrentRepeat = elapsedTime - timesRepeated * durationAndDelay;
783783
// TODO use %?
784784
// const timeIntoCurrentRepeat = elapsedTime % durationAndDelay
785785
var portion = Math.min(timeIntoCurrentRepeat / _this._duration, 1);
786-
if (portion === 0 && elapsedTime === _this._duration) {
786+
if ((portion === 0 || 1 - portion <= Number.EPSILON) && time >= _this._startTime + _this._duration) {
787787
return 1;
788788
}
789789
return portion;
@@ -795,7 +795,7 @@ define(['exports'], (function (exports) { 'use strict';
795795
if (this._onUpdateCallback) {
796796
this._onUpdateCallback(this._object, elapsed);
797797
}
798-
if (this._duration === 0 || elapsedTime >= this._duration) {
798+
if (this._duration === 0 || time >= this._startTime + this._duration) {
799799
if (this._repeat > 0) {
800800
var completeCount = Math.min(Math.trunc((elapsedTime - this._duration) / durationAndDelay) + 1, this._repeat);
801801
if (isFinite(this._repeat)) {

‎dist/tween.cjs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -777,15 +777,15 @@ var Tween = /** @class */ (function () {
777777
var calculateElapsedPortion = function () {
778778
if (_this._duration === 0)
779779
return 1;
780-
if (elapsedTime > totalTime) {
780+
if (time >= _this._startTime + totalTime) {
781781
return 1;
782782
}
783783
var timesRepeated = Math.trunc(elapsedTime / durationAndDelay);
784784
var timeIntoCurrentRepeat = elapsedTime - timesRepeated * durationAndDelay;
785785
// TODO use %?
786786
// const timeIntoCurrentRepeat = elapsedTime % durationAndDelay
787787
var portion = Math.min(timeIntoCurrentRepeat / _this._duration, 1);
788-
if (portion === 0 && elapsedTime === _this._duration) {
788+
if ((portion === 0 || 1 - portion <= Number.EPSILON) && time >= _this._startTime + _this._duration) {
789789
return 1;
790790
}
791791
return portion;
@@ -797,7 +797,7 @@ var Tween = /** @class */ (function () {
797797
if (this._onUpdateCallback) {
798798
this._onUpdateCallback(this._object, elapsed);
799799
}
800-
if (this._duration === 0 || elapsedTime >= this._duration) {
800+
if (this._duration === 0 || time >= this._startTime + this._duration) {
801801
if (this._repeat > 0) {
802802
var completeCount = Math.min(Math.trunc((elapsedTime - this._duration) / durationAndDelay) + 1, this._repeat);
803803
if (isFinite(this._repeat)) {

‎dist/tween.esm.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -773,15 +773,15 @@ var Tween = /** @class */ (function () {
773773
var calculateElapsedPortion = function () {
774774
if (_this._duration === 0)
775775
return 1;
776-
if (elapsedTime > totalTime) {
776+
if (time >= _this._startTime + totalTime) {
777777
return 1;
778778
}
779779
var timesRepeated = Math.trunc(elapsedTime / durationAndDelay);
780780
var timeIntoCurrentRepeat = elapsedTime - timesRepeated * durationAndDelay;
781781
// TODO use %?
782782
// const timeIntoCurrentRepeat = elapsedTime % durationAndDelay
783783
var portion = Math.min(timeIntoCurrentRepeat / _this._duration, 1);
784-
if (portion === 0 && elapsedTime === _this._duration) {
784+
if ((portion === 0 || 1 - portion <= Number.EPSILON) && time >= _this._startTime + _this._duration) {
785785
return 1;
786786
}
787787
return portion;
@@ -793,7 +793,7 @@ var Tween = /** @class */ (function () {
793793
if (this._onUpdateCallback) {
794794
this._onUpdateCallback(this._object, elapsed);
795795
}
796-
if (this._duration === 0 || elapsedTime >= this._duration) {
796+
if (this._duration === 0 || time >= this._startTime + this._duration) {
797797
if (this._repeat > 0) {
798798
var completeCount = Math.min(Math.trunc((elapsedTime - this._duration) / durationAndDelay) + 1, this._repeat);
799799
if (isFinite(this._repeat)) {

‎dist/tween.umd.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -779,15 +779,15 @@
779779
var calculateElapsedPortion = function () {
780780
if (_this._duration === 0)
781781
return 1;
782-
if (elapsedTime > totalTime) {
782+
if (time >= _this._startTime + totalTime) {
783783
return 1;
784784
}
785785
var timesRepeated = Math.trunc(elapsedTime / durationAndDelay);
786786
var timeIntoCurrentRepeat = elapsedTime - timesRepeated * durationAndDelay;
787787
// TODO use %?
788788
// const timeIntoCurrentRepeat = elapsedTime % durationAndDelay
789789
var portion = Math.min(timeIntoCurrentRepeat / _this._duration, 1);
790-
if (portion === 0 && elapsedTime === _this._duration) {
790+
if ((portion === 0 || 1 - portion <= Number.EPSILON) && time >= _this._startTime + _this._duration) {
791791
return 1;
792792
}
793793
return portion;
@@ -799,7 +799,7 @@
799799
if (this._onUpdateCallback) {
800800
this._onUpdateCallback(this._object, elapsed);
801801
}
802-
if (this._duration === 0 || elapsedTime >= this._duration) {
802+
if (this._duration === 0 || time >= this._startTime + this._duration) {
803803
if (this._repeat > 0) {
804804
var completeCount = Math.min(Math.trunc((elapsedTime - this._duration) / durationAndDelay) + 1, this._repeat);
805805
if (isFinite(this._repeat)) {

‎docs/contributor_guide_zh-CN.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,4 @@ Prettier 规则在 `.prettierrc.js` 中,ESLint 规则在 `.eslintrc.js` 中。
118118

119119
当准备在 `master` 分支上发布时,确保没有未提交的更改,然后运行 `npm run release:patch` 来发布补丁版本号递增的新版本,运行 `npm run release:minor` 来发布次版本号递增的新版本,或运行 `npm run release:major` 来发布主版本号递增的新版本。
120120

121-
提示:请参阅 [semver.org](https://semver.org) 和 [npm-semver](https://docs.npmjs.com/misc/semver) 文档来了解语义版本控制。
121+
提示:请参阅 [semver.org](https://semver.org) 和 [npm-semver](https://docs.npmjs.com/misc/semver) 文档来了解语义版本控制。

‎docs/user_guide_zh-CN.md‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ tween.pause()
179179

180180
### `chain`
181181

182-
当你按顺序排列不同的补间时,事情变得更有趣,即设置一个补间在前一个完成后开始。我们称之为_链式补间_,这通过 `chain` 方法完成。因此,要使 `tweenB` 在 `tweenA` 完成后开始:
182+
当你按顺序排列不同的补间时,事情变得更有趣,即设置一个补间在前一个完成后开始。我们称之为*链式补间*,这通过 `chain` 方法完成。因此,要使 `tweenB` 在 `tweenA` 完成后开始:
183183

184184
```javascript
185185
tweenA.chain(tweenB)
@@ -216,7 +216,7 @@ tween.repeat(Infinity) // 永远重复
216216

217217
### `yoyo`
218218

219-
此函数只有与 `repeat` 一起使用时才有效。当激活时,补间的行为将_像溜溜球_,即它将在开始值和结束值之间来回跳跃,而不是只是从头开始重复相同的序列:
219+
此函数只有与 `repeat` 一起使用时才有效。当激活时,补间的行为将*像溜溜球*,即它将在开始值和结束值之间来回跳跃,而不是只是从头开始重复相同的序列:
220220

221221
```js
222222
tween.yoyo(false) // 默认值,动画只会从开始值到结束值
@@ -364,7 +364,7 @@ function tenStepEasing(k) {
364364
tween.easing(tenStepEasing)
365365
```
366366

367-
查看[自定义缓动函数的图表](../examples/12_graphs_custom_functions.html)示例以查看实际效果(以及一些用于生成步进函数的_元编程_)。
367+
查看[自定义缓动函数的图表](../examples/12_graphs_custom_functions.html)示例以查看实际效果(以及一些用于生成步进函数的*元编程*)。
368368

369369
## 回调
370370

@@ -396,15 +396,15 @@ const tween = new Tween(obj).to({x: 100}).onStart(function () {
396396

397397
### onStart
398398

399-
在补间开始动画之前执行,在 `delay` 方法指定的任何延迟时间之后。每个补间只会执行一次,即当补间通过 `repeat()` 重复时_不会_运行。
399+
在补间开始动画之前执行,在 `delay` 方法指定的任何延迟时间之后。每个补间只会执行一次,即当补间通过 `repeat()` 重复时*不会*运行。
400400

401401
它非常适合与其他事件同步或触发你希望在补间开始时发生的操作。
402402

403403
补间对象作为第一个参数传入。
404404

405405
### onEveryStart
406406

407-
与 `onStart` 一样,但它_会_在补间的每次重复时运行。
407+
与 `onStart` 一样,但它*会*在补间的每次重复时运行。
408408

409409
补间对象作为第一个参数传入。
410410

@@ -665,12 +665,12 @@ const tween = new Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpd
665665

666666
如果你想了解更多相关信息,请查看[这篇文章](http://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/)。
667667

668-
但是,如果你的动画需求_就是那么_简单,最好只使用 CSS 动画或过渡(在适用的情况下),以便浏览器可以尽可能地优化。当你的动画需求涉及复杂的安排时,Tween.js 最有用,即你需要将多个补间同步在一起,在一个完成后开始一些补间,循环它们多次,有不是用 CSS 而是用 Canvas 或 WebGL 渲染的图形等等。
668+
但是,如果你的动画需求*就是那么*简单,最好只使用 CSS 动画或过渡(在适用的情况下),以便浏览器可以尽可能地优化。当你的动画需求涉及复杂的安排时,Tween.js 最有用,即你需要将多个补间同步在一起,在一个完成后开始一些补间,循环它们多次,有不是用 CSS 而是用 Canvas 或 WebGL 渲染的图形等等。
669669

670670
### 对垃圾收集器友好(别名 GC)
671671

672-
如果你使用 `onUpdate` 回调,你需要对放入其中的内容非常小心。此函数每秒将被调用多次,因此如果你在每次更新时进行昂贵的操作,你可能会阻塞主线程并导致可怕的_卡顿_,或者——如果你的操作涉及内存分配,你最终会让垃圾收集器运行得太频繁,也会导致_卡顿_。所以不要做这两件事中的任何一件。保持你的 `onUpdate` 回调非常轻量级,并确保在开发时也使用内存分析器。
672+
如果你使用 `onUpdate` 回调,你需要对放入其中的内容非常小心。此函数每秒将被调用多次,因此如果你在每次更新时进行昂贵的操作,你可能会阻塞主线程并导致可怕的*卡顿*,或者——如果你的操作涉及内存分配,你最终会让垃圾收集器运行得太频繁,也会导致*卡顿*。所以不要做这两件事中的任何一件。保持你的 `onUpdate` 回调非常轻量级,并确保在开发时也使用内存分析器。
673673

674674
## 疯狂的补间
675675

676-
这是你可能不经常使用的东西,但你可以在 Tween.js 之外使用补间方程。它们毕竟只是函数。因此,你可以使用它们来计算平滑曲线作为输入数据。例如,它们在[这个实验](http://5013.es/toys/tween.audio/)中用于生成音频数据。
676+
这是你可能不经常使用的东西,但你可以在 Tween.js 之外使用补间方程。它们毕竟只是函数。因此,你可以使用它们来计算平滑曲线作为输入数据。例如,它们在[这个实验](http://5013.es/toys/tween.audio/)中用于生成音频数据。

‎src/Tween.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ export class Tween<T extends UnknownProps = any> {
479479

480480
const calculateElapsedPortion = () => {
481481
if (this._duration === 0) return 1
482-
if (elapsedTime > totalTime) {
482+
if (time >= this._startTime + totalTime) {
483483
return 1
484484
}
485485

@@ -489,7 +489,7 @@ export class Tween<T extends UnknownProps = any> {
489489
// const timeIntoCurrentRepeat = elapsedTime % durationAndDelay
490490

491491
const portion = Math.min(timeIntoCurrentRepeat / this._duration, 1)
492-
if (portion === 0 && elapsedTime === this._duration) {
492+
if ((portion === 0 || 1 - portion <= Number.EPSILON) && time >= this._startTime + this._duration) {
493493
return 1
494494
}
495495
return portion
@@ -504,7 +504,7 @@ export class Tween<T extends UnknownProps = any> {
504504
this._onUpdateCallback(this._object, elapsed)
505505
}
506506

507-
if (this._duration === 0 || elapsedTime >= this._duration) {
507+
if (this._duration === 0 || time >= this._startTime + this._duration) {
508508
if (this._repeat > 0) {
509509
const completeCount = Math.min(Math.trunc((elapsedTime - this._duration) / durationAndDelay) + 1, this._repeat)
510510
if (isFinite(this._repeat)) {

‎src/tests.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,10 +1494,11 @@ export const tests = {
14941494
'Test that TWEEN.Tween.end sets the final values.'(test: Test): void {
14951495
const object1 = {x: 0, y: -50, z: 1000}
14961496
const target1 = {x: 50, y: 123, z: '+234'}
1497+
const fractionalStartTime = 1234.56789
14971498

14981499
const tween1 = new TWEEN.Tween(object1).to(target1, 1000)
14991500

1500-
tween1.start()
1501+
tween1.start(fractionalStartTime)
15011502
tween1.end()
15021503

15031504
test.equal(object1.x, 50)
@@ -1522,12 +1523,13 @@ export const tests = {
15221523

15231524
'Test that TWEEN.Tween.end calls the onComplete callback of the tween.'(test: Test): void {
15241525
test.expect(1)
1526+
const fractionalStartTime = 1234.56789
15251527

15261528
const tween1 = new TWEEN.Tween({}).to({}, 1000).onComplete(function (): void {
15271529
test.ok(true)
15281530
})
15291531

1530-
tween1.start()
1532+
tween1.start(fractionalStartTime)
15311533
tween1.end()
15321534

15331535
test.done()

0 commit comments

Comments
 (0)