Analog Clock in JavaScript

It has been over a week since my last post. A lot of things have happened besides COVID-19. As you might know I live in a suburb in the Twin Cities of Minneapolis and St. Paul. I live in Dakota County. On May 24, 2020 the county had experienced 33 deaths due to the pandemic. Today is June 03, 2020 and the count is up to 59. The count is going up. It seems that a second wave has been forecasted by models for about June 15, 2020. As the rate things are going, I would not be surprised.

When you read about my location, I would assume that the death of George Floyd is known to you as the event that triggered a set of riots and lootings in several cities in the USA.

If you do not know about the death of George Floyd then you might want to read the Wikipedia article regarding his death. I was under the impression that the laws in the USA clearly state that a person is innocent until proven otherwise. If you read the article, the police officer, that allegedly caused the death of George Floyd, has been already found guilty by Wikipedia; shame on you.

During the past few decade’s I have read some articles on the media, in which use of excessive force has been attributed to deaths of people under their custody. That said, in very few cases, the police officer(s) involved acted improperly. In this specific case, we are talking about an individual that was committing a crime, refused being taken into custody and to top it all, the autopsy determine use of illegal drugs.

Then we have the mayor of Minneapolis which had the four police officers (I have read in the news than only one was fired) involved in the arrest, fired. What is wrong with this picture? The governor of Minnesota and the mayor of Minneapolis decided without a trial to fire the police officers without a trial; shame on you.

Following the incident, in many cities all over the country (mostly on liberal states) the black community decided that it was a great idea to loot and burn down businesses. Not sure how such behavior would improve on the stand of the “Black Lives Matter” human rights movement.

For about two or three nights following the death of George Floyd, mostly black people, looted and burned down businesses that in no way shape or form had anything to do with the death. Interesting that most of the targeted businesses sold liquor, entertainment devices, foods and prescription drugs.

The riots were located in different cities, so after a couple days, the Minnesota governor decided to call on the National Guard for assistance. It was not until a couple days after when the FBI issued a thread warning against the National Guard that they were allowed to start carrying live ammunition. I have not heard of any incidents since then. I guess the people looting and rioting decided to start behaving when it became evident that their actions could bring them consequences. Not sure how the governor of Minnesota allowed the loss of so many businesses because the riots and looters were running loose and he had at his disposal the National Guard; shame on you.

During the last day or two of the riots, there were talks that the problems were going to be extended to the suburbs. That never happened. The main reason for it being is that most people have arms at home, and they do not have issues defending their lives and properties.

In a previous life, I have been on both sides of the coin. I was a career naval officer and during some hard political and economical times I had to enforce curfews. I experienced many things but always respected the citizens and military team. On more than one occasion I had to make special arrangements because I could not make it home before curfew. By following the law and rules, I never had an issue.

OK, enough of this sad set of events. Hopefully the truth will prevail. Do not forget that police officers have web cams which should have recorded the entire incident. The liberal authorities in this part of the country have a hard time understanding the laws of the nation. Any one should be considered innocent until proved guilty, and no one has the right to loot and burn down businesses because they feel like it.

As you know I am refreshing and learning while getting ready to start a project which I will document in this post. The first item in my list is Angular and JavaScript is a prerequisite. In this post I will cover the development of an analog clock that runs on a web browser. This was part of a LinkedIn course named “JavaScript Essential Training” by Morten Rand-Hendriksen.

The object of this code is to use some of the topics that were covered before this chapter. So far I would highly recommend the course if you need a refresher in JavaScript and also the BOM and DOM.

In this project I decided to use the Atom (test editor not an IDE) instead of VS Code because the instructor decided to use Atom. In general I like to be able to follow as close as possible to prevent issues which would serve as a distraction from the subject at hand.

The requirements for this task are to develop an analog clock using JavaScript so it can run on a web browser. I followed and experiment only with Chrome. In production one should always test on a few different browsers to make sure all is well.

<!DOCTYPE html>
<html lang="en-US">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>A Digital Analog Clock</title>
    <link rel="stylesheet" href="style.css" type="text/css" media="all">
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22script.js%22%20defer%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />
</head>

<body>
<main class="main">
    


<div class="clockbox">
        <svg id="clock" xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">

            <g id="face">
                <circle class="circle" cx="300" cy="300" r="253.9"/>
                <path class="hour-marks" d="M300.5 94V61M506 300.5h32M300.5 506v33M94 300.5H60M411.3 107.8l7.9-13.8M493 190.2l13-7.4M492.1 411.4l16.5 9.5M411 492.3l8.9 15.3M189 492.3l-9.2 15.9M107.7 411L93 419.5M107.5 189.3l-17.1-9.9M188.1 108.2l-9-15.6"/>
                <circle class="mid-circle" cx="300" cy="300" r="16.2"/>
            </g>

            <g id="hour">
                <path class="hour-arm" d="M300.5 298V142"/>
                <circle class="sizing-box" cx="300" cy="300" r="253.9"/>
            </g>

            <g id="minute">
                <path class="minute-arm" d="M300.5 298V67"/>
                <circle class="sizing-box" cx="300" cy="300" r="253.9"/>
            </g>

            <g id="second">
                <path class="second-arm" d="M300.5 350V55"/>
                <circle class="sizing-box" cx="300" cy="300" r="253.9"/>
            </g>

        </svg>
    </div>



<!-- .clockbox -->
</main>

</body>

</html>

The HTML contains the definitions for the face of the clock including the ticks for the hours and the three hands, one for hour, the second for minutes and the last for seconds. The magic, making the clock work, is in the JavaScript with help from CSS.

// **** get access to the hands of our clock ****
const HOURHAND = document.querySelector("#hour");
const MINUTEHAND = document.querySelector("#minute");
const SECONDHAND = document.querySelector("#second");

// ???? ????
console.log("Number.MAX_VALUE: ", Number.MAX_VALUE, " Number.MIN_VALUE: ", Number.MIN_VALUE);
console.log("Number.MAX_SAFE_INTEGER: ", Number.MAX_SAFE_INTEGER);

// **** get the current date and time ****
var date = new Date();

// ???? ????
console.log(date);

// **** assigne the initial time to a set of variables ****
let hr = date.getHours();
let min = date.getMinutes();
let sec = date.getSeconds();
let ms = date.getMilliseconds();

// ???? ????
console.log("time: " + hr + ":" + min + ":" + sec + "." + ms);

// **** some basic arithmetic to get th eposition of the hands ****
let hrPosition = (hr * 360 / 12) + (min * (360 / 60) / 12);
let minPosition = (min * 360 / 60) + (sec * (360 / 60) / 60);
let secPosition = sec * 360 / 60;

// **** function to run the clock ****
function runTheClock() {

  // **** increment position of hands ****
  secPosition += 6;
  minPosition += (6 / 60);
  hrPosition += (3 / 360);

  // ???? ????
  if (secPosition % 360 == 0) {
    console.log("milliseconds: ", new Date().getMilliseconds());
  }

  // ???? ????
  // console.log("secPosition: ", secPosition);
  // console.log("minPosition: ", minPosition);
  // console.log("hrPosition: ", hrPosition);

  // **** update hand position on clock ****
  HOURHAND.style.transform = "rotate(" + hrPosition + "deg)";
  MINUTEHAND.style.transform = "rotate(" + minPosition + "deg)";
  SECONDHAND.style.transform = "rotate(" + secPosition + "deg)";
}

// **** run the clock every 1000 milliseconds ****
var interval = setInterval(runTheClock, 1000);

We start by getting constants to refer to the hour, minute and second hands in our clock.

I then display a few variables. I will tell you why in a few.

We create a Date object, which allows us to get to the current date and time. The time is then displayed in “HH:MM:SS” format.

We compute the position for the hands of our clock. Initially we just used the first set of terms for the hours and minutes. Since we decided on having a smoother clock, we added the second terms so it removes the jumps from the hands. Feel free to comment them out to experience the initial behavior.

The runTheClock function was put together so we could run it once a second and have the clock update automatically. You can see in the last statement in this code snippet the cal to set a one second (1,000 milliseconds) interval which calls it.

Note that the initial position of the hands is calculated when the script is executed. The function just updates the hands each second. During the course we ran into an issue each time the second had would complete a minute. You can reproduce this by editing the script and directly computing the position of all hands each second.

The last lines in the runTheClock function are used to draw the updated hands on our analog clock.

/* Layout */
.main {
    display: flex;
    padding: 2em;
    height: 90vh;
    justify-content: center;
    align-items: middle;
}

.clockbox,
#clock {
    width: 100%;
}

/* Clock styles */
.circle {
    fill: none;
    stroke: #000;
    stroke-width: 9;
    stroke-miterlimit: 10;
}

.mid-circle {
    fill: #000;
}
.hour-marks {
    fill: none;
    stroke: #000;
    stroke-width: 9;
    stroke-miterlimit: 10;
}

.hour-arm {
    fill: none;
    stroke: #000;
    stroke-width: 17;
    stroke-miterlimit: 10;
}

.minute-arm {
    fill: none;
    stroke: #000;
    stroke-width: 11;
    stroke-miterlimit: 10;
}

.second-arm {
    fill: none;
    stroke: #000;
    stroke-width: 4;
    stroke-miterlimit: 10;
}

/* Transparent box ensuring arms center properly. */
.sizing-box {
    fill: none;
}

/* Make all arms rotate around the same center point. */
/* Optional: Use transition for animation. */
#hour,
#minute,
#second {
    transform-origin: 300px 300px;
    transition: transform .5s ease-in-out;
}

The CSS file is used for the style of all the elements of our clock.

Of interest is the last group of statements which specify the transition effects. This makes the updates of the hands flow smoothly. The last line is directly responsible for the issue that was mentioned when the hands passed the 0 hour, minute or second.

The entire code for this project can be found in my GitHub repository.

If you have comments or questions regarding this, or any other post in this blog, or if you would like for me to serve of assistance with any phase in the SDLC (Software Development Life Cycle) of a project associated with a product or service, please do not hesitate and leave me a note below. If you prefer, send me a private message using the following address:  john.canessa@gmail.com. I will reply as soon as possible.

Keep on reading and experimenting. It is the best way to learn, refresh your knowledge and enhance your developer toolset!

One last thing, many thanks to all 1,072 subscribers to my blog!!!

Keep safe during the COVID-19 pandemic and economy restart.

John

Twitter:  @john_canessa

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.