Circular Countdown using only HTML, CSS, Javascript (no jQuery). Great for any sort of Coming Soon pages.
Created
November 18, 2019 00:39
-
-
Save mewmix/273a0fb99fc812e7dfd125a428c8e91e to your computer and use it in GitHub Desktop.
Circular Countdown Timer - HTML, CSS, Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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%); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 thelaunchDate
in order to calculate the completion percentage for days...