@coon/utils
Version:
214 lines (212 loc) • 6.46 kB
JavaScript
/*
* @Author: None
* @LastEditors: None
* @Date: 2020-11-04 22:52:50
* @LastEditTime: 2020-11-09 00:48:43
*/
/*
TODO: 全局只使用一个统一的时钟计时器,所有不同的计时器都由此分裂出来,如果支持使用worker.js 以及 wasm 来解决.
*/
/* 使用方法
timer.countdown({}).tick(rest=>{
})
*/
// 计时器状态
var timerStatus;
(function (timerStatus) {
timerStatus[timerStatus["finished"] = 0] = "finished";
timerStatus[timerStatus["suspend"] = 1] = "suspend";
timerStatus[timerStatus["progress"] = 2] = "progress";
})(timerStatus || (timerStatus = {}));
// 全局timestamps,请自行避免重复
/**
* @description: 生成guid
* @return string
*/
function guid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// 计时器静态库
const timer = {
timestamps: {},
timers: {},
/**
* @description: 计时器是否存在
* @param {string} name
* @return boolean
*/
exist(name) {
return !!this.timers[name];
},
/**
* @description: 获取当前相对时间戳
* @return number
*/
get now() {
return this.timestamp();
},
/**
* @description: 获取当前相对时间戳
* @return number
*/
timestamp() {
var _a;
return ((_a = performance === null || performance === void 0 ? void 0 : performance.now) === null || _a === void 0 ? void 0 : _a.call(performance)) || Date.now();
},
/**
* @description: 创建计时器
* @param {ITimerOption} opt
* @return Timer
*/
create(opt) {
return new Timer(opt);
},
/**
* @description: 倒计时,当start===end时会返回计数次数,当有name时优先获取已存在的。
* @param {countdownOption} opt
* @return Timer
*/
countdown(opt) {
var _a;
const defOpt = {
auto: true,
name: guid(),
interval: 1000,
start: 0,
end: 0,
};
if (typeof opt === 'number') {
opt = { start: opt };
}
else if (typeof opt === 'string') {
return this.timers[opt];
}
opt = Object.assign(Object.assign({}, defOpt), opt);
if (this.timers[opt.name]) {
// console.warn(`计时器${opt.name}已存在,将被覆盖!`)
(_a = this.timers[opt.name]) === null || _a === void 0 ? void 0 : _a.destroy();
}
const newTimer = this.create(opt);
this.timers[opt.name] = newTimer;
return opt.auto ? newTimer.start() : newTimer;
},
/**
* @description: 类似console.time
* @param {string} name
* @return number
*/
time(name = 'none') {
return this.timestamps[name] = this.timestamp();
},
/**
* @description: 类似console.timeLog,只返回,不输出
* @param {string} name
* @return number
*/
timeLog(name = 'none') {
return this.timestamp() - this.timestamps[name];
},
/**
* @description: 类似console.timeEnd,只返回,不输出
* @param {string} name
* @return number
*/
timeEnd(name = 'none') {
const r = this.timeLog(name);
delete this.timestamps[name];
return r;
}
};
// 计时器类
export class Timer {
constructor(opt) {
this.setTimeout = window.requestAnimationFrame.bind(window) || window.setTimeout.bind(window);
this.clearTimeout = window.cancelAnimationFrame.bind(window) || window.clearTimeout.bind(window);
this.hz = opt.hz || 1000;
this.status = timerStatus.finished; //0:未开始或已结束,1:正在进行中。
this.ticks = [];
this.timeups = [];
this.name = opt.name || guid();
this.begin = opt.begin || opt.start || 0;
this.end = opt.end || 0;
this.interval = opt.interval || 1000;
this.tid = null;
// 开始时间(相对)
this.startTime = 0;
if (this.hz) {
this.setTimeout = window.setTimeout.bind(window);
this.clearTimeout = window.clearTimeout.bind(window);
}
}
destroy() {
this.stop();
}
start() {
this.startTime = timer.timestamp();
const sign = Math.sign(this.begin - this.end);
let resetTime = this.startTime;
let times = 0;
// 定义计时器
// const globalTimer=new GlobalTimer()
// const myTimer=globalTimer.add({start:120}).get();
// myTimer.tick(value=>{
// this.ticks.forEach(tick => tick(value));
// console.log(value);
// }).timeup(()=>{
// this.stop();
// })
const tickTimer = (interval, timerTick = () => { }) => {
const curTime = timer.timestamp();
if (curTime - resetTime >= interval) {
times = Math.floor((curTime - this.startTime) / interval);
resetTime = curTime;
// timerTick();
this.setTimeout(timerTick);
}
this.tid = this.setTimeout(() => tickTimer(interval, timerTick), this.hz);
};
tickTimer(this.interval, () => {
const progress = this.begin - sign * times;
this.ticks.forEach(tick => tick(!sign ? times : progress));
if (progress < this.end + 1) {
this.timeups.forEach(timeup => timeup());
this.stop();
}
});
return this;
}
pause() {
if (this.status === timerStatus.finished)
return false;
this.status = timerStatus.suspend;
}
resume() {
this.status = timerStatus.progress;
}
stop() {
this.clearTimeout(this.tid);
this.status = timerStatus.finished;
}
on(name, fun) {
this[({ tick: 'ticks', timeup: 'timeups' })[name]].push(fun);
return this;
}
off(name, fun) {
const events = this[({ tick: 'ticks', timeup: 'timeups' })[name]];
const idx = events.findIndex(item => item === fun);
idx && events.splice(idx, 1);
return this;
}
tick(fun) {
this.ticks.push(fun);
return this;
}
timeup(fun) {
this.timeups.push(fun);
return this;
}
}
export default timer;