Analog Clock with JavaScript
Share on

Analog Clock with JavaScript

Oh hi there 👋 dont miss out by subscribing.

Today, we will again use the Power of Scalable Vector Graphics (SVG) to build something awesome: An analog clock. By analog, I mean Watch with hands, if that makes sense.

The clock will look like this.

HTML for the Analog Clock

Let’s start by reviewing the Markup for our little Website. We mostly have the HTML Boilerplate; we just add a script and link tag to your JavaScript and CSS files. We also create an SVG with a view box of -50 -50 100 100, which means elements placed at 0 0 will be in the middle, like the two circles we add within our SVG.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Clock</title>

    <script defer src="clock.js"></script>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <svg viewBox="-50 -50 100 100">
        <circle cx="0" cy="0" r="49.5" class="clock" id="clock"></circle>
        <circle cx="0" cy="0" r="2" class="clock-joint" id="clock"></circle>
    </svg>
</body>
</html>

CSS for the Analog Clock

Next, let’s go over the CSS. We start by simply setting box-sizing to border-box for every element; this makes working with padding and margin much easier.

* {
    box-sizing: border-box;
}

Then we make it so the Body has no margin, a little padding, and it is as high as the Viewport.

body {
    height: 100vh;
    margin: 0;
    padding: 2rem;
    background-color: hsl(0, 0%, 13%);
}

After that, we make it so the SVG, which will be the clock, can’t be wider or higher than the screen, but we want it to grow as much as possible. To also center it, we can add margin: auto.

.clock {
    box-shadow: 0 0 5px hsl(0, 0%, 0%);
    stroke: hsl(0, 0%, 30%);
    fill: hsl(0, 0%, 20%);
}

Lastly, we set the Fill and stroke colors for the circles. Stroke is like the border, and fill is the background color.

.clock {
    stroke: hsl(0, 0%, 30%);
    fill: hsl(0, 0%, 20%);
}

.clock-joint {
    fill: hsl(0, 0%, 90%);
}

JavaScript for the Analog Clock

In the JavaScript file, we start by getting references for several DOM Nodes that we will need later.

const clockNode = document.getElementById('clock')
const svgNode = document.querySelector('svg')
const handsContainer = document.getElementById('hands')

Continuing, we create the lines that run along the edge of the clock: the seconds, minutes, and hours. To do this, we use the addHand function that we go over later.

const numTimes = 60
for (i = 0; i < numTimes; i++) {
    const handRotationOffset = 360 / numTimes

    if ((i % 15 == 0 || i == 0) && numTimes != i + 1) {
        console.log('15er');
	        addHand({ rotation: i * handRotationOffset, color: 'hsl(0, 0%, 80%)', width: 15 })
    } else if (i % 5 == 0 && numTimes != i + 1) {
        console.log('5er');
        addHand({ rotation: i * handRotationOffset, color: 'hsl(0, 0%, 40%)', width: 12 })
    }
    else {
        addHand({ rotation: i * handRotationOffset, color: 'hsl(0, 0%, 30%)' })
    }
}

After that, we create the actual hands that indicate the seconds, minutes, and hours. We save these for later.

const secondHand = addHand({ color: 'hsl(0, 0%, 90%)', width: 40, x: 0, height: 1 })
const minuteHand = addHand({ color: 'hsl(0, 0%, 90%)', width: 25, x: 0, height: 1.5 })
const hourHand = addHand({ color: 'hsl(0, 0%, 90%)', width: 15, x: 0, height: 2 })

Lastly, we create a function called render, which will check the time and adjust the hands appropriately. We use the requestAnimationFrame function for rerendering the clock automatically but also for Performance.

render()
function render() {
    const time = new Date()

    const secondsDegrees = (time.getSeconds() * 6) + 90;
    const minutesDegrees = (time.getMinutes() * 6) - 90;
    const hoursDegrees = (time.getHours() * 30) - 90;
    
    secondHand.style.transform = `rotate(${secondsDegrees}deg)`
    minuteHand.style.transform = `rotate(${minutesDegrees}deg)`
    hourHand.style.transform = `rotate(${hoursDegrees}deg)`

    requestAnimationFrame(render)
}

addHand Function

Below, you also see the Implementation of the Add Hand. As you see, we use the g as a pivot to rotate the rect to the correct Position.

function addHand({ width = 10, height = 1.5, x = 35, rotation = 0, color = 'black' } = {}) {
    const handNode = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
    const handNodeGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')

    handNode.setAttribute('width', width)
    handNode.setAttribute('height', height)
    handNode.setAttribute('x', x)
    handNode.setAttribute('fill', color)

    handNodeGroup.style.transform = `rotate(${rotation - 90}deg)`
    handNodeGroup.style.transformOrigin = `0px ${height / 2}px`
    handNodeGroup.style.translate = `0px -${height / 2}px`

    handNodeGroup.appendChild(handNode)

    svgNode.appendChild(handNodeGroup)

    return handNodeGroup
}

Conclusion

So that’s it. I hope you had a good time and that you learned something!

Visit the Demo.

No Comments

No Comments Found, you Could be the First ...

Leave a Reply

Your email address will not be published. Required fields are marked *

Other Posts you may like ...

Simple quiz in the console with python.

Simple quiz in the console with python.

Custom Svelte Store

Custom Svelte Store

Simple spreadsheet app with vue

Simple spreadsheet app with vue

To Top
© 2022 - 2024 Maxim Mäder
Enthusiast Shui Theme Version 44