Hey, Programmers In This Post We will make an Animated Stopwatch with HTML, CSS & JavaScript. In this post, we will focus on concepts like JavaScript Date, JS Set Attributes, HTML Canvas & How to work with Canvas with JS.
We will also understand the HTML, CSS & JavaScript code step by step needed to make an animated stopwatch.
Also Read: Bottom Tab Navigation Bar With HTML & CSS
The HTML structure sets up the basic framework for the clock. Here’s a detailed breakdown:
div
with the class clock
is the main container that holds the entire clock. <div class="clock">
clock
container, there’s a div
with the class time
. This will display the current time in a readable format. <div class="time"></div>
div
elements represent a time component: hours, minutes, and seconds. Each contains a canvas
element for drawing the rotating circles.canvas
elements have a class circle
and a data-number
attribute that holds the total units (e.g., 12 hours, 60 minutes, 60 seconds). <div class="hour">
<canvas class="circle" data-number="12"></canvas>
</div>
<div class="minute">
<canvas class="circle" data-number="60"></canvas>
</div>
<div class="second">
<canvas class="circle" data-number="60"></canvas>
</div>
body
is styled to remove any margin and padding, set a font family, and apply a background color. It also makes sure the entire viewport is filled by setting the width and height to 100vw
and 100vh
. body {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Montserrat;
background: #1a1f39;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.clock
class centers the clock on the page using position: absolute
and transform: translate(-50%, -50%)
. It sets the size of the clock to 300px
by 300px
and applies a circular border. A background image is set to cover the entire clock. .clock {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 300px;
border-radius: 50%;
background: url(https://shu-vro.github.io/Analog-Clock-Effect/clock.png)
no-repeat center center;
background-size: cover;
}
.circle
class positions each canvas
element absolutely in the center of the clock and rotates it by -90deg
to align the start point of the drawing with the top. .circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotatez(-90deg);
}
.time
class styles the time text to be centered and displayed in white, with a font size of 20px
and a line height of 350px
to vertically center the text within the clock. .time {
position: relative;
width: 100%;
color: white;
line-height: 350px;
text-align: center;
font-size: 20px;
}
hour
, minute
, second
, and time
elements using document.querySelector
. const hour = document.querySelector(".hour");
const minute = document.querySelector(".minute");
const second = document.querySelector(".second");
const time = document.querySelector(".time");
setInterval
function runs the provided code every 1000 milliseconds (1 second). setInterval(() => {
new Date()
. const date = new Date();
hh
), minutes (mm
), and seconds (ss
) are extracted from the date
object. If the hour is 12 or more, it is converted to a 12-hour format by subtracting 12. let hh = date.getHours();
let mm = date.getMinutes();
let ss = date.getSeconds();
if (hh >= 12) {
hh = hh - 12;
}
time
element’s text content is updated to the current time using toLocaleTimeString
. time.textContent = date.toLocaleTimeString();
data-number
attributes for hour
, minute
, and second
elements are updated to the current time. For hour
and minute
, fractions are used to get more accurate positions. hour.setAttribute("data-number", hh + mm / 60);
minute.setAttribute("data-number", mm + ss / 60);
second.setAttribute("data-number", ss);
drawCircle
function is defined to draw each rotating circle on the canvas. It takes the circle
element, color
, strokeWidth
, and radius
as parameters. const circles = document.querySelectorAll(".circle");
function drawCircle(circle, color, strokeWidth, radius) {
circle.width = window.innerWidth;
circle.height = window.innerHeight;
let max_value = circle.dataset.number;
let actual_value = circle.parentNode.dataset.number;
let angle = (actual_value / max_value) * 2 * Math.PI;
const ctx = circle.getContext("2d");
ctx.beginPath();
ctx.arc(circle.width / 2, circle.height / 2, radius, 0, angle, false);
ctx.lineCap = "round";
ctx.strokeStyle = color;
ctx.lineWidth = strokeWidth;
ctx.stroke();
}
drawCircle
for Each Time Component: The drawCircle
function is called for each circle
, drawing an arc representing the hours, minutes, and seconds with different colors and radii. drawCircle(circles[0], "orangered", 8, 200);
drawCircle(circles[1], "lime", 8, 180);
drawCircle(circles[2], "dodgerblue", 8, 160);
setInterval
function.HTML:
<div class="clock">
<div class="time"></div>
<div class="hour">
<canvas class="circle" data-number="12"></canvas>
</div>
<div class="minute">
<canvas class="circle" data-number="60"></canvas>
</div>
<div class="second">
<canvas class="circle" data-number="60"></canvas>
</div>
</div>
CSS:
<style>
@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700");
body {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Montserrat;
background: #1a1f39;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.clock {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 300px;
border-radius: 50%;
background: url(https://shu-vro.github.io/Analog-Clock-Effect/clock.png)
no-repeat center center;
background-size: cover;
}
.circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotatez(-90deg);
}
.time {
position: relative;
width: 100%;
color: white;
line-height: 350px;
text-align: center;
font-size: 20px;
}
</style>
JAVASCRIPT:
<script>
const hour = document.querySelector(".hour");
const minute = document.querySelector(".minute");
const second = document.querySelector(".second");
const time = document.querySelector(".time");
setInterval(() => {
const date = new Date();
let hh = date.getHours();
let mm = date.getMinutes();
let ss = date.getSeconds();
if (hh >= 12) {
hh = hh - 12;
}
time.textContent = date.toLocaleTimeString();
hour.setAttribute("data-number", hh + mm / 60);
minute.setAttribute("data-number", mm + ss / 60);
second.setAttribute("data-number", ss);
const circles = document.querySelectorAll(".circle");
function drawCircle(circle, color, strokeWidth, radius) {
circle.width = window.innerWidth;
circle.height = window.innerHeight;
let max_value = circle.dataset.number;
let actual_value = circle.parentNode.dataset.number;
let angle = (actual_value / max_value) * 2 * Math.PI;
const ctx = circle.getContext("2d");
ctx.beginPath();
ctx.arc(circle.width / 2, circle.height / 2, radius, 0, angle, false);
ctx.lineCap = "round";
ctx.strokeStyle = color;
ctx.lineWidth = strokeWidth;
ctx.stroke();
}
drawCircle(circles[0], "orangered", 8, 200);
drawCircle(circles[1], "lime", 8, 180);
drawCircle(circles[2], "dodgerblue", 8, 160);
// circle, length, color, strokeWidth, radius
}, 1000);
</script>
Last Updated: June 18, 2024