데이터 시각화
시각화 원칙
ON:GI 차트는 D3.js로 스케일 · 축 · 도형을 계산하고 React SVG로 렌더링합니다. 사장님과 운영자가 ‘오늘 장사가 어땠는지’를 3초 안에 파악하도록, 장식 없이 수치와 추세에 집중합니다.
- 엔진
- D3.js v7 (scale · shape · array · timer)
- 렌더링
- React SVG (선언형)
- 차트
- 8종
- 접근성
- aria 요약 · 키보드 탐색
차트 갤러리
5가지 원칙
팔레트
Categorical — 계열 구분
순서대로 사용합니다. 계열이 6개를 넘으면 상위 5개 + ‘기타(--viz-7)’로 묶습니다.
viz-17C3AED
viz-23182F6
viz-312B886
viz-4FFB020
viz-5F0506E
viz-622B8CF
viz-78B95A1
Sequential — 크기 · 밀도
히트맵 · 코로플레스 등 연속 값. 7단계 퍼플, 다크 모드에서는 밝을수록 큰 값으로 반전됩니다.
0
1
2
3
4
5
6
차트 선택 가이드
숫자 포맷
구현 구조
D3는 계산만, DOM은 React가 소유합니다. d3.select로 DOM을 직접 조작하지 않아 React 상태와 충돌하지 않습니다.
components/charts/line-chart.tsx (요약)
"use client";
import { scaleTime, scaleLinear, line, curveMonotoneX, bisector } from "d3";
export function LineChart({ series, height = 280 }: Props) {
const [ref, width] = useChartWidth(); // ResizeObserver
const t = useEnterProgress(900); // d3.timer + easeCubicOut (0 → 1)
const x = scaleTime().domain(extent).range([0, innerW]);
const y = scaleLinear().domain([0, max]).nice(4).range([innerH, 0]);
const path = line<Point>().x(d => x(d.x)).y(d => y(d.y)).curve(curveMonotoneX);
return (
<svg role="img" aria-label="…" tabIndex={0} onKeyDown={arrowKeyNav}>
{y.ticks(4).map(tick => <GridLine key={tick} y={y(tick)} />)}
<clipPath id="reveal"><rect width={innerW * t} /></clipPath>
<path d={path(values)} clipPath="url(#reveal)" stroke="var(--viz-1)" />
</svg>
);
}서버 컴포넌트에서 데이터 넘기기
차트는 클라이언트 컴포넌트입니다. 서버에서 집계한 값을{ x: Date, y: number }[] 형태로 넘기면 되고, 포맷 함수처럼 함수 props가 필요하면 클라이언트 래퍼 안에서 지정하세요.사용 규칙
이렇게 하세요
- y축은 0부터 (막대는 필수, 선은 권장)
- 비교 기간은 회색 점선
- 데이터가 없으면 차트 대신 EmptyState
이렇게 하지 마세요
- 파이 · 도넛에 6개 이상 조각
- 이중 축에 같은 단위 사용
- 무지개 팔레트 · 그라데이션 막대