Skip to content

Commit

Permalink
Made _evaluateSpring take an absolute timestamp
Browse files Browse the repository at this point in the history
Summary: This separates the looping logic (`_step`) from the state updating logic (`_evaluateSpring`).  By keep these separate, it's easier to ensure that only one loop is running at a time, and that the listeners are only triggered once per frame.

Reviewers: skevy

Reviewed By: skevy

Differential Revision: http://codereview.cc/D3339
  • Loading branch information
appsforartists committed Sep 15, 2017
1 parent 49a3a2f commit 0696712
Showing 1 changed file with 29 additions and 18 deletions.
47 changes: 29 additions & 18 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export class Spring {
// being changed in `updatedConfig`, we run the simulation with `_step()`
// and default `fromValue` and `initialVelocity` to their current values.

this._step(performance.now());
this._evaluateSpring(performance.now());

const baseConfig = {
fromValue: this._currentValue,
Expand Down Expand Up @@ -229,10 +229,31 @@ export class Spring {
});
}

/**
* `_step` is the main loop. While the animation is running, it updates the
* current state once per frame, and schedules the next frame if the spring is
* not yet at rest.
*/
_step(timestamp: number) {
// `_step` updates `_currentTime` and dispatches `onUpdate`. Because of
// these side effects, it's only safe to call when an animation is already
// in-progress.
this._evaluateSpring(timestamp);

// check `_isAnimating`, in case `stop()` got called during
// `evaluateSpring()`
if (this._isAnimating) {
this._currentAnimationStep = requestAnimationFrame((t: number) =>
this._step(t)
);
}
}

/**
* `_evaluateSpring` updates `_currentTime`, `_currentValue`, and
* `_currentVelocity` to reflect the absolute timestamp provided.
*/
_evaluateSpring(timestamp: number) {
// `_evaluateSpring` updates `_currentTime` and triggers the listeners.
// Because of these side effects, it's only safe to call when an animation
// is already in-progress.
if (!this._isAnimating) {
return;
}
Expand All @@ -242,23 +263,12 @@ export class Spring {
this._currentTime = timestamp;
}

const deltaTime = timestamp - this._currentTime;

if (deltaTime || isFirstStep) {
this._evaluateSpring(deltaTime);
this._currentTime = timestamp;
let deltaTime = timestamp - this._currentTime;

// check `_isAnimating` again, in case `stop()` got called during
// `evaluateSpring()`
if (this._isAnimating) {
this._currentAnimationStep = requestAnimationFrame((t: number) =>
this._step(t)
);
}
if (deltaTime === 0 && !isFirstStep) {
return;
}
}

_evaluateSpring(deltaTime: number) {
// If for some reason we lost a lot of frames (e.g. process large payload or
// stopped in the debugger), we only advance by 4 frames worth of
// computation and will continue on the next frame. It's better to have it
Expand Down Expand Up @@ -339,6 +349,7 @@ export class Spring {
omega2;
}

this._currentTime = timestamp;
this._currentValue = oscillation;
this._currentVelocity = velocity;

Expand Down

0 comments on commit 0696712

Please sign in to comment.