@nent/core
Version:
190 lines (184 loc) • 6.25 kB
JavaScript
/*!
* NENT 2022
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const index$1 = require('./index-1829aebc.js');
const index = require('./index-637e8c28.js');
const interfaces$1 = require('./interfaces-1da33056.js');
const state = require('./state-246c735d.js');
const interfaces = require('./interfaces-023ea612.js');
const time = require('./time-95d533f4.js');
const logging = require('./logging-37c154cf.js');
const promises = require('./promises-463f4e01.js');
require('./index-96f3ab3f.js');
/* It's a timer that uses the browser's animation frame to emit events at a given interval */
class FrameTimer extends index.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;
logging.debugIf(this.debug, `presentation-timer: starting timer w/ ${this.durationSeconds} duration`);
this.currentTime = time.getTimeDetails(this.start, this.start, this.durationMs);
if (this.interval > 0)
this.debouncedInterval = promises.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 = time.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$1) {
var _a;
this.currentTime = time.getTimeDetails(this.start, time$1, this.durationMs);
if (this.currentTime.ended) {
this.stop();
this.emit(interfaces.TIMER_EVENTS.OnEnd, this.currentTime);
}
else {
this.emit(interfaces.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();
}
}
const PresentationTimer = class {
constructor(hostRef) {
index$1.registerInstance(this, hostRef);
this.ready = index$1.createEvent(this, "ready", 7);
this.elapsed = 0;
/**
* To debug timed elements, set this value to true.
*/
this.debug = false;
/**
* Duration before the timer stops and raises
* the ended event (seconds). 0 = never
*/
this.duration = 0;
/**
* Interval in milliseconds to request
* between the getAnimationFrame. This
* affects the precision.
*/
this.interval = 200;
/**
* Display elapsed seconds
*/
this.display = false;
/**
* If set, disables auto-starting the timer
* on render. This will be removed if in a view,
* when the view is activated or when the start
* method is called.
*/
this.deferLoad = false;
this.now = () => performance.now();
}
get currentRoute() {
var _a;
const parent = this.el.closest('n-view-prompt') || this.el.closest('n-view');
if (parent)
return parent.route;
return ((_a = state.state.router) === null || _a === void 0 ? void 0 : _a.exactRoute) || null;
}
/**
* Begin the timer. This is called automatically
* by the presentation element.
*/
async begin() {
this.timer.begin();
}
/**
* Stop the timer.
*/
async stop() {
this.timer.stop();
}
componentWillLoad() {
this.timer = new FrameTimer(window, this.interval, this.duration, () => this.now(), () => {
this.elapsed = this.timer.currentTime.elapsedSeconds;
}, this.debug);
}
render() {
return index$1.h(index$1.Host, null, this.display ? this.elapsed : null);
}
componentDidLoad() {
var _a, _b;
this.ready.emit(true);
if (this.currentRoute) {
logging.debugIf(this.debug, `n-presentation-timer: syncing to route ${this.currentRoute.path}`);
if ((_b = (_a = this.currentRoute) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.isExact) {
this.timer.begin();
}
this.navigationSubscription = index.eventBus.on(interfaces$1.ROUTE_EVENTS.RouteChanged, () => {
var _a, _b;
if ((_b = (_a = this.currentRoute) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.isExact) {
this.timer.begin();
}
else {
this.timer.stop();
}
});
}
else {
this.timer.begin();
}
}
disconnectedCallback() {
var _a;
this.timer.destroy();
(_a = this.navigationSubscription) === null || _a === void 0 ? void 0 : _a.call(this);
}
get el() { return index$1.getElement(this); }
};
exports.n_presentation_timer = PresentationTimer;