글이 길어질 것 같아 시리즈를 따로 만들었다.
이전내용은...여기
요약하자면 돌려돌려 돌림판이라는 크롬 익스텐션을 발견했는데 기능을 추가해서 사용하고 싶었다.
부족했던 svg와 애니메이션 등도 배울겸 처음부터 끝까지 만들어보려함.
일단 svg로 원 부터 만들어보자.
<svg width="700" height="700" viewBox="0 0 50 40">
<circle r="10" cx="20" cy="20" fill="transparent" stroke="tomato" stroke-width="20"
stroke-dasharray="calc(100 * calc(2*3.14*10) / 100) calc(2*3.14*10)" transform="rotate(-90) translate(-40)">
</circle>
<circle r="10" cx="20" cy="20" fill="transparent" stroke="pink" stroke-width="20"
stroke-dasharray="calc(66.6 * calc(2*3.14*10) / 100) calc(2*3.14*10)" transform="rotate(-90) translate(-40)" />
<circle r="10" cx="20" cy="20" fill="transparent" stroke="yellow" stroke-width="20"
stroke-dasharray="calc(33.3 * calc(2*3.14*10) / 100) calc(2*3.14*10)" transform="rotate(-90) translate(-40)" />
</svg>
구글링하며 얻은 코드를 붙여넣었다. 음 제법 이쁜걸?
돌림판의 핵심은 회전이니 한번 돌려본다.
const $button = document.getElementById("button");
const $spinner = document.getElementById("spinner");
$button.addEventListener("click", () => {
$spinner.classList.toggle("rotating");
});
.rotating{
animation: rotating 1s linear infinite;
}
@keyframes rotating {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
대충 이정도면 되겠지? ㅎㅎ
...🙄
회전 애니메이션을 svg
에 걸어서 그런 것 같다. svg
에 회전 애니메이션을 준 이유는 circle
태그를 감싸고 있었기 때문이다.
circle
태그의 지름과 svg
태그의 너비가 맞지 않는게 문제구나? 이를 한번 해결해보자
<svg id="spinner" width="700" height="700" viewBox="0 0 50 40">
사용중인 svg
태그 속성들이다. 이중 viewBox
라는 친구만 알아보면 될 것 같다.
그러면 viewBox
의 첫번째, 두번째 값을 바꿔보자.
크기는 그대로지만, 원이 y축으로 20만큼, x축으로 -20만큼 이동한 것 같다.
양수를 넣었는데 x축은 왜 음수만큼 이동한걸까?
실제로 이동한게 아니라, 보이는 박스 즉, viewBox의 위치가 이동한거다.
아하! viewBox
의 첫번째 두번째인자인 min-x, min-y
는 카메라를 이동한다고 생각하면 편하구나
그러면 세번째 네번째 인자인 width, heigth
는 도대체 뭘 나타낼까? 이미 속성에 너비와 높이가 지정되어있는데 말이다.
svg
를 감싸고있는 컨테이너의 크기는 800x800(px)이다.
svg
의 크기 또한 800x800(px)이다.
이해를 돕기위해 만든 사각형이다. 400x400의 크기를 갖고있다.
<svg width="800px" height="800px" id="spinner">
<rect width="400px" height="400px" fill="tomato" />
</svg>
코드는 위와 같다. 여기서 viewBox
의 width, height
를 먹여본다.
<svg width="800px" height="800px" id="spinner" viewBox="0 0 500 500">
사각형이 애매하게 커졌다(1.6배). 640이라는 값은 어디서 나온걸까?
바로 svg
의 너비,높이 와 viewBox
의 너비,높이 비율이다.
800(svg너비):500(svg속성인 viewBox의 너비) = 640(커진 사각형 너비):400(원래 사각형 너비)
왜 이런 현상이 발생할까?
우리가 흔히 아는 viewport는 현재 화면에 보여지고 있는 영역을 뜻한다. 보통 브라우저 크기라고 착각하는데, 이는 사실과 다르다.
본래 컴퓨터 그래픽스의 용어다. 즉, 화면에 보여지고 있는 다각형을 뜻한다.
svg
에서는 이게 컨테이너가 되었던 것이다.
<svg width="800px" height="800px" id="spinner" viewBox="0 0 500 500">
<rect width="400px" height="400px" fill="tomato" />
</svg>
위 코드에서 svg
의 viewport는 svg
태그 본인이다. 즉, 800x800영역이 뷰포트다.
viewBox
는 viewport내부에서의 카메라다. 즉, viewBox
의 크기가 작아지면, 그만큼 내부 요소가 당연히 커져보인다.
정리하자면!
자! 그러면 원의크기를 svg태그와 맞추면 되는 것이다.
속성을 하나씩 살펴보자!
<circle r="400" cx="50%" cy="50%" />
r
: 반지름cx, cy
: 원의 중점위치. viewPort
기준으로 움직인다.위 값을 이용해 svg
태그내부에 원을 딱 맞춰준다.
룰렛은 사실상 pie chart라고 봐도 무방하다. 각 부채꼴의 색상이 달라야하며 넓이도 달라야한다.
circle
태그에는 그런 기능이 없다. 따라서 태그 속성중 하나인 stroke
를 이용해야한다.
크기가 너무크니 조금 줄였다.
<circle r="150" cx="50%" cy="50%" stroke="tomato" fill="transparent" stroke-width="300" />
참고로 stroke-width
는 반지름의 2배가 되어야 원을 그린다.
따라서 반지름은 viewport의 1/4가 되어야한다.
=> 원의 크기는 반지름의 4배가 된다.
다음은 stroke-dasharray
를 이용하여 테두리(원)를 잘라준다.
첫번째 값은 선의 길이고 두번째 값은 공백이다.
<circle r="150" cx="50%" cy="50%" stroke="tomato" fill="transparent" stroke-width="300"
stroke-dasharray="100 50" />
이제 공식을 적용해보자.
<circle r="150" cx="50%" cy="50%" stroke="tomato" fill="transparent" stroke-width="300"
stroke-dasharray="calc(25 * calc(2*3.14*150) / 100) calc(2*3.14*150)" />
적당한 1/4짜리 원이 등장했다!
하지만 원의 위치가 조금 아리송하다. 이를 옮겨보자.
<circle r="150" cx="50%" cy="50%" stroke="tomato" fill="transparent" stroke-width="300"
stroke-dasharray="calc(25 * calc(2*3.14*150) / 100) calc(2*3.14*150)" transform="rotate(-90) translate(-600)" />
처음에 긁어온 코드를 전부 이해했다! 다시 처음 코드로 되돌아가보자. 크기는 임의로 조정했다.
<svg width="600px" height="600px" id="spinner" viewBox="0 0 600 600">
<circle r="150" cx="50%" cy="50%" stroke="tomato" fill="transparent" stroke-width="300"
stroke-dasharray="calc(100 * calc(2*3.14*150) / 100) calc(2*3.14*150)"
transform="rotate(-90) translate(-600)" />
<circle r="150" cx="50%" cy="50%" stroke="pink" fill="transparent" stroke-width="300"
stroke-dasharray="calc(66.6 * calc(2*3.14*150) / 100) calc(2*3.14*150)"
transform="rotate(-90) translate(-600)" />
<circle r="150" cx="50%" cy="50%" stroke="yellow" fill="transparent" stroke-width="300"
stroke-dasharray="calc(33.3 * calc(2*3.14*150) / 100) calc(2*3.14*150)"
transform="rotate(-90) translate(-600)" />
</svg>
한번 돌려볼까?
잘돌아간다!