<body>
<div class="clock">
<div class="clock-face">
<div class="hand hour-hand"></div>
<div class="hand min-hand"></div>
<div class="hand second-hand"></div>
</div>
</div>
</body>
html {
background: #018ded url(https://unsplash.it/1500/1000?image=881&blur=5);
background-size: cover;
font-family: "helvetica neue";
text-align: center;
font-size: 10px;
}
body {
margin: 0;
font-size: 2rem;
display: flex;
flex: 1;
min-height: 100vh;
align-items: center;
}
.clock {
width: 30rem;
height: 30rem;
border: 20px solid white;
border-radius: 50%;
margin: 50px auto;
position: relative;
padding: 2rem;
box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1), inset 0 0 0 3px #efefef,
inset 0 0 10px black, 0 0 10px rgba(0, 0, 0, 0.2);
}
.clock-face {
position: relative;
width: 100%;
height: 100%;
transform: translateY(-3px); /* account for the height of the clock hands */
}
.hand {
width: 50%;
height: 6px;
background: black;
position: absolute;
top: 50%;
transform-origin: 100%;
transform: rotate(90deg);
transition: all 0.03s;
transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
}
const secondHand = document.querySelector(".second-hand");
const minHand = document.querySelector(".min-hand");
const hourHand = document.querySelector(".hour-hand");
function setDate() {
const now = new Date();
const seconds = now.getSeconds();
const minutes = now.getMinutes();
const hours = now.getHours();
const secondsDegrees = (seconds / 60) * 360 + 90;
const minutesDegrees = ((minutes / 60) * 360) + ((seconds / 60) * 6) + 90;
const hoursDegrees = ((hours / 12) * 360) + ((minutes / 60) * 30) + 90;
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
minHand.style.transform = `rotate(${minutesDegrees}deg)`;
hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}
setInterval(setDate, 1000);
setDate();
css 프로퍼티인 transform-origin
는 엘리먼트를 transform할 기준점을 설정하는 프로퍼티이다.
이번 챌린지에서는 transform-origin=100%
로 작성하여 x-offset의 가장 오른쪽을 기준점으로 설정했다.
/* One-value syntax */
transform-origin: 2px;
transform-origin: bottom;
/* x-offset | y-offset */
transform-origin: 3cm 2px;
/* x-offset-keyword | y-offset */
transform-origin: left 2px;
/* x-offset-keyword | y-offset-keyword */
transform-origin: right top;
/* y-offset-keyword | x-offset-keyword */
transform-origin: top right;
/* x-offset | y-offset | z-offset */
transform-origin: 2px 30% 10px;
/* x-offset-keyword | y-offset | z-offset */
transform-origin: left 5px -3px;
/* x-offset-keyword | y-offset-keyword | z-offset */
transform-origin: right bottom 2cm;
/* y-offset-keyword | x-offset-keyword | z-offset */
transform-origin: bottom right 2cm;
/* Global values */
transform-origin: inherit;
transform-origin: initial;
transform-origin: revert;
transform-origin: revert-layer;
transform-origin: unset;
구현은 했지만 0초가 되면 transition으로 인해 초침이 원점으로 돌아가는 글리치 현상이 발생한다.
이는 변수 secondsDegrees
의 값이 마지막값 444에서 초기값 90이 되는 과정에서 transition이 적용되기 때문에 발생하는 현상이다. 이 문제는 transition을 제거하면 해결되는 것이었지만, 강의에서 제안한 if/else 문으로 해결해보았다.
function setDate() {
const secondHand = document.querySelector(".second-hand");
const minHand = document.querySelector(".min-hand");
const hourHand = document.querySelector(".hour-hand");
const now = new Date();
const seconds = now.getSeconds();
const minutes = now.getMinutes();
const hours = now.getHours();
const secondsDegrees = (seconds / 60) * 360 + 90;
const minutesDegrees = (minutes / 60) * 360 + (seconds / 60) * 6 + 90;
const hoursDegrees = (hours / 12) * 360 + (minutes / 60) * 30 + 90;
if (secondsDegrees === 90) {
secondHand.style.transition = "none";
} else {
secondHand.style.transition = "";
}
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
minHand.style.transform = `rotate(${minutesDegrees}deg)`;
hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}
setInterval(setDate, 1000);
setDate();
변수 secondsDegrees
의 값이 90일 때는 transition을 none을 통해 제거하고 그외에는 transtion을 리셋하도록 빈 문자열을 할당했다.
secondHand.style.transition = "";
이런 식으로 빈 문자열 값을 할당하면 기존의 인라인 스타일을 제거함으로써 해당 엘리먼트의 인라인 스타일은 리셋시킨다. 그리고 기존의 스타일시트에 있는 transition 속성을 적용한다.