A Digital-Analog Clock🕰 : Day 2 #JavaScript30

A Digital-Analog Clock🕰 : Day 2 #JavaScript30

👋 Hello people!

The title might sound like an oxymoron, but the blog is going to be quite clear. In this blog, we will be making a JavaScript Analog Clock. As its done digitally, I called it a Digital Analog Clock. To the end, we will be building a functional Clock that can be used on any webpage. Check the live demo and without wasting much "time" let's get started.

The starter files for this project can be found here.

🧠 HTML && CSS

The HTML for this project is nothing more than 7 lines. All we have is a div for clock-face and three nested divs inside for the hands of the clock. All three hands have a hand class in common and second-hand, min-hand and hour-hand respectively for each clock hand.

In CSS we have styling applied for .hand class. We need to add few more rules to make it work. For a clock to function we should be have moving hands. We shall use transform:rotate() property to achieve this. First let's try it out on seconds hand, apply this styling.

.second-hand{
    transform:rotate(30deg)
}

Well that should result something like below and its weird. We want our clock hands to rotate along its center not anywhere else.

clock.png

For that we need to transform the origin to the right most of the element. Along with that lets add a transition for smooth movement of clock hands.

.hand{
    transform-origin : 100%
    /* by default its 50%, making it 100 moves it to right */
    transition: all 0.05s ease-in-out;

}

Everything is fine, but the clock hands are pointing in the wrong direction ( left ). They should be facing north, this is important. transform: rotate(90deg); in .hand class should fix this. Remember, this 90deg shift is compensated later. That's pretty much the HTML and Styling part of it.

🚴 Approach

Before heading to JS, let's see how we are going to implement this. Our clock needs to display the exact time of the internet clock. For that, we grab the date object in a variable from which we can get seconds, minutes and hours. Once these values are obtained they should be converted to degrees, so that we can transform:rotate() clock hands by that amount of degrees.

💛 JavaScript

To start with, we querySelect three classes .second-hand, .min-hand and .hour-hand in to individual variables.

const secondHand = document.querySelector('.second-hand')
const minuteHand = document.querySelector('.min-hand')
const hourHand = document.querySelector('.hour-hand')

Next, declare a function setDate() , grab the date object as said before. But we don't need complete date object, it has lot of information. All we want is seconds , minutes and hours values.

function setDate() {
    const now = new Date();

    const seconds = now.getSeconds();

    const minutes = now.getMinutes();

    const hours = now.getHours();
}

Now, we convert this seconds into degrees, as the transform:rotate(_deg) accepts only degrees. For each second we update the .second-hand class with the new degree calculated. Let's see how to do this for seconds and its quite similar for minutes and hours hands too. As the second hand moves 60 positions to complete one revolution we get, secondsDegrees = ((seconds / 60) * 360). This calculation will lag by 90 degrees. If you remember in CSS we have added a style to rotate all hands by 90deg, that should be added here as well. The obtained degrees value should be updated with the .second-hand. This operation needs to happen every second. We use setInterval function to achieve that.

function setDate() {
    const now = new Date();

    const seconds = now.getSeconds();
    const secondsDegrees = ((seconds / 60) * 360) + 90;
    secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
}
setInterval( setDate,1000)
// the second argument expects time in milliseconds.

We are almost to the end. These steps have to be performed for minutes and hours hands as well. Hours hand has 12 positions, values vary a bit over there. To the end, the function looks like below.

function setDate() {
    const now = new Date();

    const seconds = now.getSeconds();
    const secondsDegrees = ((seconds / 60) * 360) + 90;
    secondHand.style.transform = `rotate(${secondsDegrees}deg)`;

    const minutes = now.getMinutes();
    const minutesDegrees = (( minutes / 60)*360) + 90;
    minuteHand.style.transform = `rotate(${minutesDegrees}deg)`;

    const hours = now.getHours();
    const hoursDegrees = ((hours/12)*360)+ 90;
    hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}
setInterval(setDate, 1000)

If everything is done well, your clock should be ticking by now. If it doesn't, not to worry, even the dead clock is right twice a day. Just kidding it should work fine.

Limitations of this clock

You might have observed some, issues by now. If not let me list them.

  • The minutes & hours hand sticks to its position till the next updated value arrives. What do I mean by this? In a real clock, all three clocks move every second. The movement in minutes and hours hand is so subtle that we don't notice it. This clock fails to do it.
  • The second's hand refreshes when it reaches 60 seconds mark, which makes a little weird animation.
  • The clock tries to catch up when moving to another tab in the browser and coming back. This is because the Browser tries to throttle Javascript when you're not actively viewing that tab.

    The first two issues can be fixed and I have made another clock earlier addressing both of them. It can be found here the script.js is very well documented, it's easy to understand.

🤝Thank you for reading till the end.

That's all for today. Feel free to drop a comment, if anything can be done better or any more features can be added. See you in my next blog. Until then,

Bye !

References

The course, from which the project is picked.

MDN: Date object

MDN: setInterval