.content
#okinawa.widget.clock(data-timezone="+9")
.shadow
.hand.seconds
.hand.minutes
.hand.hours
.hand-cap
label Okinawa
#seattle.widget.clock(data-timezone="-8")
.shadow
.hand.seconds
.hand.minutes
.hand.hours
.hand-cap
label Seattle
#amalfi.widget.clock(data-timezone="+1")
.shadow
.hand.seconds
.hand.minutes
.hand.hours
.hand-cap
label Amalfi
View Compiled
$color-primary: #673AB7
$color-secondary: #FFF
$color-tertiary: #5A2EA5
$size-base: 12px
$size-small: $size-base / 2
$size-large: $size-base * 2
$clock-size: $size-base * 32
$clock-size-small: $size-base * 20
$clock-weight: $size-small
$clock-weight-small: $size-small / 2
$clock-seconds-length: 95%
$clock-minutes-length: 85%
$clock-hours-length: 75%
html
height: 100%
display: flex
justify-content: center
align-items: center
background-color: $color-primary
overflow: hidden
.content
display: flex
align-items: center
.widget
padding: $size-large
margin: $size-large
&.clock
position: relative
width: $clock-size
height: $clock-size
border-radius: 100%
box-sizing: border-box
background-color: $color-tertiary
// specific to smaller clocks
&#okinawa, &#amalfi
width: $clock-size-small
height: $clock-size-small
&:before
border-width: $clock-weight-small
.hand
height: $clock-weight-small
top: ($clock-size-small - $clock-weight-small) / 2
transform-origin: right ($clock-weight-small / 2)
&.seconds
display: none
// clock rim
&:before
content: ''
width: 100%
height: 100%
position: absolute
top: 0
left: 0
border: $clock-weight solid $color-secondary
border-radius: 100%
box-sizing: border-box
// clock shadow
.shadow
content: ''
width: 100%
height: 500px
position: absolute
top: 50%
left: 0
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.65) 0%, rgba(0, 0, 0, 0) 100%)
transform: rotate(-45deg)
transform-origin: 50% 0%
opacity: 0.3
z-index: -1
.hand
height: $clock-weight
position: absolute
top: ($clock-size - $clock-weight) / 2
background-color: $color-secondary
border-radius: 100% 0% 0% 100%
transform-origin: right ($clock-weight / 2)
transition: all 0.05s cubic-bezier(0, 0, 0.52, 2.51) 0s
&.seconds
width: 50 - (100 - $clock-seconds-length)
left: 100 - $clock-seconds-length
opacity: 0.25
&.minutes
width: 50 - (100 - $clock-minutes-length)
left: 100 - $clock-minutes-length
opacity: 0.5
&.hours
width: 50 - (100 - $clock-hours-length)
left: 100 - $clock-hours-length
opacity: 0.75
.hand-cap
width: 5%
height: 5%
position: absolute
top: 47.5%
left: 47.5%
background-color: $color-secondary
border-radius: 100%
label
display: block
width: 100%
position: absolute
top: -$size-base * 2
left: 0
font-family: sans-serif
font-weight: 200
font-size: 12px
text-transform: uppercase
text-align: center
letter-spacing: 4px
color: $color-secondary
opacity: 0.5
View Compiled
class Clock {
constructor(id) {
this.timezone = parseInt(document.getElementById(id).dataset.timezone);
if (this.isDST(new Date())) {
this.timezone += 1;
}
this.handSeconds = document.querySelector(`#${id} .hand.seconds`);
this.handMinutes = document.querySelector(`#${id} .hand.minutes`);
this.handHours = document.querySelector(`#${id} .hand.hours`);
this.getTime();
this.cycle();
}
isDST(now) {
const jan = new Date(now.getFullYear(), 0, 1);
const jul = new Date(now.getFullYear(), 6, 1);
const dst = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
return now.getTimezoneOffset() < dst;
}
draw(hours, minutes, seconds) {
const drawSeconds = ((seconds / 60) * 360) + 90;
const drawMinutes = ((minutes / 60) * 360) + 90;
const drawHours = ((hours / 12) * 360) + 90;
this.handSeconds.style.transform = `rotate(${drawSeconds}deg)`;
this.handMinutes.style.transform = `rotate(${drawMinutes}deg)`;
this.handHours.style.transform = `rotate(${drawHours}deg)`;
// fix for animation bump on when clock hands hit zero
if (drawSeconds === 444 || drawSeconds === 90) {
this.handSeconds.style.transition = "all 0s ease 0s";
} else {
this.handSeconds.style.transition = "all 0.05s cubic-bezier(0, 0, 0.52, 2.51) 0s";
}
}
getTime() {
const now = new Date();
const hours = now.getUTCHours() + this.timezone;
const minutes = now.getUTCMinutes();
const seconds = now.getUTCSeconds();
this.draw(hours, minutes, seconds);
}
cycle() {
setInterval(this.getTime.bind(this), 1000);
}
}
new Clock('okinawa');
new Clock('seattle');
new Clock('amalfi');
// this is just a rough draft for some effects
// const shadowOkinawa = document.querySelector("#okinawa .shadow");
// const shadowSeattle = document.querySelector("#seattle .shadow");
// const shadowAmalfi = document.querySelector("#amalfi .shadow");
// const handleMouseMove = (event) => {
// const percent = parseInt((100 * event.pageX) / window.innerWidth);
// const drawShadow = (0.22 * percent) - 50;
// shadowOkinawa.style.transform = `rotate(${drawShadow}deg)`;
// shadowSeattle.style.transform = `rotate(${drawShadow}deg)`;
// shadowAmalfi.style.transform = `rotate(${drawShadow}deg)`;
// };
// document.onmousemove = handleMouseMove;
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.