moveTowards function
Moves a value towards a target at a limited rate (a slew-rate limiter), whatever the frame rate: a needle or a rudder that cannot jump.
ts
import { moveTowards } from 'utils';Signature
ts
export function moveTowards(current: number, target: number, maxRatePerSecond: number, deltaMs: number): numberParameters
| Name | Description |
|---|---|
current | The current value. |
target | The value to reach. |
maxRatePerSecond | The largest change per second. |
deltaMs | The time elapsed since the previous call, in milliseconds. |
Returns
The new value, never beyond target.
Example
ts
moveTowards(0, 10, 5, 1000); // 5
moveTowards(8, 10, 5, 1000); // 10Tests
Line coverage: 100 %.
- ✅ moves from 0 towards 10 at 5/s over 1000 ms: 5
- ✅ moves from 0 towards 10 at 5/s over 500 ms: 2.5
- ✅ moves from 10 towards 0 at 5/s over 1000 ms: 5
- ✅ moves from 9 towards 10 at 5/s over 1000 ms: 10
- ✅ moves from 10 towards 10 at 5/s over 1000 ms: 10
- ✅ moves from 0 towards 10 at 0/s over 1000 ms: 0
- ✅ gives the same result whatever the frame rate
Source
src/math/move-towards.ts (on GitHub)
Source code
ts
const MS_PER_SECOND = 1000;
/**
* Moves a value towards a target at a limited rate (a slew-rate limiter), whatever the frame rate: a needle
* or a rudder that cannot jump.
*
* @param current - The current value.
* @param target - The value to reach.
* @param maxRatePerSecond - The largest change per second.
* @param deltaMs - The time elapsed since the previous call, in milliseconds.
* @returns The new value, never beyond `target`.
* @example
* moveTowards(0, 10, 5, 1000); // 5
* moveTowards(8, 10, 5, 1000); // 10
*/
export function moveTowards(current: number, target: number, maxRatePerSecond: number, deltaMs: number): number {
const maxStep = (maxRatePerSecond * deltaMs) / MS_PER_SECOND;
const difference = target - current;
return Math.abs(difference) <= maxStep ? target : current + Math.sign(difference) * maxStep;
}Test file
ts
import { moveTowards } from './move-towards';
describe(moveTowards, () => {
it.for([
[0, 10, 5, 1000, 5],
[0, 10, 5, 500, 2.5],
[10, 0, 5, 1000, 5],
[9, 10, 5, 1000, 10],
[10, 10, 5, 1000, 10],
[0, 10, 0, 1000, 0],
] as const)('moves from %s towards %s at %s/s over %s ms: %s', ([current, target, rate, deltaMs, expected]) => {
expect(moveTowards(current, target, rate, deltaMs)).toBe(expected);
});
it('gives the same result whatever the frame rate', () => {
let value = 0;
for (let frame = 0; frame < 10; frame++) {
value = moveTowards(value, 100, 20, 100);
}
expect(value).toBeCloseTo(moveTowards(0, 100, 20, 1000), 9);
});
});Keywords: move, towards, math, function