Skip to content

Commit 464bc4c

Browse files
authored
Merge pull request #84 from mateowatson/feature/83-javascript-timer-lags-behind
refactored timer to use requestAnimationFrame
2 parents de74024 + 6b47064 commit 464bc4c

File tree

2 files changed

+71
-56
lines changed

2 files changed

+71
-56
lines changed

public/assets/js/controllers/timer_controller.js

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,65 +5,61 @@ export default class extends Controller {
55

66
connect() {
77
// start the automatic timer display
8-
this.startTimer();
8+
const timer = requestAnimationFrame(this.loop.bind(this));
9+
this.data.set('timer', timer);
10+
11+
// keep a reference to the start time
12+
const startTime = Date.now();
13+
this.data.set('start-time', startTime);
914

1015
// hide the refresh link
1116
this.refreshTarget.style.display = 'none';
1217
}
1318

14-
startTimer() {
15-
// read initial time
16-
let initialTime = this.data.get('elapsed');
17-
initialTime = initialTime.split(':');
18-
initialTime = initialTime.map(number => {
19-
return parseInt(number);
20-
});
21-
22-
// create a diy time object
23-
this.currentTime = {
24-
h: initialTime[0],
25-
m: initialTime[1],
26-
s: initialTime[2]
27-
};
28-
29-
// start timer loop
30-
this.timer = setInterval(() => {
31-
this.incrementTimer();
32-
this.updateDisplay();
33-
}, 1000);
19+
disconnect() {
20+
// stop the animation loop
21+
const timer = parseInt(this.data.get('timer'));
22+
cancelAnimationFrame(timer);
3423
}
3524

36-
incrementTimer() {
37-
this.currentTime.s++;
38-
39-
if (this.currentTime.s > 59) {
40-
this.currentTime.s = 0;
41-
this.currentTime.m++;
25+
displayElapsedTime(ms) {
26+
// convert the elapsed milliseconds into seconds
27+
const totalInSeconds = ms / 1000;
28+
// how many seconds to display
29+
const s = parseInt(totalInSeconds % 60);
30+
// how many minutes to display
31+
const m = Math.floor(totalInSeconds / 60) % 60;
32+
// how many hours to display
33+
const h = Math.floor(totalInSeconds / 60 / 60);
4234

43-
if (this.currentTime.m > 59) {
44-
this.currentTime.m = 0;
45-
this.currentTime.h++;
46-
}
47-
}
35+
// convert to the string format: HH:MM:SS
36+
const displayTime = `${this.pad(h)}:${this.pad(m)}:${this.pad(s)}`;
37+
// display the string
38+
this.elapsedTarget.innerHTML = displayTime;
4839
}
4940

50-
updateDisplay() {
51-
const hours = this.displayNumber(this.currentTime.h);
52-
const minutes = this.displayNumber(this.currentTime.m);
53-
const seconds = this.displayNumber(this.currentTime.s);
54-
const elapsed = `${hours}:${minutes}:${seconds}`;
55-
56-
this.elapsedTarget.innerHTML = elapsed;
57-
this.data.set('elapsed', elapsed);
41+
loop(ms) {
42+
// the loop keeps running itself; replace the reference each time
43+
const timer = requestAnimationFrame(this.loop.bind(this));
44+
this.data.set('timer', timer);
45+
46+
// get the elapsed time in milliseconds
47+
const now = Date.now();
48+
const startTime = parseInt(this.data.get('start-time'));
49+
const elapsed = now - startTime;
50+
51+
// convert to human friendly format and display it
52+
this.displayElapsedTime(elapsed);
5853
}
5954

60-
displayNumber(number) {
61-
number = number.toString();
55+
// convert number to string and ensure it is at least two characters long
56+
pad(num) {
57+
num = num.toString();
6258

63-
if (number.length < 2) {
64-
number = '0' + number;
59+
if (num.length < 2) {
60+
num = `0${num}`;
6561
}
6662

67-
return number;
63+
return num;
6864
}
6965
}

public/package-lock.json

Lines changed: 30 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)