minsky-kit
Version:
Kit of components for MINSKY web agency
234 lines (181 loc) • 6.03 kB
JavaScript
// imports
import EventDispatcher from './EventDispatcher';
// private static properties
// class definition
export default class Ticker extends EventDispatcher {
// constructor
constructor (args = {}, objectName = 'Ticker') {
// call super
super(args, objectName);
// set properties
this.timeout = (args.timeout) ? processTimeoutArgument(args.timeout) : 0;
this.isInterval = args.isInterval || false;
this.autoDestroy = (typeof args.autoDestroy === 'boolean') ? args.autoDestroy : false;
this.autoStart = (typeof args.autoStart === 'boolean') ? args.autoStart : false;
this.data = args.data || {};
this.useTimeout = args.useTimeout || false;
this.autoReset = args.autoReset || false;
// set system properties
this.timerId = 0;
this.time = args.time || 0;
this.lastTick = 0;
// autostart
if (args.autoStart) this.start();
// call super initializer
super.initialize(args);
// autostart
if (this.autoStart) this.start();
}
// methods
start (reset = false) {
// reset if required
if (reset) this.reset();
// only start when already running
if (!this.running) {
// request frame and keep id
this.id = (this.useTimeout) ? setTimeout(this.tick.bind(this)) : requestAnimationFrame(this.tick.bind(this));
// keep currnet time
this.lastTick = performance.now();
// dispatch start event
this.dispatch('start');
}
}
stop (reset = false) {
if (this.running) {
// cancel animation request
(this.useTimeout) ? clearTimeout(this.id) : cancelAnimationFrame(this.id);
// reset id
this.id = 0;
// dispatch stop event
this.dispatch('stop');
}
// reset time if requested
if (reset) this.reset();
}
reset (stop = false) {
// reset time
this.time = 0;
// dispatch reset event
this.dispatch('reset');
// stop if requested
if (this.id && stop) this.stop();
}
tick (force) {
// cancel if not running
// if (!this.dispatch) return; // check if tick is ran after instance is destroyed
if (!force && !this.running) return;
// get current time
const currentTime = performance.now();
let requestTick = true;
// update time
this.time += currentTime - this.lastTick;
// dispatch tick
this.dispatch('tick');
// if time passed timout => do stuff
if (this.time >= this.timeout) {
if (this.isInterval) {
this.reset();
this.dispatch('interval', this.data);
}
else {
this.stop(this.autoReset);
this.dispatch('timeout', this.data);
requestTick = false;
if (this.autoDestroy) this.destroy();
}
}
// request new frame
if (requestTick) this.id = requestAnimationFrame(this.tick.bind(this));
// keep current time for next tick
this.lastTick = currentTime;
}
destroy () {
// dispatch event
this.dispatch('destroy');
// ensure stop
this.stop();
// remove all references
this.id = this.timeout = this.callback = this.isInterval = this.autoDestroy = this.time = this.lastTick = null;
// destroy super
super.destroy();
}
// getters & setters
get running () {
return !!this.id;
}
get progress () {
return this.time / this.timeout;
}
// statics
}
// argument processor exact copy of v2.2.0's
function processTimeoutArgument (str) {
if (!Number.isNaN(str)) {
return str;
}
if (str.indexOf(':')) { // hh:mm:ss.msms
const parts = str.split(':');
const total = parts.length - 1;
return (parseFloat(parts[total]) + (parseInt(parts[total - 1]) * 60) + ((total > 1) ? parseInt(parts[total - 2]) * 3600 : 0)) * 1000;
}
// css way: 2ms, 2s, 2min, 2h, 2milliseconds, 2seconds, ...
return parseFloat(str) * getMsFactorFromString(str);
}
// time formatting from v2
function getMsFactorFromString (str) {
let result;
switch (true) {
case (str.indexOf('ms') > -1 || str.indexOf('milliseconds') > -1):
result = 1; // 1
break;
case (str.indexOf('s') > -1 || str.indexOf('seconds') > -1):
result = 1000; // 1 * 1000
break;
case (str.indexOf('min') > -1 || str.indexOf('minutes') > -1):
result = 60000; // 1 * 1000 * 60
break;
case (str.indexOf('h') > -1 || str.indexOf('hr') > -1 || str.indexOf('hour') > -1):
result = 3600000; // 1 * 1000 * 60 * 60
break;
default:
}
return result;
}
export function quickTick (...args) {
// different formats
let timeout;
let callback;
let isInterval = false;
let data;
if (typeof args[0] === 'number') {
timeout = args.shift();
// shift it
}
if (typeof args[0] === 'object') {
timeout = timeout || 0;
data = args[0];
if (typeof args[1] === 'function') callback = args[1];
}
else if (typeof args[0] === 'function') {
callback = args[0];
data = {};
timeout = timeout || 0;
}
if (typeof args[1] === 'boolean' || typeof args[2] === 'boolean' || typeof args[3] === 'boolean') {
isInterval = true;
}
// construct
const t = new Ticker({
timeout,
isInterval,
data,
});
// change additional properties
t.autoDestroy = true;
// add listeners
t.on(isInterval ? 'interval' : 'timeout', data, callback);
// start
t.start(true);
return t;
}
Ticker.quick = quickTick;