UNPKG

@nent/core

Version:

Functional elements to add routing, data-binding, dynamic HTML, declarative actions, audio, video, and so much more. Supercharge static HTML files into web apps without script or builds.

86 lines (85 loc) 3.15 kB
/*! * NENT 2022 */ import { debugIf, EventEmitter, throttle, } from '../../../services/common'; import { TIMER_EVENTS, } from '../../n-presentation/services/interfaces'; import { getTimeDetails } from '../../n-presentation/services/time'; /* It's a timer that uses the browser's animation frame to emit events at a given interval */ export class FrameTimer extends EventEmitter { /** * It creates a new timer object that will fire an event every `interval` milliseconds, and will fire * a final event when the timer has run for `durationSeconds` * @param {AnimationFrameProvider} provider - AnimationFrameProvider * @param {number} interval - The interval at which to emit the current time. * @param {number} durationSeconds - The duration of the timer in seconds. * @param getStart - () => number = performance.now, * @param {null | (() => void)} [onInterval=null] - a callback that will be called every interval * milliseconds. * @param {boolean} [debug=false] - boolean - if true, will log to console.log */ constructor(provider, interval, durationSeconds, getStart = performance.now, onInterval = null, debug = false) { super(); this.provider = provider; this.interval = interval; this.durationSeconds = durationSeconds; this.getStart = getStart; this.onInterval = onInterval; this.debug = debug; this.timer = 0; this.start = 0; this.durationMs = 0; this.durationMs = this.durationSeconds * 1000; debugIf(this.debug, `presentation-timer: starting timer w/ ${this.durationSeconds} duration`); this.currentTime = getTimeDetails(this.start, this.start, this.durationMs); if (this.interval > 0) this.debouncedInterval = throttle(this.interval, () => { this.timer = this.provider.requestAnimationFrame(current => { this.doInterval(current); }); }, true, true); else this.debouncedInterval = () => { this.timer = this.provider.requestAnimationFrame(current => { this.doInterval(current); }); }; } /** * We start the timer by setting the start time, and then we call the `doInterval` function */ begin() { if (this.timer) this.stop(); this.start = this.getStart(); this.currentTime = getTimeDetails(this.start, this.start, this.durationMs); this.provider.requestAnimationFrame(async (current) => { await this.doInterval(current); }); } /** * It stops the animation by cancelling the requestAnimationFrame */ stop() { this.provider.cancelAnimationFrame(this.timer); } async doInterval(time) { var _a; this.currentTime = getTimeDetails(this.start, time, this.durationMs); if (this.currentTime.ended) { this.stop(); this.emit(TIMER_EVENTS.OnEnd, this.currentTime); } else { this.emit(TIMER_EVENTS.OnInterval, this.currentTime); await this.debouncedInterval(); } (_a = this.onInterval) === null || _a === void 0 ? void 0 : _a.call(this); } /** * It stops the timer and removes all listeners. */ destroy() { this.stop(); this.removeAllListeners(); } }