-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimer.js
More file actions
118 lines (107 loc) · 3.38 KB
/
timer.js
File metadata and controls
118 lines (107 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
class TimeDisplay {
constructor({
container,
format = "hh:mm:ss:msms",
mode = "countdown", // countdown | stopwatch | clock
targetTime = null, // required for countdown
updateInterval = 10,
onTick = () => {},
}) {
this.container = typeof container === 'string' ? document.querySelector(container) : container;
this.format = format;
this.mode = mode;
this.targetTime = targetTime ? new Date(targetTime) : null;
this.updateInterval = updateInterval;
this.onTick = onTick;
this.running = false;
this.timeStamps = [];
this.init();
}
init() {
this.container.innerHTML = '';
const chars = this.format.replace(/[^a-z]/gi, '').split('');
this.formatSlots = this.format.split('').map(char => {
const el = document.createElement('div');
el.style.width = '80px';
el.style.height = '80px';
el.style.display = 'inline-flex';
el.style.alignItems = 'center';
el.style.justifyContent = 'center';
el.style.margin = '0 2px';
el.style.background = '#181818';
el.style.borderRadius = '0.5rem';
el.style.color = '#fff';
el.style.fontSize = '1.5rem';
el.innerText = char.match(/[a-z]/i) ? '0' : char;
this.container.appendChild(el);
return { type: char, el };
});
}
start() {
if (this.running) return;
this.running = true;
this.startTime = new Date();
this.interval = setInterval(() => this.update(), this.updateInterval);
}
pause() {
this.running = false;
clearInterval(this.interval);
}
resume() {
if (!this.running) {
this.running = true;
this.interval = setInterval(() => this.update(), this.updateInterval);
}
}
stop() {
this.pause();
this.startTime = null;
}
takeTime() {
const time = this._getTime();
this.timeStamps.push(time);
return time;
}
update() {
const time = this._getTime();
this.onTick(time);
const timeParts = this._formatTime(time);
this.formatSlots.forEach((slot, idx) => {
if (slot.type.match(/[a-z]/i)) {
slot.el.innerText = timeParts.shift() || '0';
}
});
}
_getTime() {
const now = new Date();
let diff;
if (this.mode === 'countdown') {
diff = Math.max(0, this.targetTime - now);
} else if (this.mode === 'stopwatch') {
diff = now - this.startTime;
} else if (this.mode === 'clock') {
return now;
}
return new Date(diff);
}
_formatTime(date) {
const parts = [];
for (const c of this.format) {
switch (c) {
case 'y': parts.push(date.getFullYear().toString()); break;
case 'M': parts.push((date.getMonth() + 1).toString().padStart(2, '0')); break;
case 'd': parts.push(date.getDate().toString().padStart(2, '0')); break;
case 'D': parts.push(date.toLocaleString('default', { weekday: 'long' })); break;
case 'm': parts.push(date.getMinutes().toString().padStart(2, '0')); break;
case 'h': parts.push(date.getHours().toString().padStart(2, '0')); break;
case 's': parts.push(date.getSeconds().toString().padStart(2, '0')); break;
case 'S': parts.push(Math.floor(date.getMilliseconds()).toString().padStart(3, '0')); break;
default: break;
}
}
return parts;
}
}
// Example usage:
// const display = new TimeDisplay({ container: '#timer', format: 'hh:mm:ss:S', mode: 'stopwatch' });
// display.start();