3 분 소요

서론

JavaScript30 Day 2, 오늘은 JS로 시계를 만드는 미션이다.

시:분:초 이런 형식이 아니라 시침, 분침, 초침이 돌아가는 시계를 만드는 것이다.

혼자서 해보려고 했으나 오늘도 실패… 풀이를 보지 않고 미션을 풀 수 있는 날이 오길 바란다. 그럼 이제 시작하자!

구현

링크

JS and CSS Clock

Task

  1. 시곗바늘 정각을 가리키게 만들기
  2. 시곗바늘 회전시키기
  3. 시간에 맞춰 매초 시곗바늘 회전시키기

1. 시곗바늘 정각을 가리키게 만들기

우선 시곗바늘들이 12시를 가리키고 있는 것이 아니라, 9시 방향을 가리키고 있어서 transform: rotate(90deg);를 한다.

2. 시간에 따라 시곗바늘 회전시키기

const now = new Date();
const seconds = now.getSeconds();
const secondsDegrees = ((seconds / 60) * 360) + 90;

const mins = now.getMinutes();
const minsDegrees = ((mins / 60) * 360) + ((seconds / 60) * 6) + 90;

const hours = now.getHours();
const hoursDegrees = ((hours / 12) * 360) + ((mins / 60) * 30) + 90;

new Date()를 사용하면 요일 달 날짜 HH:MM:SS GMT+0900 (Korean Standard Time) 형식으로 시간을 알 수 있다. get~함수들로 시, 분, 초를 각각 상수에 저장한다.

이제 시곗바늘을 시간에 맞게 회전시켜야 하는데 몇 도씩 회전시켜야 할까?

시침은 60초마다 시계 한 바퀴를 돈다. 그럼 360/60 = 6, 즉 1초에 6도씩 회전시키면 된다.

분침 또한 60분 동안 한 바퀴를 돈다. 그럼 1분에 6도씩 회전시키면 되는데, 시계를 자세히 보면 분침이 1분에 한 번 움직이는 것이 아니라, 초침이 돌아감과 함께 조금씩 움직이고 있다.
그럼 1분에 6도씩 움직이니까 6/60 = 0.1도 해서 매초 0.1도씩 움직이면 되는 것이다.

시침도 마찬가지로 360/12 = 30, 30/60 = 0.5, 즉 매분 0.5도씩 회전시키면 된다. (+90을 하는 이유는 맨 처음 시곗바늘이 정각을 가리키고 있지 않아서 그렇다.)

secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
minHand.style.transform = `rotate(${minsDegrees}deg)`;
hourHand.style.transform = `rotate(${hoursDegrees}deg)`;

각도를 구했으니 이제 시곗바늘을 움직이도록 하자. 회전은 위에서 말했듯 transform: rotate()를 사용하면 된다.

그러나 여기서 문제가 있는데, 바로 저렇게 사용하면 div의 한가운데를 중심으로 회전하는 것이다. 내가 원하는 방식은 div의 오른쪽 가운데를 중심으로 회전하는 것이다. 그래서 css에 transform-origin 속성을 추가했다.

회전축 문제도 해결했으니 이제 매초 회전시키면 된다.

3. 시간에 맞춰 매초마다 시곗바늘 회전시키기

1초에 한 번씩 시곗바늘이 회전해야 한다. 이럴 때 사용하는 것이 바로 setInterval이다. 1초는 1000임으로 매초 2번을 실행시키면 되는 것이다.

그런데 완성본을 보면 시곗바늘이 움직일 때마다 반동이 있다. 바로 transition-timing-functioncubic-bezier()를 사용한 것이다.

cubic-bezier란 3차원 베지어 곡선을 의미하는 것인데 부드러운 곡선을 모델링하기 위해 컴퓨터 그래픽에 널리 사용되는 곡선 모델이라고 한다. 더 자세한 설명은 생략한다.

여튼 이 transition을 0.05초씩, transition-timing-function 속성으로 전환의 효과를 제어하면 반동을 구현할 수 있다.

F12를 눌러 개발자 모드에서 element.style로 효과를 조절해도 되고, 아니면 cubic-bezier 이 웹사이트를 사용해도 된다.

TLD

오늘도 역시 새로운 것투성이였다. JS에서 사용한 것은 다 아는 것들인데 오히려 CSS의 처음 보는 다양한 transition(Coding Factory) transition(MDN) 효과들이 많았다. transform: rotate(90deg);transition: all 0.05s; 빼고 다 처음 보는 것들이다.

CSS로 반동을 구현할 수 있다니!!! 역시 웹의 세계는 무궁무진하고 내가 모르는 신기한 JS API들 투성이다. 그래도 기초적인 것들은 어느 정도 섭렵했다고 생각했는데 아직도 배울 것이 이렇게 많다니…! 신난다 더 열심히 공부해야지!!! 웹 마스터가 되는 그날까지 파이퉹!!!!

최종 코드

JS:

const secondHand = document.querySelector(`.second-hand`);
const minHand = document.querySelector(`.min-hand`);
const hourHand = document.querySelector(`.hour-hand`);

function setClock() {
  const now = new Date();
  const seconds = now.getSeconds();
  const secondsDegrees = ((seconds / 60) * 360) + 90;

  const mins = now.getMinutes();
  const minsDegrees = ((mins / 60) * 360) + ((seconds / 60) * 6) + 90;

  const hours = now.getHours();
  const hoursDegrees = ((hours / 12) * 360) + ((mins / 60) * 30) + 90;

  secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
  minHand.style.transform = `rotate(${minsDegrees}deg)`;
  hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}

setInterval(setClock, 1000);

setClock();

CSS:

.hand {
  width: 50%;
  height: 6px;
  background: black;
  border-radius: .3rem; /* 시곗바늘 모서리를 둥글게 만들었다 */
  position: absolute;
  top: 50%;
  transform: rotate(90deg);
  transition: all 0.05s;
  transform-origin: 100%;
  transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
}

/* 시침을 짧게 만들었다 */
.hour-hand {
  width: 35%;
  left: 15%;
}

/* 초침을 얇게  */
.second-hand {
  height: 3px;
}

댓글남기기