GODRICH
#css애니메이션#버튼#로딩#전환효과#스크롤#대시보드#실전ui#디자인트렌드

그래프 애니메이션 css 피커 9가지 — 값 하나로 다시 그리기

그래프 애니메이션 css 아홉 개를 나란히 두고 보면 막대를 픽셀 위치로만 옮기면 그래프가 실제 값과 어긋난다 — 그래서 값 하나로 히스토그램 막대 높이를 다시 계산하는 피커, 원호 길이를 채우는 게이지 피커, 지나온 값을 꺾은선으로 남기는 스파크라인 피커까지 아홉 가지를 본다.

자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip

01드래그할 때마다 막대 높이가 다시 계산되는 히스토그램 피커

드래그로 값을 옮기면 그 값이 12개 구간 중 어디에 속하는지부터 계산합니다. 해당 구간(BUCKET_COUNT)의 막대만 기준 높이 위에 추가 높이(PEAK_BOOST)를 더해 올리고, 나머지 열한 개 막대는 기준 높이 그대로 둡니다. css 막대 그래프 애니메이션을 값 하나로 다시 계산해 그리는 대표적인 예입니다.

드래그할 때마다 막대 높이가 다시 계산되는 히스토그램 피커
새 창에서 열기

01 · 드래그할 때마다 막대 높이가 다시 계산되는 히스토그램 피커 — 측정 누적면적 23.203% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

BUCKET_COUNTPEAK_BOOSTCHART_H
function bucketOf(v) {
  var idx = Math.floor(v / 100 * BUCKET_COUNT);
  return Math.max(0, Math.min(BUCKET_COUNT - 1, idx));
}

function fracIn(v, bucket) {
  var raw = v / 100 * BUCKET_COUNT - bucket;
  return Math.max(0, Math.min(1, raw));
}

// 구간 하나만 목표 높이를 다시 계산한다 — 나머지는 기준 높이 그대로
function recompute() {
  var b = bucketOf(value);
  var f = fracIn(value, b);
  for (var i = 0; i < BUCKET_COUNT; i++) {
    targetH[i] = BASE[i];
  }
  targetH[b] = Math.min(0.96, BASE[b] + PEAK_BOOST * (0.4 + 0.6 * f));
  return b;
}

02값만큼 원호가 채워지는 방사형 게이지 피커

핸들을 원 둘레를 따라 돌리면 포인터 좌표를 중심 기준 각도(Math.atan2)로 바꾸고, 그 각도가 시작각(START)·끝각(END) 범위를 벗어나지 않도록 보정합니다. 보정된 각도까지 원호 하나를 새로 그려 값이 늘수록 호가 길어지고 줄면 짧아지도록 합니다. css 원형 그래프 애니메이션에서 흔한 방식이지만, 이 항목은 각도와 원호 경로(d 속성)를 매 프레임 직접 계산해 다시 그립니다.

값만큼 원호가 채워지는 방사형 게이지 피커
새 창에서 열기

02 · 값만큼 원호가 채워지는 방사형 게이지 피커 — 측정 누적면적 9.973% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

STARTENDMath.atan2
function arcPath(cx, cy, r, a0, a1) {
  if (Math.abs(a1 - a0) < 0.5) return '';
  var s = polar(cx, cy, r, a0), e = polar(cx, cy, r, a1);
  var large = (a1 - a0) > 180 ? 1 : 0;
  return 'M ' + s.x + ' ' + s.y + ' A ' + r + ' ' + r + ' 0 ' + large + ' 1 ' + e.x + ' ' + e.y;
}

function angleOf(v) { return START + (SWEEP * v) / 100; }

function paint() {
  track.setAttribute('d', arcPath(CX, CY, R, START, END));
  fill.setAttribute('d', arcPath(CX, CY, R, START, angleOf(current)));
  var p = polar(CX, CY, R, angleOf(current));
  grab.style.left = (p.x / 480 * 100) + '%';
  grab.style.top = (p.y / 300 * 100) + '%';
  var rv = Math.round(current);
  numEl.textContent = rv + '%';
  valEl.textContent = String(rv);
  grab.setAttribute('aria-valuenow', String(rv));
  grab.setAttribute('aria-valuetext', '레벨 ' + rv + '%');
}

03드래그 궤적이 꺾은선 그래프로 남는 스파크라인 피커

드래그하는 동안 지나온 값을 좌표 배열(TRAIL_LENGTH개)에 계속 쌓아 그 배열 전체를 하나의 꺾은선 경로로 다시 그립니다. 배열 길이가 고정돼 있어 새 값이 들어오면 가장 오래된 값이 밀려나며, 지금 값이 아니라 값이 움직여 온 궤적 전체가 갱신됩니다.

드래그 궤적이 꺾은선 그래프로 남는 스파크라인 피커
새 창에서 열기

03 · 드래그 궤적이 꺾은선 그래프로 남는 스파크라인 피커 — 측정 누적면적 32.755% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

TRAIL_LENGTHCHART_WSTEP
function buildPoints() {
  var step = CHART_W / (TRAIL_LENGTH - 1);
  var pts = [];
  for (var i = 0; i < TRAIL_LENGTH; i++) pts.push([i * step, yOf(trail[i])]);
  return pts;
}

function paint() {
  var pts = buildPoints();
  var d = 'M ' + pts[0][0] + ' ' + pts[0][1];
  for (var i = 1; i < pts.length; i++) d += ' L ' + pts[i][0] + ' ' + pts[i][1];
  lineEl.setAttribute('d', d);
  areaEl.setAttribute('d', d + ' L ' + pts[pts.length - 1][0] + ' ' + CHART_H + ' L ' + pts[0][0] + ' ' + CHART_H + ' Z');
  var last = pts[pts.length - 1];
  dotEl.setAttribute('cx', String(last[0]));
  dotEl.setAttribute('cy', String(last[1]));
  var rv = Math.round(current);
  valEl.textContent = String(rv);
  grab.style.left = value + '%';
  grab.setAttribute('aria-valuenow', String(Math.round(value)));
  grab.setAttribute('aria-valuetext', '값 ' + Math.round(value));
}

04값 비율만큼 조각이 늘어나는 도넛 피커

선택한 값을 전체 100에서 뺀 나머지를 고정 비율(OTHER_RATIO)로 나머지 세 조각에 배분한 뒤, 네 조각의 각도를 한 번에 다시 계산합니다. 한 조각이 커지면 나머지 세 조각이 정해진 비율을 유지한 채 함께 줄어들어, 원 전체는 항상 360도를 유지합니다.

값 비율만큼 조각이 늘어나는 도넛 피커
새 창에서 열기

04 · 값 비율만큼 조각이 늘어나는 도넛 피커 — 측정 누적면적 12.204% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

LABELSOTHER_RATIOSTROKE
function recompute(v) {
  var rest = 100 - v;
  pct = [v, rest * OTHER_RATIO[0], rest * OTHER_RATIO[1], rest * OTHER_RATIO[2]];
}

function paint() {
  recompute(current);
  var start = -90, a = start;
  for (var i = 0; i < 4; i++) {
    var sweep = pct[i] * 3.6;
    var a1 = a + sweep;
    segEls[i].setAttribute('d', arcPath(CX, CY, R, a, a1));
    a = a1;
  }
  var rv = Math.round(current);
  numEl.textContent = rv + '%';
  capEl.textContent = LABELS[0];
  valEl.textContent = String(rv);
  grab.style.left = ((value - MIN_V) / (MAX_V - MIN_V) * 100) + '%';
  grab.setAttribute('aria-valuenow', String(rv));
  grab.setAttribute('aria-valuetext', 'A 조각 ' + rv + '%');
  var rows = '';
  for (var j = 0; j < 4; j++) rows += '<tr><th>' + LABELS[j] + '</th><td>' + Math.round(pct[j]) + '%</td></tr>';
  srBody.innerHTML = rows;
}

05축마다 점을 끌면 모양이 다시 그려지는 레이더 피커

다섯 축(AXIS_COUNT)의 값을 각도와 반지름으로 바꿔 극좌표 점을 찍고, 그 점을 순서대로 이은 다각형 경로를 값이 바뀔 때마다 다시 계산합니다. 드래그로 조정하는 축은 A 하나뿐이고 나머지 네 축은 서로 다른 주기(PERIODS)로 자동 진동해, 다각형이 끊임없이 모양을 바꿉니다.

축마다 점을 끌면 모양이 다시 그려지는 레이더 피커
새 창에서 열기

05 · 축마다 점을 끌면 모양이 다시 그려지는 레이더 피커 — 측정 누적면적 9.604% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

AXIS_COUNTPHASESPERIODS
function paint() {
  var d = '';
  for (var i = 0; i < AXIS_COUNT; i++) {
    var p = polar(CX, CY, R * (current[i] / 100), angleOf(i));
    d += (i === 0 ? 'M ' : 'L ') + p.x + ' ' + p.y;
    pointEls[i].setAttribute('cx', String(p.x));
    pointEls[i].setAttribute('cy', String(p.y));
  }
  polyEl.setAttribute('d', d + ' Z');
  var rv = Math.round(current[0]);
  valEl.textContent = String(rv);
  grab.style.left = ((values[0] - MIN_V) / (MAX_V - MIN_V) * 100) + '%';
  grab.setAttribute('aria-valuenow', String(Math.round(values[0])));
  grab.setAttribute('aria-valuetext', 'A 축 ' + Math.round(values[0]));
  var rows = '';
  for (var j = 0; j < AXIS_COUNT; j++) rows += '<tr><th>' + LABELS[j] + '</th><td>' + Math.round(current[j]) + '</td></tr>';
  srBody.innerHTML = rows;
}

06스크럽한 위치까지 막대가 채워지는 파형 피커

가로 위치를 40개 막대 배열의 인덱스로 바꿔 그 인덱스 이전 막대는 채운 색으로, 이후 막대는 옅은 색으로 다시 칠합니다. 막대 높이(HEIGHTS) 자체는 고정값이라 바뀌지 않고, 어디까지 지나왔는지를 색 경계로만 표시합니다.

스크럽한 위치까지 막대가 채워지는 파형 피커
새 창에서 열기

06 · 스크럽한 위치까지 막대가 채워지는 파형 피커 — 측정 누적면적 23.116% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

BAR_WHEIGHTSGAP
function buildBars() {
  var html = '';
  for (var i = 0; i < N; i++) {
    var h = HEIGHTS[i] * CHART_H;
    var x = i * BAR_W + GAP / 2;
    var w = Math.max(1, BAR_W - GAP);
    html += '<rect class="wf__bar" id="wb' + i + '" x="' + x + '" y="' + (CHART_H - h) + '" width="' + w + '" height="' + h + '"></rect>';
  }
  barsG.innerHTML = html;
  for (var j = 0; j < N; j++) barEls.push(document.getElementById('wb' + j));
}

function paint() {
  var activeIdx = Math.round((current / 100) * N);
  for (var i = 0; i < N; i++) barEls[i].classList.toggle('is-past', i < activeIdx);
  var x = (current / 100) * 480;
  headline.setAttribute('x1', String(x));
  headline.setAttribute('x2', String(x));
  var rv = Math.round(current);
  valEl.textContent = String(rv);
  grab.style.left = value + '%';
  grab.setAttribute('aria-valuenow', String(Math.round(value)));
  grab.setAttribute('aria-valuetext', '재생 위치 ' + Math.round(value) + '%');
}

07값이 궤도를 도는 길이로 바뀌는 오빗 다이얼 피커

포인터 좌표를 중심 기준 각도(Math.atan2)로 바꾸고, 그 각도가 0~360도 범위를 벗어나면 보정합니다. 목표 각도로 곧장 뛰지 않고 매 프레임 현재 호 길이를 목표에 관성 계수(ARC_LERP)만큼 다가가게 해, 궤도를 도는 점이 부드럽게 따라오도록 합니다.

값이 궤도를 도는 길이로 바뀌는 오빗 다이얼 피커
새 창에서 열기

07 · 값이 궤도를 도는 길이로 바뀌는 오빗 다이얼 피커 — 측정 누적면적 9.642% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

ARC_LERPMath.atan2clip-path
function autoStep(dt) {
  autoT += dt;
  var omega = 2 * Math.PI / AUTO_PERIOD;
  value = 50 + 46 * Math.sin(autoT * omega);
}

function frame(ts) {
  if (!lastTs) lastTs = ts;
  var dt = Math.min(0.05, (ts - lastTs) / 1000);
  lastTs = ts;
  if (!manual) autoStep(dt);
  current += (value - current) * ARC_LERP;
  paint();
  rafId = requestAnimationFrame(frame);
}

08값이 셀 밝기로 바뀌는 히트맵 피커

선택한 값을 정해둔 최대값(MAX_V)으로 나눈 비율을 배경 투명도로 바꿔 대표 칸 하나만 밝기를 다시 칠합니다. 나머지 여덟 칸은 페이지가 열릴 때 한 번 정해진 고정 비율(RATIOS) 그대로 남아 있어, 지금 조작 중인 칸이 어디인지 밝기 대비로 바로 드러납니다.

값이 셀 밝기로 바뀌는 히트맵 피커
새 창에서 열기

08 · 값이 셀 밝기로 바뀌는 히트맵 피커 — 측정 누적면적 15.633% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

RATIOSMAX_Vgrid-template-columns
function buildStatic() {
  var legendHtml = '';
  for (var i = 0; i < N; i++) {
    var cell = document.createElement('div');
    cell.className = 'hm__cell';
    cell.style.background = colorFor(RATIOS[i]);
    grid.appendChild(cell);
    legendHtml += '<li>고정 칸 ' + (i + 1) + ': ' + Math.round(RATIOS[i] * 100) + '%</li>';
  }
  legend.innerHTML = legendHtml;
}

function paint() {
  var ratio = current / MAX_V;
  hero.style.background = colorFor(ratio);
  var rv = Math.round(current);
  valEl.textContent = String(rv);
  grab.style.left = value + '%';
  grab.setAttribute('aria-valuenow', String(Math.round(value)));
  grab.setAttribute('aria-valuetext', '선택 셀 ' + Math.round(value) + '%');
}

09값 크기만큼 블록이 다시 나뉘는 트리맵 피커

A 항목의 값을 조정하면 남는 값(100-A)을 고정 비율(OTHER_RATIO)로 B·C·D 세 블록에 다시 나누고, 네 블록의 너비·높이를 전부 다시 계산합니다. 달력 선택 UI 9종 — 복붙하면 되는 편의 트랙형 드래그 입력과 방식은 같지만, 이 항목은 값 하나가 아니라 사각형 넓이 네 개를 통째로 재배분하는 그래프입니다.

값 크기만큼 블록이 다시 나뉘는 트리맵 피커
새 창에서 열기

09 · 값 크기만큼 블록이 다시 나뉘는 트리맵 피커 — 측정 누적면적 24.647% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

OTHER_RATIOMIN_Vclip-path
  var rest = 100 - a;
  var b = rest * OTHER_RATIO[0];
  var c = rest * OTHER_RATIO[1];
  var d = rest * OTHER_RATIO[2];

  blkA.style.width = a + '%';
  blkA.style.height = '100%';
  blkA.style.left = '0%';
  blkA.style.top = '0%';

  var colW = 100 - a;
  var bH = rest > 0.001 ? (b / rest) * 100 : 0;
  var cH = rest > 0.001 ? (c / rest) * 100 : 0;

  blkB.style.left = a + '%';
  blkB.style.width = colW + '%';
  blkB.style.top = '0%';
  blkB.style.height = bH + '%';

  blkC.style.left = a + '%';
  blkC.style.width = colW + '%';
  blkC.style.top = bH + '%';
  blkC.style.height = cH + '%';

  blkD.style.left = a + '%';

그래프 애니메이션 사이트에서 본 예제를 대시보드 어디에 붙이나

관리자 대시보드의 필터 패널에는 01 의 히스토그램이 맞습니다. 가격대·나이대처럼 구간이 정해진 값을 고를 때 값이 속한 구간만 다시 계산해 올라가므로, 사용자가 지금 어느 구간을 고르고 있는지 막대 하나로 바로 보입니다.

시세·점수처럼 값이 계속 바뀌는 화면에는 03 의 스파크라인이 어울립니다. 지금 값만 보여주는 게이지와 달리 지나온 값을 궤적으로 남기기 때문에, 슬라이더를 움직이는 동안 값이 어떻게 변해왔는지가 그래프 자체에 기록됩니다.

예산·용량 배분 화면에는 09 의 트리맵이 맞습니다. 한 항목의 비중을 늘리면 나머지 항목이 자동으로 줄어드는 모습이 블록 넓이로 바로 드러나, 합이 항상 100을 유지한다는 사실을 숫자보다 면적으로 먼저 확인할 수 있습니다. 픽셀 좌표만 옮기는 예시가 많은 자리에 이 아홉 가지를 옮겨 붙이기 전에는 계산 축부터 확인해 두는 편이 낫습니다.

값이 픽셀이 아니라 계산으로 그려지는 이유

좌표를 드래그한 거리만큼만 옮기면 핸들 위치와 그래프가 보여주는 값이 어긋나기 쉽습니다. 트랙 너비가 바뀌거나 핸들을 화살표 키로 옮기면 픽셀 이동량과 값의 대응 관계가 깨지기 때문입니다. 아홉 항목은 전부 포인터·키보드 입력을 먼저 값(항목별 범위)으로 바꾼 뒤, 그 값을 막대 높이·원호 각도·조각 비율 같은 그래프 고유의 계산식에 넣어 매 프레임 다시 그립니다. resize 리스너는 아홉 항목 전부에 붙어 있어, 트랙 크기가 바뀌면 픽셀이 아니라 다시 계산한 값을 기준으로 그래프를 새로 그립니다.

아홉 항목이 화면에 남긴 면적과 프레임 수

항목 누적 면적 움직인 프레임
01 히스토그램 버킷 23.2% 23/23
02 방사형 게이지 10.0% 23/23
03 스파크라인 궤적 32.8% 23/23
04 도넛 조각 12.2% 23/23
05 레이더 다축 9.6% 23/23
06 파형 스크럽 23.1% 23/23
07 오빗 다이얼 9.6% 23/23
08 히트맵 강도 15.6% 23/23
09 트리맵 블록 24.6% 23/23

아홉 항목 모두 23/23 이 나온 것은 자동 시연 루프가 매 프레임 값을 미세하게라도 바꾸기 때문입니다. 면적 차이는 그래프 형태에서 옵니다 — 05 와 07 처럼 얇은 선·점으로만 그려지는 항목은 채워지는 픽셀 자체가 적어 9%대에 머물고, 03 과 09 처럼 면 전체를 다시 칠하거나 나누는 항목은 32%대까지 올라갑니다. 01 과 06 처럼 막대 다수가 동시에 색이나 높이를 바꾸는 항목도 23% 안팎으로 중간에 자리합니다.

화살표 키가 먼저 반응해야 접근성이 완성됩니다

아홉 항목 모두 핸들에 role="slider"와 aria-valuenow·aria-valuetext를 붙이고, 값이 바뀔 때마다 aria-live 영역에 현재 값을 문장으로 알립니다. 화살표 키를 누르면 포인터 드래그와 똑같이 setValue를 거쳐 값이 바뀌므로 마우스 없이도 그래프 전체를 조작할 수 있습니다. prefers-reduced-motion이 감지되면 자동 시연 루프가 멈추는 것은 물론, 포인터·키보드로 값을 직접 바꿀 때도 관성 보간을 건너뛰고 목표 값으로 즉시 넘어가 화면이 계속 흔들리는 것을 막습니다.

세 값을 바꾸면 그래프가 계산하는 축이 달라집니다

항목 값 느낌
01 BUCKET_COUNT 12 → 24 구간 개수 값을 12에서 24로 늘리면 막대 하나하나가 더 좁게 나뉘어 계산되는 히스토그램이 됩니다 — BUCKET_COUNT 상수만 바꾸면 되고 나머지 배분·보간 로직은 그대로 재사용됩니다.
03 TRAIL_LENGTH 48 → 96 궤적 길이 값을 48에서 96으로 늘리면 더 오래된 값까지 꺾은선에 남아 궤적이 두 배로 길어집니다 — TRAIL_LENGTH 상수만 바꾸면 되고 좌표 배열을 쌓고 미는 로직은 그대로입니다.
07 ARC_LERP 0.18 → 0.08 보간 계수 값을 0.18에서 0.08로 낮추면 호 길이가 목표 각도를 따라잡는 데 더 오래 걸려 뒤늦게 따라가는 동작이 됩니다 — ARC_LERP 상수만 바꾸면 되고 매 프레임 다가가는 lerp 로직은 그대로입니다.

각도를 wrap 보정하지 않으면 게이지가 튕기는 함정

02 와 07 은 포인터 좌표를 Math.atan2()로 각도로 바꾸는데, 이 함수가 돌려주는 값은 -180~180도 범위입니다. 시작각(135도·-90도)을 기준으로 한 값 범위와 이 범위가 어긋나므로, while (deg < START) deg += 360; 같은 보정을 빼면 핸들이 시작각 부근을 지날 때 값이 100에서 0으로 순간 튀는 함정에 걸립니다.

spguctjy 09 도 비슷한 함정을 품고 있습니다. B·C·D 세 블록의 높이를 rest(100에서 A를 뺀 값)로 나눠 비율을 구하는데, A 가 100 에 가까워져 rest 가 0 에 근접하면 나눗셈이 불안정해집니다. 소스가 rest > 0.001 일 때만 나누고 그렇지 않으면 0 을 쓰는 이유가 여기 있습니다 — 이 방어 코드를 빼고 값을 옮기면 A 가 최대값 근처일 때 나머지 블록 높이가 NaN 이나 Infinity 로 깨집니다.

264 대시보드 편·224 피커 편과는 무엇이 다른가요?

대시보드 차트 디자인 인터랙션 9종 — 호버부터 드릴다운까지 편은 이미 그려진 그래프 위에서 호버·드릴다운처럼 보는 방식을 바꾸는 상호작용을 다룹니다. 그래프 자체의 좌표·비율 계산은 고정돼 있고, 사용자 입력은 어떤 값을 강조해 보여줄지만 바꿉니다.

달력 선택 UI 9종 — 복붙하면 되는 편은 반대로 피커이지만 그래프가 없습니다 — 값 하나를 고르면 그 값이 텍스트나 트랙 색으로만 반영됩니다. 이 편은 그 사이에 있습니다. 피커로 값을 바꾸면 그 값이 그래프의 형태(막대 높이·호 길이·조각 비율)를 다시 계산해 그리므로, 피커도 그래프도 매 프레임 같이 움직입니다.

세 편을 함께 보면 상호작용의 층이 다릅니다 — 264 는 이미 그려진 그래프의 보는 방식을 바꾸고, 224 는 값을 고르는 데서 끝나며, 이 편은 고른 값이 그래프 계산식 자체에 들어가 막대·호·조각의 모양을 새로 만듭니다. 셋 중 어느 쪽이 필요한지는 값이 바뀔 때 그래프의 좌표까지 다시 계산해야 하는지로 가르면 됩니다.

그래프 애니메이션 css 피커에 자주 나오는 질문

아홉 개 모두 requestAnimationFrame 으로 도나요, CSS transition 은 안 쓰나요?

네, 아홉 항목 모두 requestAnimationFrame 루프 하나가 값을 목표로 보간하고 매 프레임 paint()를 다시 부릅니다. 막대 rect·경로 d·블록 width·height 처럼 그래프 자체가 매 프레임 새 좌표로 다시 계산되는 값이라, 시작·끝 두 상태만 오가는 CSS transition 으로는 이 계산을 대신할 수 없습니다.

데이터를 실시간으로 받아오지 않는 이유는 무엇인가요?

아홉 항목의 표본 값은 전부 고정 배열이거나 고정 주기의 사인파로 만든 합성 값이라 Math.random·fetch·localStorage를 하나도 쓰지 않습니다. 같은 조작을 반복하면 항상 같은 그래프가 나오도록 만든 데모용 결정값이며, 실제 서비스에 옮길 때는 이 표본 배열 자리에 API 응답을 넣으면 됩니다.

다른 그래프 애니메이션 사이트 예제와 비교하려면 어떻게 하나요?

zip 안 index.html 아홉 개를 열어 보면 각 항목이 BUCKET_COUNT·TRAIL_LENGTH·ARC_LERP 같은 상수 몇 개와 paint() 함수 하나로 이뤄져 있어, 다른 그래프 애니메이션 사이트 예제와 나란히 놓고 계산 로직만 비교하기 쉽습니다.

압축 비밀번호를 입력하세요

비밀번호는 이 글 본문 안에 있습니다. 읽다 보면 나옵니다.