포트폴리오 디자인을 전부 갈아엎는 과정에서 about me 파트와 modal창에 사용된 가로 차트(horizon chart)와 원형 차트(circle)가 창이 로딩된 후 숫자가 차르륵 올라가는 효과를 어떻게 구현했는지 기록하려고 한다.
원형 차트의 숫자가 움직이는 효과를 구현하면서 가로 차트도 이렇게 숫자가 차르륵 올라가면 예쁠텐데, 하고 생각했지만 가로 차트를 만드는 유튜브 영상을 과장 좀 보태서 수십 개를 찾아봐도 숫자가 0, 1, 2 ~ 99, 100 하고 올라가는 효과를 구현해둔 건 찾아볼 수가 없어서 가로형 차트는 css로만 구현해야 하나 싶었다.
그 때 머리를 스치는 생각이 원형 차트를 만드는 방식을 따라해서 가로형 차트의 가상 요소 after 값을 원형 차트가 작동하는 방식으로 바꿔주면 되지 않을까? 였다.
그 예상은 멋드러지게 적중하여 나는 움직이는 원형 차트와 가로형 차트를 얻은 것이다.
일단 원형 차트를 만든 과정부터 시작해보겠다.
<div class="circle" data-degree="87" data-color="#d271fe">
<h2 class="circle_number">87<span>%</span></h2>
<h4 class="circle_title">css</h4>
</div>
<div class="circle" data-degree="90" data-color="#d271fe">
<h2 class="circle_number">90<span>%</span></h2>
<h4 class="circle_title">html</h4>
</div>
<div class="circle" data-degree="75" data-color="#d271fe">
<h2 class="circle_number">75<span>%</span></h2>
<h4 class="circle_title">javascript</h4>
</div>
<div class="circle" data-degree="80" data-color="#d271fe">
<h2 class="circle_number">80<span>%</span></h2>
<h4 class="circle_title">framework</h4>
</div>
원형 차트 완성본 이미지를 보면 data-degree 값과 %의 숫자가 같다는 걸 알 수 있다.
즉, data-degree 값만큼만 숫자가 증가하면서 원형 차트가 차오르는 것이다.
숫자가 증가하는 효과는 javascript(자바스크립트)로 구현했으니 자바스크립트도 살펴보자.
let circle = document.querySelectorAll(".circle");
circle.forEach(function (progress) {
let degree = 0;
let targetDegree = parseInt(progress.getAttribute("data-degree"));
let color = progress.getAttribute("data-color");
let number = progress.querySelector(".circle_number");
let interval = setInterval(function () {
degree += 1;
if (degree > targetDegree) {
clearInterval(interval);
return;
}
progress.style.background = `conic-gradient(${color} ${degree}%, #222 0%)`;
number.innerHTML = degree + `<span>%</span>`;
number.style.color = color;
}, 50);
});
let degree = 0;
: degree 변수는 애니메이션이 진행될 때 현재 원형 차트의 배경이 얼마나 채워졌는지를 나타내는 값이다. 물론 초기값은 0이다.
let targetDegree = parseInt(progess.getAttribute("data-degree")
: data-degree 라는 커스텀 데이터 속성에서 값을 가져와 숫자로 변환하여 targetDegree 변수에 저장하는 구문이다.
목적은 애니메이션이 종료될 때 배경이 채워질 목표 각도를 설정하는 것이다.
color는 원형 차트에 어떤 색을 적용할 것인지에 대한 hex 값을 가져오는 것이니 별로 신경 쓰지 않아도 된다.
✏ getAttribute
:자바스크립트에서 DOM 요소의 특정 속성(attribute) 값을 가져오는 메서드이다.
이 메서드를 사용하면 HTML 요소에 설정된 특정 속성의 값을 읽을 수 있다.
let interval = setInterval(funtion () { ... } , 50);
: setInterval을 사용하여 50 밀리초마다 반복해서 실행되는 함수 즉, 애니메이션 루프를 설정하는 구문이다.
목적은 원형 배경이 채워지는 애니메이션을 구현하기 위해 주기적으로 코드를 실행하는 것이다.
degree += 1
: 현재의 degree 값을 1씩 증가 시키는 구문이다.
애니메이션이 진행될 수록 원형 배경을 점진적으로 채우기 위해 각도를 증가시키는 역할을 한다.
if (degree < targetDegree) { clearInterval(interval); return)
:현재의 degree 값이 목표 각도(targetDegree)를 초과하면 애니메이션을 멈추게 하는 구문이다.
즉, 목표 각도에 도달하면 애니메이션을 종료하게 만든다.
값과 다르게 원이 꽉꽉 들어차는 걸 보고 싶지 않다면 꼭 넣는 게 좋은 구문이다.
progress.style.background = \`conic-gradient(${color} ${degree}%, #222, 0%)
:CSS의 conic-gradient를 사용해 배경이 원형으로 채워지도록 설정하게 하는 구문이다.
여기서 degree의 %만큼 color 값의 색으로 채워지고 나머지는 #222(어두운 색)으로 표시된다.
즉, 원형 배경을 애니메이션에 따라 점차적으로 채워지는 효과를 시각적으로 표현하는 것이다.
number.innerHTML = degree + \`<span>%</span>
: 현재의 degree 값을 html로 삽입하여 원형 내부에 표시하는 구문이다. 이때 %도 함께 표시된다.
여기서 progress.style.background = \`conic-gradient(${color} ${degree}%, #222, 0%) 를 보자.
방금은 원형이라 conic-gradient를 사용했지만 가로형 차트를 구현한다면 conic-gradient를 사용할 필요가 없다.
여기만 가로형 차트의 width 값이 되는 것으로만 바꿔준다면 어디서 본 건 있는 나의 욕구를 충족 시켜줄 수 있는 코드를 구현할 수 있다는 뜻이다.
겨우 본론으로 돌아와서, 가로형 차트를 살펴보자.
이게 멋드러지는 가로형 차트의 완성본이다.
다시 생각해도 뿌듯해서 자꾸 보게 된다.
이제 가로형 차트의 html을 보자
<div class="chart_line" chart-data-degree="85">
<span class="skill_name">react</span>
<div class="chart_bar"></div>
<span class="percent">0<span>%</span></span>
</div>
<div class="chart_line" chart-data-degree="75">
<span class="skill_name">vite</span>
<div class="chart_bar"></div>
<span class="percent">0<span>%</span></span>
</div>
<div class="chart_line" chart-data-degree="78">
<span class="skill_name">php</span>
<div class="chart_bar"></div>
<span class="percent">0<span>%</span></span>
</div>
<div class="chart_line" chart-data-degree="83">
<span class="skill_name">vue</span>
<div class="chart_bar"></div>
<span class="percent">0<span>%</span></span>
</div>
<div class="chart_line" chart-data-degree="80">
<span class="skill_name">next.js</span>
<div class="chart_bar"></div>
<span class="percent">0<span>%</span></span>
</div>
<div class="chart_line" chart-data-degree="65">
<span class="skill_name">redux</span>
<div class="chart_bar"></div>
<span class="percent">0<span>%</span></span>
</div>
원형 차트랑 구조는 같다. (사소한 건 다르지만)
기본적인 뼈대(틀)은 같다.
차트 전체를 구성하는 div 박스에 data-degree, 즉 차트가 채워질 만큼의 커스텀 데이터 값이 있고, 각 차트의 타이틀과 어떤 제목을 가졌고, 출력될 % 값이 있다.
차이점은 원형 차트에는 width 값이 필요가 없었는데 가로형 차트(horizon chart)에는 width 값이 필요하다는 것이다.
.chart_line {
display: flex;
justify-content: space-between;
align-items: center;
margin-right: 10%;
.skill_name {
width: 10%;
text-transform: uppercase;
letter-spacing: 0.5vw;
}
.chart_bar {
display: flex;
width: 35vw;
height: 1.5vw;
background-color: rgba(255, 255, 255, 0.5);
position: relative;
&::after {
content: "";
position: absolute;
background-color: #d271fe;
width: var(--progress-width, 0%);
height: inherit;
top: 0;
left: 0;
z-index: 1;
transition: width 1s ease;
}
}
}
이런 식으로 말이다.
여기서
배경의 불투명한 부분이 chart_bar가 된다. 전체적인 가로형 차트의 배경을 그리고 가상 요소(::after)를 사용하여 그 위를 덮는 형식으로 가로형 차트를 구현했다.
그러니까 chart_bar의 width 값은 건드리지 않고 ::after의 width 값에만 변화를 주어야 하는 것이다.
그것도 값이 전부 다 다른 여섯 개의 차트를 말이다.
그래서 찾은 방법이 --progress-width를 사용하는 것이었다.
css의 커스텀 속성인 --progress-width를 사용하여 프로그레스 바의 너비를 조절하는 방법이다.
이를 사용하면 차트의 chart-data-degree 값을 따라 달라지게 되는 것이다.
그래서 자바스크립트를 어떻게 짰냐면,
let chartLines = document.querySelectorAll(".chart_line");
chartLines.forEach(function (progress) {
let degree = 0;
let targetDegree = parseInt(progress.getAttribute("chart-data-degree"));
let bar = progress.querySelector(".chart_bar");
let percent = progress.querySelector(".percent");
let interval = setInterval(function () {
degree += 1;
if (degree > targetDegree) {
clearInterval(interval);
return;
}
bar.style.setProperty("--progress-width", degree + "%");
percent.innerHTML = degree + `<span>%</span>`;
}, 50);
원형 차트의 자바스크립트 틀을 그대로 가져왔다.
물론 필요없는 color는 빼버렸다.
원형 차트와 똑같이 let chartLines를 document.quertSelectorAll을 사용하여 .chart_line이라는 클래스를 가진 모든 요소를 선택하고, 여러 개인 chartLines에 forEach를 사용하여 각 요소에 대해 순회하면서 콜백함수를 실행할 수 있도록 했다.
여기서의 progress는 각각의 .chart_line이 되겠지.
let degree = 0으로 degree의 초기값을 0으로 설정했다.
의외인 점은 let이 변수 선언이라지만 원형 차트도, 가로형 차트도 전부 degree라는 변수를 사용했는데 꼬이지 않고 값들이 제자리를 쏙쏙 찾아 들어갔다는 점이다.
data-degree 값을 찾아서 집어넣는 방식이라 그런가.
어쨌든,
let targerDegree = parseInt(progress.getAttribute("chart-data-degree")) 를 사용하여 커스텀 데이터 속성에서 값을 가져와 targetDegree 변수에 저장하게 만든다.
아, 아까는 data-degree였는데 왜 지금은 chart-data-degree를 사용하냐면, 내가 헷갈리기 때문이다. 별 이유는 없다.
let bar = progress.querySelector(".chart_bar)를 사용하여 .chart_bar 클래스를 가진 자식 요소를 선택하여 bar에 저장한다.
왜냐면 프로그레스 바의 시각적 요소를 조작하기 위해서이다.
let percent = progress.querySelector(".percent")를 사용하여 percent 클래스를 가진 자식 요소를 선택하여 percent 변수에 저장한다. 진행도를 텍스트로 표시할 요소를 선택하여 애니메이션 중 업데이트 할 수 있도록 하기 위해서이다.
대충 숫자가 차르륵 올라가려면 이 과정이 꼭 필요하다는 것만 알아두자.
let interval = setInteval( function ( ) { ... }, 50)
아까처럼 setInterval을 사용해 50밀리초마다 반복해서 실행되는 함수(애니메이션 루프)를 설정한다. 프로그레스 바가 점진적으로 채워지는 애니메이션을 구현하기 위해 주기적으로 코드를 실행해야 하기 때문이다.
degree += 1을 사용하여 애니메이션이 진행될 수록 프로그레스 바를 점진적으로 채우기 위해 현재의 degree 값을 1씩 증가시키고, if (degree > targetDegree) {clearInterval(interval); return;)을 사용해 현재의 degree 값이 목표 진행도(targetDegree)를 초과하면 clearInterval로 애니메이션을 멈춘다.
bar.style.setProperty("--progress-width", degree + "%");
:CSS의 커스텀 속성(progress-width)을 설정하여 프로그레스 바의 width값을 조정하게 된다. degree 값에 따라 width가 점진적으로 증가하게 한다.
프로그레스 바의 시각적 진행 상태를 업데이트하여 애니메이션 효과를 만들게 하는 것이다.
✏ setProperty
: 자바스크립트의 CSS Style Declaration 객체에서 사용되는 메서드로, CSS 변수(커스텀 속성 ex.progree-width)를 설정하거나 일반 CSS 속성의 값을 변경하는데 사용됨. 이 메서드는 주로 element(요소).style을 통해 접근할 수 있으며, CSS 변수의 값을 동적으로 변경할 때 유용함.
percent.innerHTML = degree + \`<span>%</span>`
:현재의 degree 값을 HTML로 삽입하여 프로그레스 바 옆에 진행도를 퍼센트로 표시하는 구문이다. 숫자가 차르륵 올라가려면 이 과정이 필수이다.
이 모든 과정을 거치고 나면 숫자라 차르르르르륵 올라가는 쾌감이 엄청난 차트 바와 원형 차트를 만들 수 있는 것이다.
사실 내가 언젠가 또 써먹고 싶은데 기억 안 나서 헤맬까봐 써놓는 것이다.
뭐... 나처럼 짱 멋진 가로형 차트를 만들고 싶은데 방법을 모르겠는 사람이 보면 더 좋고.