Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mewmix/273a0fb99fc812e7dfd125a428c8e91e to your computer and use it in GitHub Desktop.
Save mewmix/273a0fb99fc812e7dfd125a428c8e91e to your computer and use it in GitHub Desktop.
Circular Countdown Timer - HTML, CSS, Javascript

Circular Countdown Timer - HTML, CSS, Javascript

Circular Countdown using only HTML, CSS, Javascript (no jQuery). Great for any sort of Coming Soon pages.

A Pen by chubbykat on CodePen.

License.

<h1> Time until SNAPSHOT </h1>
<div id='container'>
</div>
<div class="countdown">
<div class="container days">
<canvas id="days-canvas" width="200" height="200"></canvas>
<svg width="200" height="200">
<circle id="outer" cx="100" cy="100" r="90" fill="transparent" stroke-width="20" stroke="#00fdff" opacity="0.1"/>
</svg>
<div class="label">
<span id="days-value"></span><br>
<span>days</span>
</div>
</div>
<div class="container hours">
<canvas id="hours-canvas" width="200" height="200"></canvas>
<svg width="200" height="200">
<circle id="outer" cx="100" cy="100" r="90" fill="transparent" stroke-width="20" stroke="#FFA246" opacity="0.1"/>
</svg>
<div class="label">
<span id="hours-value"></span><br>
<span>hours</span>
</div>
</div>
<div class="container minutes">
<canvas id="minutes-canvas" width="200" height="200"></canvas>
<svg width="200" height="200">
<circle id="outer" cx="100" cy="100" r="90" fill="transparent" stroke-width="20" stroke="#E834B1" opacity="0.1"/>
</svg>
<div class="label">
<span id="minutes-value"></span><br>
<span>minutes</span>
</div>
</div>
<div class="container seconds">
<canvas id="seconds-canvas" width="200" height="200"></canvas>
<svg width="200" height="200">
<circle id="outer" cx="100" cy="100" r="90" fill="transparent" stroke-width="20" stroke="#3A55FF" opacity="0.1"/>
</svg>
<div class="label">
<span id="seconds-value"></span><br>
<span>seconds</span>
</div>
</div>
</div>
<div class='center'>
<center>
<h1><a href='https://hex.win' > Learn More </h1>
</center>
</div>
<br>
<li>
<a class="telegram-button" href="javascript:void(window.open('https://t.me/share/url?url='+encodeURIComponent(window.location.href)+'&text='+encodeURIComponent(document.title), '_blank'))">
<i></i>
<span>Forward to Your Friends</span>
</a>
<a class="telegram-button" href="https://t.me/HEXcrypto" target="_blank">
<i></i>
<span>@HexCryptoChat</span>
</a>
// Set Launch Date (ms)
const launchDate = new Date("December 02, 2019 00:00:00 UTC").getTime();
// Context object
const c = {
context: {},
values: {},
times: {}
};
// Convert radians to degrees
function deg(d) {
return (Math.PI/180)*d-(Math.PI/180)*90;
}
function render() {
c.context.seconds.clearRect(0, 0, 200, 200);
c.context.seconds.beginPath();
c.context.seconds.strokeStyle = "#FFFF";
c.context.seconds.arc(100, 100, 90, deg(0), deg(6 * (60 - c.times.seconds)));
c.context.seconds.lineWidth = 20;
c.context.seconds.lineCap = "round";
c.context.seconds.stroke();
c.context.minutes.clearRect(0, 0, 200, 200);
c.context.minutes.beginPath();
c.context.minutes.strokeStyle = "yellow";
c.context.minutes.arc(100, 100, 90, deg(0), deg(6 * (60 - c.times.minutes)));
c.context.minutes.lineWidth = 20;
c.context.minutes.lineCap = "round";
c.context.minutes.stroke();
c.context.hours.clearRect(0, 0, 200, 200);
c.context.hours.beginPath();
c.context.hours.strokeStyle = "aquamarine";
c.context.hours.arc(100, 100, 90, deg(0), deg(15 * (24 - c.times.hours)));
c.context.hours.lineWidth = 20;
c.context.hours.lineCap = "round";
c.context.hours.stroke();
c.context.days.clearRect(0, 0, 200, 200);
c.context.days.beginPath();
c.context.days.strokeStyle = "salmon";
c.context.days.arc(100, 100, 90, deg(0), deg(365 - c.times.days));
c.context.days.lineWidth = 20;
c.context.days.lineCap = "round";
c.context.days.stroke();
}
function init() {
// Get 2D contexts
c.context.seconds = document.getElementById('seconds-canvas').getContext('2d');
c.context.minutes = document.getElementById('minutes-canvas').getContext('2d');
c.context.hours = document.getElementById('hours-canvas').getContext('2d');
c.context.days = document.getElementById('days-canvas').getContext('2d');
// Get displayed values
c.values.seconds = document.getElementById('seconds-value');
c.values.minutes = document.getElementById('minutes-value');
c.values.hours = document.getElementById('hours-value');
c.values.days = document.getElementById('days-value');
setInterval(function() {
// Get todays date and time (ms)
const now = new Date().getTime();
// Get distance from now to launchDate
const distance = launchDate - now;
// Time calculations
c.times.days = Math.floor(distance / (1000 * 60 * 60 * 24));
c.times.hours = Math.floor(
(distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
);
c.times.minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
c.times.seconds = Math.floor((distance % (1000 * 60)) / 1000);
c.values.days.innerText = c.times.days;
c.values.hours.innerText = c.times.hours;
c.values.minutes.innerText = c.times.minutes;
c.values.seconds.innerText = c.times.seconds;
render(); // Draw!
}, 1000);
}
init();
let video = document.querySelector('video');
const setVideoDimensions = () => {
if (window.innerWidth / window.innerHeight > 16 / 9) {
video.style.width = '100vw';
video.style.height = 'calc(100vw * 9 / 16)';
} else {
video.style.width = 'calc(100vh * 16 / 9)';
video.style.height = '100vh';
}
};
window.onresize = setVideoDimensions;
setVideoDimensions();
body {
background-color: black;
font-family: "Verdana", sans-serif;
}
.countdown {
display: flex;
justify-content: space-between;
margin: 20vh auto 0 auto;
width: 60%;
min-width: 800px;
.container {
position: relative;
svg {
position: absolute;
top: 0;
left: 0;
}
.label {
position: absolute;
width: 100px;
height: 100px;
top: 50%;
left: 50%;
transform: translate(-50%, -55%);
text-align: center;
display: flex;
flex-direction: column;
justify-content: space-around;
span {
&:first-of-type {
font-size: 55px;
color: white;
}
&:nth-of-type(2) {
font-size: 20px;
text-transform: uppercase;
color: white;
}
}
}
}
}
@media screen and (max-width: 800px) {
.countdown {
flex-direction: column;
align-items: center;
height: 900px;
width: auto;
min-width: auto;
}
}
.telegram-button{
position: relative;
display: inline-block;
vertical-align: top;
height: 20px;
box-sizing: border-box;
cursor: pointer;
background-color: #0088cc;
border-radius: 3px;
padding: 3px 6px;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
font-size: 11px;
color: #FFF;
text-decoration: none;
}
.telegram-button:hover{
background-color: #007dbb;
}
.telegram-button:active{
background-color: #026698;
}
.telegram-button i{
display: inline-block;
height: 12px;
width: 14px;
vertical-align: middle;
margin-right: 2px;
background: url('https://telegram.org/img/oauth/tg_button_small.png') no-repeat;
background-size: contain;
}
.telegram-button span{
display: inline-block;
vertical-align: top;
}
#container{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
video {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@ndmax
Copy link

ndmax commented Jan 4, 2021

How would one modify this gist so that the circular bars "count down" instead of counting up, reducing as time expires? (For example, at 59 seconds, the seconds circle would be almost 100% complete, and at 1 second, it would be almost 0% complete.)

I suspect a startDate would be required in addition to the launchDate in order to calculate the completion percentage for days...

@Sheggsmann
Copy link

Thanks Man, this helps...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment