Progress Bar는 어떠한 작업이 수행될 때, 그 작업의 진행 상태, 수치 값을 시각적으로 보여주기 위해 사용하는 요소입니다.
막대 형태의 Progress Bar는 일반적으로 아래와 같이 진행 상태에 따른 %를 width 값으로 주고
그 영역만 배경색을 적용하는 방법으로 간단히 처리할 수 있었습니다.

<div class="progress" style="width:30%"></div>

문득 원형의 경우는 어떻게 적용할까 궁금해졌지만 방법이 쉽게 떠오르지 않았습니다.
그래서 방법을 찾아보았고 여러 가지 방법들을 찾아볼 수 있어 정리해보았습니다.

Circle Progress Bar 만들기

기본 형태

A. UI 구현

1. 먼저 빈 div로 원형 프로그레스 바의 영역을 만들어줍니다.

<div class="circle_progress"></div>

2. 원형 프로그레스 바 영역에 좌, 우로 각각 50% 넓이를 가진 빈 영역을 생성합니다.

<div class="circle_progress">
  <span class="left"></span>
  <span class="right"></span>
</div>

3. 좌, 우 영역 안쪽에 각각 실제 진행 정도를 표시할 bar 역할을 해줄 요소를 생성합니다.

bar 요소는 반원의 형태로 만들고 아래와 같이 좌, 우 박스를 벗어난 반대편에 위치합니다.
좌, 우 영역에는 overflow:hidden;이 들어가 있어 처음에는 bar가 보이지 않습니다.

<span class="left"><span class="bar"></span></span>
<span class="right"><span class="bar"></span></span>

B. 상태 제어

• 애니메이션

오른쪽 bar를 transform: rotate(180deg);를 이용하여 먼저 돌려주고 오른쪽 bar의 회전이 끝나는 시간에 맞도록 왼쪽 bar에 딜레이를 준 후 똑같이 회전을 시키면 진행 상태가 한 바퀴 돌아가는 형태가 나오게 됩니다. 이 회전을 transform: rotate(360deg);까지 하고 animation-iteration-count: infinite;를 하면 아래와 같은 형태로 반복되는 UI를 만들 수 있으며, 이런 요소는 로딩 UI로도 활용될 수 있습니다.

그리고 javascript를 이용하여 진행되고 있는 애니메이션에 animation-play-state : paused 또는 animation-play-state : running을 주게 되면 진행 정도의 정지와 시작을 조절할 수 있습니다.

See the Pen NWdevPa by WITBLOG (@witblog) on CodePen.

• inline style

javascript를 이용하여 계산된 각도 값을 inline style로 직접 부여하여 회전을 시킵니다.
50% 이하일 경우에는 오른쪽 bar의 각도 계산만 하며 계산식은 deg = 18 * percent / 5 입니다.
50%를 넘을 경우에는 오른쪽 bar를 180도 돌리고 왼쪽 bar의 각도 계산은 deg = 18 * (percent - 50) / 5 를 해줍니다.

예를 들어, 30%는 오른쪽 bar만 회전 시키며 deg = 18 * 30 / 5 로 108deg를 회전시키면 됩니다.
60%는 오른쪽 bar는 180deg 회전시키고 왼쪽 bar는 deg = 18 * (60 - 50) / 5 36deg를 회전시키면 됩니다.

See the Pen GRrPvJN by WITBLOG (@witblog) on CodePen.


SVG로 만들기

SVG를 이용하면 좌우 요소를 나눌 필요 없이 간단한 구조로 구현이 가능합니다.

UI 구현 

1. 먼저 SVG 내부에 원형 프로그레스 바의 영역을 만들어줍니다.

<circle class="progress__meter" cx="60" cy="60" r="54" stroke-width="12" />

2. 앞서 만든 원형 영역 위에 겹치도록 원형상태 표시 바를 추가합니다.

<circle class="progress__ing" cx="60" cy="60" r="54" stroke-width="12" />

3. 진행 상태를 나타낼 circle 요소는 stroke-dasharraystroke-dashoffset 속성을 가지며, 두 값은 원의 둘레 길이만큼 가집니다.
이렇게 값을 주면 진행 상태 circle이 보이지 않고 앞서 만든 기본틀만 보이게 됩니다.

stroke-dasharray
SVG 모양의 획에 대시를 만드는 데 사용됩니다. 숫자가 클수록 획의 대시 사이에 넓은 공간을 만듭니다.

stroke-dashoffset
stroke가 시작되는 위치를 변경하는데 사용됩니다. 숫자가 클수록 시작점으로부터 더 많이 띄워준 다음 시작을 합니다.


상태 제어

진행 상태를 나타내는 circle 요소의 원둘레 길이에서 원하는 만큼의 퍼센트 값을 빼는 방식으로 stroke-dashoffset 값에 변화를 주어 circle progress bar 상태를 조절합니다. 이미 stroke-dashoffset 값과 stroke-dasharray 값에는 원 둘레 만큼 들어가 있기 때문에 아무런 진행 상태도 보이지 않은 상태입니다.

여기서, stroke-dashoffset 값을 조금씩 감소시켜주면 진행 상태 circle이 조금씩 보이게 됩니다.

예를 들어서, 30%를 나타내기 위해서는 전체 원둘레 2 * π * r(반지름)에서 2 * π * r * 0.3을 뺀 값이 stroke-dashoffset 값이 됩니다. 반지름은 circle 속성으로 들어가는 r 값을 넣어주면 됩니다. 변경되는 stroke-dashoffset의 계산식은 2 * π * r * (1 - percent)이며, 이 값을 계산하여 javascript로 적용하면 됩니다.

var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
var progress = value / 100;
var dashoffset = CIRCUMFERENCE * (1 - progress);

See the Pen svg+js by WITBLOG (@witblog) on CodePen.

SVG Line Art, Line Animation

위에서 설명한 SVG stroke-dashoffset, stroke-dasharray 을 이용하면 Circle Progress Bar 뿐만 아니라 다양한 선 애니메이션을 만들어 적용할 수 있습니다.

UI 구현

1. SVG 내부에 pathcircle 등 stroke-dashoffsetstroke-dasharray를 사용할 수 있는 요소로 이미지를 만듭니다.이 부분은 일러스트를 사용하여 제작하시는 것을 추천드립니다.

2. javascript를 통해 해당 요소들의 총 길이만큼 stroke-dashoffsetstroke-dasharray 부여합니다.
getTotalLength()를 사용하면 총 길이를 쉽게 얻을 수 있습니다.
이렇게 속성값을 부여하면 처음에는 아무런 이미지도 보이지 않게 됩니다.

3. 마지막으로 animation을 통해 내부 요소 모두를 stroke-dashoffset를 0으로 만들어 주면 요소의 시작점부터 끝까지 선을 그리는 것처럼 그림을 그리는 효과를 줄 수 있습니다.

See the Pen svg line animation by WITBLOG (@witblog) on CodePen.

브라우저 지원

SVG를 지원하는 모든 브라우저에서 구현 가능하지만(참고), IE는 SVG animation을 지원하지 않기 때문에 javascript를 통해 stroke-dashoffset값을 변경하여 구현해야 합니다.
다만, IE 11에서 일부 SVG 렌더링에 문제가 있고 알려진 해결 방법은 stroke-dashoffset값이 변경될 때마다 해당 SVG를 재 렌더링 시키는 방법으로 보여집니다.(참고)
해당 이슈 관련하여 많이 알려진 SVG animation 라이브러리들은 별도로 IE 대응을 하고 있는 것으로 보이며, vivus의 경우 foreceRender라는 전용 옵션 제공하고 있습니다. (Troubleshoot)

See the Pen d값 재설정으로 인한 재렌더링 by WITBLOG (@witblog) on CodePen.

마치며

Circle Progress Bar를 만드는 방법 중 SVG의 속성들을 이용하여 막대 Progress Bar 처럼 정확한 퍼센트를 나타낼 수 있다는 점이 흥미로웠습니다.
또한, SVG를 이용하여 Line art도 구현할 수 있어, 그림 그리기를 좋아하시는 분들은 이 방식을 통해 이미지들을 재미있게 표현할 수 있을 것 같다는 생각을 했습니다.

끝까지 글 읽어 주셔서 감사합니다!

참고


0개의 댓글

답글 남기기

아바타 플레이스홀더

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다