virtual-clock

3 min read Original article ↗

virtual-clock

A tiny library for configurable virtual clocks

npm license dependencies coverage code quality build status

Overview

virtual-clock is a tiny library for tracking time, for example in games, simulations, visualizations, media applications, or even just a stopwatch app.

Virtual clocks can be paused and resumed, be sped up, down, or even made to go backwards, can be limited to not go beyond a certain minimum or maximum value, or to loop around whenever the set minimum or maximum value is reached.

Clocks can register callbacks which should fire at specific clock times, either once or every time the clock reaches the specified time. Event listeners can also be attached for specific changes in state, for example to be notified when the clock is started or stopped.

A VirtualClock's time is calculated using high resolution time data, meaning clock time is not affected by imprecision in JavaScript's timers, system clock drift or skewing by software like NTP. This makes it ideal for use in for example graphics render loops where the timing should not be bound to the speed at which the software runs.

The library has extensive test coverage for all functionality and edge cases, provides type annotations for both TypeScript and Flow users, and is fully compatible with browsers, Node.js, and Deno environments.

Usage example

Try it live: https://virtual-clock.js.org/

import VirtualClock from 'virtual-clock';

const VirtualClock = require('virtual-clock');

import VirtualClock from 'https://virtual-clock.js.org/1.2.3/virtual-clock.mjs';

let clock = new VirtualClock;

console.log('Initial clock time: ' + clock.time);

let outputElement = document.getElementById('output');

(function loop() {

    outputElement.textContent = (clock.time / 1000).toFixed(5);

    window.requestAnimationFrame(loop);

})();

clock.start();

clock.running = true;

clock.rate = 2.0;

clock.rate = -1.0;

console.log('Default bounds: ' + clock.minimum + ' - ' + clock.maximum);

clock.minimum = 0;

clock.maximum = 10 * 1000;

clock.loop = true;

clock.on('start', () => {

    console.log('The clock has been started!');

});

clock.on('setrate', () => {

    console.log('The flow rate of time was set!');

});

clock.onceAt(9 * 1000, () => {

    console.log('I\'ll fire once at 9, and then never again!');

});

clock.alwaysAt(5 * 1000, () => {

    console.log('I\'ll fire every time the clock is at 5!');

});

clock.minimum += 1000;

clock.rate *= 2;

API

class VirtualClock {

    start(): VirtualClock;

    stop(): VirtualClock;

    on(event: string, callback: () => mixed): VirtualClock;

    off(event: string, callback: () => mixed): VirtualClock;

    trigger(event: string, ...args: mixed[]): VirtualClock;

    onceAt(time: number, callback: () => mixed): VirtualClock;

    alwaysAt(time: number, callback: () => mixed): VirtualClock;

    removeAt(time: number, callback: () => mixed): VirtualClock;

    time: number;

    running: boolean;

    rate: number;

    minimum: number;

    maximum: number;

    loop: boolean;

}

Note that all methods return the called object to allow for method chaining.

Issues and contributing

If you have any issues with virtual-clock, first check the issue tracker to see whether it was already reported by someone else. If not, go ahead and create a new issue. Try to include as much information (version of the library, example code to reproduce) as possible.

If you want to contribute, feel free to open a pull request on GitHub!

License

virtual-clock is freely distributable under the terms of the MIT license.