Skip to content

Instantly share code, notes, and snippets.

@bishoplee
Created July 11, 2018 03:04
Show Gist options
  • Save bishoplee/71713df1316037fc09171077a53a5868 to your computer and use it in GitHub Desktop.
Save bishoplee/71713df1316037fc09171077a53a5868 to your computer and use it in GitHub Desktop.
Minimal Countdown Timer
.container
.countdown.countdown--wide#countdown
.countdown__fill#ticker
.countdown__digit#seconds 00
//.countdown__buttons
// .countdown__button +
// .countdown__button -
a.full-button#toggle Toggle size

Minimal Countdown Timer

DailyUI #014 - Countdown timer. For this one I was thinking a bit about how a simple countdown timer could work on a smart watch, hence the circle shape and touch controls.

Tap to stop/reset/start. When stopped, slide to set the time (it's a little hard to get it to an exact value).

Looks best on touch devices!

Using css blend modes to achieve the text effect and viewport units to scale things nicely (so useful!).

A Pen by Nathaniel Watson on CodePen.

License.

function Timer(duration, element) {
var self = this;
this.duration = duration;
this.element = element;
this.running = false;
this.els = {
ticker: document.getElementById('ticker'),
seconds: document.getElementById('seconds'),
};
document.getElementById('toggle').addEventListener('click', function() {
var cl = 'countdown--wide';
if (self.element.classList.contains(cl)) {
self.element.classList.remove(cl);
} else {
self.element.classList.add(cl);
}
});
var hammerHandler = new Hammer(this.element);
hammerHandler.get('pan').set({ direction: Hammer.DIRECTION_VERTICAL });
hammerHandler.on('panup pandown', function(ev) {
if (!self.running) {
if (ev.direction === Hammer.DIRECTION_UP && self.duration < 999000) {
self.setDuration(self.duration + 1000);
} else if (ev.direction === Hammer.DIRECTION_DOWN && self.duration > 0) {
self.setDuration(self.duration - 1000);
}
}
});
hammerHandler.on('tap', function() {
if (self.running) {
self.reset();
} else {
self.start();
}
})
}
Timer.prototype.start = function() {
var self = this;
var start = null;
this.running = true;
var remainingSeconds = this.els.seconds.textContent = this.duration / 1000;
function draw(now) {
if (!start) start = now;
var diff = now - start;
var newSeconds = Math.ceil((self.duration - diff)/1000);
if (diff <= self.duration) {
self.els.ticker.style.height = 100 - (diff/self.duration*100) + '%';
if (newSeconds != remainingSeconds) {
self.els.seconds.textContent = newSeconds;
remainingSeconds = newSeconds;
}
self.frameReq = window.requestAnimationFrame(draw);
} else {
//self.running = false;
self.els.seconds.textContent = 0;
self.els.ticker.style.height = '0%';
self.element.classList.add('countdown--ended');
}
};
self.frameReq = window.requestAnimationFrame(draw);
}
Timer.prototype.reset = function() {
this.running = false;
window.cancelAnimationFrame(this.frameReq);
this.els.seconds.textContent = this.duration / 1000;
this.els.ticker.style.height = null;
this.element.classList.remove('countdown--ended');
}
Timer.prototype.setDuration = function(duration) {
this.duration = duration;
this.els.seconds.textContent = this.duration / 1000;
}
var timer = new Timer(10000, document.getElementById('countdown'));
timer.start();
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.4/hammer.min.js"></script>
$col-bg: black;
$col-sun: #FF5722;
html,
body {
height: 100%;
}
body {
background: $col-bg;
}
* {
touch-action: none;
}
.container {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.countdown {
display: block;
width: 66vmin;
height: 66vmin;
position: relative;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Oswald', sans-serif;
font-weight: 400;
font-size: 25vmin;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
transition: width, height, border-radius, font-size;
transition-duration: 0.2s;
&--ended {
animation: buzz 0.5s;
}
&:active {
transform: scale(1.02);
}
@keyframes buzz {
0% {
transform: rotate(0);
}
10%, 30%, 50%, 70%, 90% {
transform: rotate(6deg);
}
20%, 40%, 60%, 80% {
transform: rotate(-6deg);
}
100% {
transform: rotate(0);
}
}
&--wide {
width: 100%;
height: 100%;
font-size: 50vmin;
border-radius: 0;
}
&__fill {
display: block;
width: 100%;
height: 100%;
position: absolute;
left: 0;
bottom: 0;
background: $col-sun;
opacity: 1;
}
&__digit {
width: 100%;
color: $col-sun;
text-align: center;
mix-blend-mode: difference;
pointer-events: none;
user-select: none;
}
&__buttons {
position: absolute;
right: 50px;
top: 50%;
height: 200px;
margin-top: -100px;
color: white;
z-index: 1;
}
&__button {
height: 50%;
}
}
.full-button {
position: absolute;
right: 10px;
bottom: 10px;
padding: 1em 0.5em 0.5em 2em;
font-family: 'Oswald', sans-serif;
text-transform: uppercase;
color: white;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Oswald" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment