Let’s build an analog chronograph watch with VanillaJS + HTML pt.2
Tung V

Continuing from the pt.1 https://medium.com/@whoz_/lets-build-an-analog-chronograph-watch-with-vanillajs-html-pt-1-ef28ce9edf63, in this part, we will focus on the sub-dials and the chronograph function.

You can find the source code here at: https://github.com/tungvotan/chronograph-analog-watch

Recap:

We already have this up and running as a basic analog watch with

  • Basic UI

  • The movement

Now we can get to the real chronograph thingy.

Add the sub-second dial

Maybe you already know that the standard chronograph will have a small sub-dial for the real-time second hand, while the red second hand from the design, most of the time, will stay at the 12-hour mark and only run when the timer starts.

The real second hand movement in the red circle.

Let’s add it.

In the HTML file we add this to the dial

1
2
3
4
5
6
7
8
9
<div class="dial">
<div class="hand hour-hand"></div>
<div class="hand minute-hand"></div>
<div class="hand main-second-hand"></div>
<!-- Sub-dial for Real Time Seconds -->
<div class="sub-dial real-time-second-dial">
<div class="hand sub-second-hand"></div>
</div>
</div>

And in CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Sub-dials */
.sub-dial {
position: absolute;
border: 2px solid #000;
border-radius: 50%;
width: 70px;
height: 70px;
top: 50%;
left: 25%;
transform: translate(-50%, -50%);
}

.sub-second-hand {
position: absolute;
bottom: 50%;
left: 50%;
width: 1px;
height: 45%;
background-color: black;
transform-origin: bottom;
}

Now we have this

Okay, so let’s move the second-hand movement to the sub-dial one.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const subSecondHand = document.querySelector('.sub-second-hand');

// Start the real-time second hand
function startRealTimeSecondHand() {
const realTime = new Date();
const ms = realTime.getMilliseconds();
const roundedSecondResult = Math.round((ms / 1000) * 4) / 4;

const seconds = realTime.getSeconds();
const realSecondDegrees = ((seconds + roundedSecondResult) / 60) * 360;
// replace the second hand movement here
subSecondHand.style.transform = `rotate(${realSecondDegrees}deg)`;
const minutes = realTime.getMinutes();
const minuteDegrees = ((minutes + seconds / 60) / 60) * 360;
minuteHand.style.transform = `rotate(${minuteDegrees}deg)`;
const hours = realTime.getHours();
const hourDegrees = ((hours + minutes / 60) / 12) * 360;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
}

Perfect!

The timer function

Now, the goal is to have the red second-hand start as a timer function.

Let’s add the basic control to HTML

1
2
3
4
5
6
<!-- Controls for the Chronograph -->
<div class="controls">
<button id="start-btn">Start</button>
<button id="stop-btn">Stop</button>
<button id="reset-btn">Reset</button>
</div>

Here, we add some more JS code to the control buttons

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
let intervalChronograph;
let chronographSeconds = 0;
const startButton = document.getElementById('start-btn');
const stopButton = document.getElementById('stop-btn');
const resetButton = document.getElementById('reset-btn');

// Start the chronograph timer
startButton.addEventListener('click', () => {
if (!intervalChronograph) {
intervalChronograph = setInterval(startChronograph, 250);
}
});

// Stop the chronograph timer
stopButton.addEventListener('click', () => {
clearInterval(intervalChronograph);
intervalChronograph = null;
});

// Reset the chronograph timer
resetButton.addEventListener('click', () => {
clearInterval(intervalChronograph);
intervalChronograph = null;
chronographSeconds = 0;
updateHands();
});

// Chronograph function for main second hand
function startChronograph() {
chronographSeconds++;
if (chronographSeconds / 4 === 60) {
chronographSeconds = 0;
}
updateHands();
}

function updateHands() {
const secondDegrees = (chronographSeconds / 60 / 4) * 360;
mainSecondHand.style.transform = `rotate(${secondDegrees}deg)`;
}

Let’s check it out

It’s working!

Let’s add the minute timer dial

This part is to add the second sub dial to indicate the elapsed minutes.

It’s similar to the subsecond dial, so I skipped the HTML and CSS parts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Chronograph function for main second hand
function startChronograph() {
chronographSeconds++;
if (chronographSeconds / 4 === 60) {
chronographSeconds = 0;
chronographMinutes++;
}

if (chronographMinutes === 30) {
chronoMinuteMinutes = 0;
}

updateHands();
}

function updateHands() {
const secondDegrees = (chronographSeconds / 60 / 4) * 360;
const chronoMinuteDegree = (chronographMinutes / 30) * 360;
mainSecondHand.style.transform = `rotate(${secondDegrees}deg)`;
chronoMinuteHand.style.transform = `rotate(${chronoMinuteDegree}deg)`;
}

Now we have the watch looked exactly the same as my real watch right? xD

The end

Since I’m looking for a new software engineer position, this is good practice for front-end interview questions, where I can demonstrate my knowledge of HTML, CSS, and pure Javascript skills.

Maybe I can make a newer version with proper state management in the near future. If you have any suggestions to make this better, please let me know!

Thank you so much for following up on this topic.
Have a nice nice new day!