UNPKG

dev-timer

Version:

Super interval timer that can handle multiple timers simulteanously

427 lines (426 loc) 16.1 kB
"use strict"; // A nice, easy to use, timer, that provides powerful features // Made with ❤️ by Gaskam -> Gaskam.com var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var _Timer_instances, _Timer_currentTimeout, _Timer_specialEvents, _Timer_timelineInsert, _Timer_registerEvent, _Timer_unregisterEvent, _Timer_registerAllEvents; Object.defineProperty(exports, "__esModule", { value: true }); exports.Timer = void 0; class Timer { // Works fine, but rounds time down(1999ms -> 1s) /** * Function to help you format time * @param time - A time in ms * @param format - The format, accepted formats are: 'ms', 'ss', 'mm', 'hh', 'dd', 'ww', 'mo', 'yy', 'yyyy', and you may use multiple formats at once, for example: 'hh:mm:ss' * @returns The formatted time */ static formatTime(time, format) { if (format === undefined) return `${time}`; format = format.toLowerCase(); if (format === "ms") return `${time}`; if (time < 0) time = 0; if (format.includes("yyyy")) { let tmp = Math.floor(time / 31536000000); format = format.replace("yyyy", tmp); time -= tmp * 31536000000; // 31 536 000 000 ms = 1 year of 365 days } else if (format.includes("yy")) { let tmp = Math.floor(time / 31536000000); format = format.replace("yy", String(tmp).slice(-2)); time -= tmp * 31536000000; // 31 536 000 000 ms = 1 year of 365 days } if (format.includes("mo")) { let tmp = Math.floor(time / 2592000000); if (tmp < 10) tmp = "0" + tmp; format = format.replace("mo", tmp); time -= tmp * 2592000000; // 2 592 000 000 ms = 1 month of 30 days } if (format.includes("ww")) { let tmp = Math.floor(time / 604800000); format = format.replace("ww", tmp); time -= tmp * 604800000; // 604 800 000 ms = 1 week } if (format.includes("dd")) { let tmp = Math.floor(time / 86400000); if (tmp < 10) tmp = "0" + tmp; format = format.replace("dd", tmp); time -= tmp * 86400000; // 86 400 000 ms = 1 day } if (format.includes("hh")) { let tmp = Math.floor(time / 3600000); if (tmp < 10) tmp = "0" + tmp; format = format.replace("hh", tmp); time -= tmp * 3600000; // 3 600 000 ms = 1 hour } if (format.includes("mm")) { let tmp = Math.floor(time / 60000); if (tmp < 10) tmp = "0" + tmp; format = format.replace("mm", tmp); time -= tmp * 60000; // 60 000 ms = 1 minute } if (format.includes("ss")) { let tmp = Math.floor(time / 1000); if (tmp < 10) tmp = "0" + tmp; format = format.replace("ss", tmp); time -= tmp * 1000; // 1 000 ms = 1 second } if (format.includes("ms")) { let tmp = Math.floor(time); if (tmp < 100) tmp = "0" + tmp; else if (tmp < 10) tmp = "00" + tmp; else if (tmp < 1) tmp = "000"; format = format.replace("ms", tmp); } return format; } formatTime(time, format) { return Timer.formatTime(time, format); } // Works fine, you should only provide a string with a number and a unit(ex: 1s, 1m, 1h, 1d, 1w, 1mo, 1y) /** * Ensures that the time is in ms, and if not, converts it to ms * @param time - The time to convert, if string, it must be in the format: 'number + unit', ex: '1s', '1m', '1h', '1d', '1w', '1mo', '1y' * @throws {Error} If the time string is not in the correct format * @returns The time converted to ms */ static toMs(time) { try { if (typeof time === "number") { return time; } if (typeof time === "string") { time = time.toLowerCase(); if (time.includes("ms")) return Number(time.replace("ms", "")); if (time.includes("ss")) return Number(time.replace("ss", "")) * 1000; if (time.includes("mm")) return Number(time.replace("mm", "")) * 60000; if (time.includes("hh")) return Number(time.replace("hh", "")) * 3600000; if (time.includes("dd")) return Number(time.replace("dd", "")) * 86400000; if (time.includes("ww")) return Number(time.replace("ww", "")) * 604800000; if (time.includes("mo")) return Number(time.replace("mo", "")) * 2592000000; if (time.includes("yy")) return Number(time.replace("yy", "")) * 31536000000; if (time.includes("s")) return Number(time.replace("s", "")) * 1000; if (time.includes("m")) return Number(time.replace("m", "")) * 60000; if (time.includes("h")) return Number(time.replace("h", "")) * 3600000; if (time.includes("d")) return Number(time.replace("d", "")) * 86400000; if (time.includes("w")) return Number(time.replace("w", "")) * 604800000; if (time.includes("y")) return Number(time.replace("y", "")) * 31536000000; } } catch (e) { throw `Timer.js: unable to convert time to ms: ${e}`; } return 0; } toMs(time) { return Timer.toMs(time); } /** * Create a new Timer with a duration * @constructor * @param duration - The duration of the timer, in ms */ constructor(duration) { _Timer_instances.add(this); this.beginTime = null; this.pauseAmount = 0; this.pauseBegin = null; this.paused = true; this.callbacks = []; this._timeline = []; _Timer_currentTimeout.set(this, -1); _Timer_specialEvents.set(this, { start: [], stop: [], end: [], reset: [], }); this.duration = duration; } // Timer length functions // Works fine(the 4 ones below) /** * Set the duration of the timer * @param duration - The duration of the timer, in ms */ setDuration(duration) { this.duration = this.toMs(duration); } /** * Add a duration to the timer duration, or removes it if the duration is negative * @param duration - The duration to add to the timer, in ms */ addDuration(duration) { this.duration += this.toMs(duration); } /** * Sets the running time of the timer(overrides the current running time) * @param duration - The new running time of the timer */ setRunningTime(duration) { this.pauseAmount = this.toMs(duration); this.beginTime = Date.now(); } /** * Add a duration to the running time of the timer, or removes it if the provided duration is negative * @param duration - The duration to add to the running time of the timer, in ms */ addRunningTime(duration) { this.pauseAmount += this.toMs(duration); } // Timer execution functions /** * Gives the current running time of the timer */ get runningTime() { if (this.paused) return this.pauseAmount; return this.pauseAmount + (Date.now() - this.beginTime); } /** * Gives the current time left of the timer */ get timeLeft() { return this.duration - this.runningTime; } get ended() { return this.timeLeft < 1; } /** * Starts the timer. * Triggers the onStart event. * @returns Returns true if the timer was paused, false if not */ start() { if (this.paused) { this.paused = false; this.beginTime = Date.now(); if (this.pauseBegin) { let tmp1 = this.pauseBegin, tmp2 = this.beginTime; this._timeline.forEach(function (tmp) { tmp[0] += tmp2 - tmp1; }); } this.checkEvents(); this.dispatchSpecialEvent("start"); return true; } return false; } /** * Stops/pauses the timer. * Triggers the onStop event. * @returns Returns true if the timer was running, false if not */ stop() { if (!this.paused) { let tmp = Date.now(); this.pauseBegin = tmp; this.paused = true; this.pauseAmount += tmp - this.beginTime; this.dispatchSpecialEvent("stop"); return true; } return false; } /** * Resets the timer to its initial state but keeps the events. * If you want to reset completely, just create a new timer. * Trigger the onReset event. */ reset() { this.pauseAmount = 0; this.paused = true; this.beginTime = null; __classPrivateFieldGet(this, _Timer_instances, "m", _Timer_registerAllEvents).call(this); this.dispatchSpecialEvent("reset"); } // Special Events functions /** * Add a callback to the onStart event, you may add multiple ones */ set onStart(callback) { __classPrivateFieldGet(this, _Timer_specialEvents, "f").start.push(callback); } /** * Add a callback to the onStop event, you may add multiple ones */ set onStop(callback) { __classPrivateFieldGet(this, _Timer_specialEvents, "f").stop.push(callback); } /** * Add a callback to the onReset event, you may add multiple ones */ set onEnd(callback) { __classPrivateFieldGet(this, _Timer_specialEvents, "f").end.push(callback); } /** * Add a callback to the onReset event, you may add multiple ones */ set onReset(callback) { __classPrivateFieldGet(this, _Timer_specialEvents, "f").reset.push(callback); } /** * Dispatches one of the special events * @param event - The event to dispatch */ dispatchSpecialEvent(event) { __classPrivateFieldGet(this, _Timer_specialEvents, "f")[event].forEach((el) => el()); } /** * Destroys all the callbacks of a special event * @param event - The event type to destroy */ destroySpecialEvent(event) { __classPrivateFieldGet(this, _Timer_specialEvents, "f")[event] = []; } /** * Destroys all the callbacks of all the special events */ destroyAllSpecialEvents() { __classPrivateFieldSet(this, _Timer_specialEvents, { start: [], stop: [], reset: [], end: [] }, "f"); } // Callbacks functions /** * Add an event listener, to trigger at a specific interval of time * @param event - The interval of time the event should be triggered at * @param callback - The callback to trigger */ addEventListener(event, callback) { __classPrivateFieldGet(this, _Timer_instances, "m", _Timer_registerEvent).call(this, event); this.callbacks.push([event, callback]); this.checkEvents(); } /** * Removes all the callbacks of a specific time interval * @param event - The event to remove */ removeEventListener(event) { this.callbacks = this.callbacks.filter((el) => el[0] != event); __classPrivateFieldGet(this, _Timer_instances, "m", _Timer_unregisterEvent).call(this, event); } /** * Triggers all the callbacks of a specific time interval * @param event - The interval of the callbacks to trigger * @returns The amount of callbacks triggered */ dispatchEvent(event) { let tmp = 0; this.callbacks.forEach((el) => { if (el[0] == event) { el[1](); tmp++; } }); return tmp; } // Events checkEvents() { if (this.ended) this.timerEndRoutine(); else if (this.paused != true) { while (this._timeline.length && this._timeline[0][0] <= Date.now()) { this.dispatchEvent(this._timeline[0][1]); let tmp = this._timeline.shift(); __classPrivateFieldGet(this, _Timer_instances, "m", _Timer_registerEvent).call(this, tmp[1]); } if (this.timeLeft <= 0) { this.stop(); return; } clearTimeout(__classPrivateFieldGet(this, _Timer_currentTimeout, "f")); if (this._timeline.length) __classPrivateFieldSet(this, _Timer_currentTimeout, setTimeout(this.checkEvents.bind(this), this._timeline[0][0] - Date.now()), "f"); else __classPrivateFieldSet(this, _Timer_currentTimeout, setTimeout(this.checkEvents.bind(this), this.timeLeft), "f"); } } timerEndRoutine() { this.stop(); this.callbacks.forEach((event) => { event[1](); }); this.dispatchSpecialEvent("end"); } } exports.Timer = Timer; _Timer_currentTimeout = new WeakMap(), _Timer_specialEvents = new WeakMap(), _Timer_instances = new WeakSet(), _Timer_timelineInsert = function _Timer_timelineInsert(date, name) { let i = 0; try { while (date >= this._timeline[i][0]) { if (name === this._timeline[i][1]) break; i++; } } catch (e) { i = this._timeline.length; } this._timeline.splice(i, 0, [date, name]); }, _Timer_registerEvent = function _Timer_registerEvent(event) { if (Array.isArray(event)) event = event[0]; if (event > 0) { let now = Date.now(); let timeLeft = this.timeLeft; let nextTime = (timeLeft % event) + now; if (nextTime == now) nextTime = event + now; if ((timeLeft + nextTime - now) >= now + this.duration) return false; __classPrivateFieldGet(this, _Timer_instances, "m", _Timer_timelineInsert).call(this, nextTime, event); return true; } return false; }, _Timer_unregisterEvent = function _Timer_unregisterEvent(event) { if (Array.isArray(event)) event = event[0]; if (event > 0) { this._timeline = this._timeline.filter(tmp => tmp[1] !== event); return true; } return false; }, _Timer_registerAllEvents = function _Timer_registerAllEvents() { this._timeline = []; this.callbacks.forEach((tmp) => { __classPrivateFieldGet(this, _Timer_instances, "m", _Timer_registerEvent).call(this, tmp[0]); }); };