Skip to content

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): number

Parameters ​

NameDescription
currentThe current value.
targetThe value to reach.
maxRatePerSecondThe largest change per second.
deltaMsThe 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); // 10

Tests ​

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

Generated from the JSDoc of the sources.