FunnelChart
SVG로 그리는 깔때기·피라미드 차트 컴포넌트.
개요
첫 시리즈의 행을 단계(세그먼트)로 그립니다. 세그먼트 높이는 값에 비례하고, 값이 큰 항목이 넓은 쪽에 옵니다.
주요 특징
- ✅ 도형:
shape로 깔때기("funnel")·피라미드("pyramid") - ✅ 깔때기 목:
neckWidth·neckHeight비율 - ✅ 숫자 서식:
thousandSeparator로 툴팁 값에 구분자 - ✅ 범례 토글: 범례 항목을 눌러 세그먼트 숨김·표시
- ✅ 컨테이너: 제목·도구·검색 폼·접기
- ✅ 빈 상태: 데이터가 없으면 안내 문구
기본 사용
series에 시리즈를 넘깁니다. 첫 시리즈만 쓰고, xKey는 단계 이름, yKey는 값 필드입니다. 기본 도형은 깔때기이고 값 내림차순으로 위부터 쌓습니다. 범례는 위에 놓이고 그리는(정렬된) 순서로 나열합니다.
Preview
피라미드 (shape=“pyramid”)
꼭짓점이 위인 삼각형입니다. 값 오름차순이라 작은 값이 위에 옵니다.
Preview
깔때기 목 (neckWidth, neckHeight)
목의 너비·높이를 전체 대비 비율(0~1)로 정합니다. 기본은 0.3·0.25이고 shape="funnel"에서만 씁니다.
Preview
범례·툴팁 끄기 (legend, tooltip)
둘 다 기본으로 켜져 있습니다.
Preview
천 단위 구분자 (thousandSeparator)
툴팁 값에 걸립니다. 세그먼트에 마우스를 올려 확인합니다.
Preview
색상 (colors)
행(입력) 순서대로 쓰고, 모자라면 처음부터 다시 씁니다. 정렬해도 항목마다 색이 그대로라 깔때기와 피라미드에서 같은 색이고, 범례 색도 같습니다. 이 예는 입력 순서가 값 순서와 다른 데이터라, 위에서부터가 아니라 행 순서(구매·방문·재구매·관심·검토)대로 색이 붙습니다.
Preview
범례 클릭 토글 (legendToggle)
범례 항목을 누르면 그 세그먼트를 빼고 남은 항목이 전체 높이를 나눕니다. 숨긴 항목은 범례에 흐리게 남아 다시 누르면 돌아옵니다. 이름이 같은 항목도 따로 그리고 따로 숨기며, 범례·툴팁에는 그 이름이 그대로 보입니다. 기본으로 켜져 있고 legendToggle={false}로 끕니다.
Preview
포인트 클릭 (onPointClick)
세그먼트를 누르면 단계 이름·인덱스(입력 순서), X값(단계 이름)·Y값(값), 클릭한 세그먼트의 원본 행(payload)을 넘깁니다. payload는 series[0].data[j] 그 객체입니다.
Preview
세그먼트를 클릭하세요
제목·도구·검색 폼 (title, actions, searchContent)
title을 주면 접고 펼 수 있는 머리가 생깁니다. actions는 머리 오른쪽에, searchContent는 차트 위 검색 폼 자리에 그립니다. 검색 폼은 24칸 격자이고 searchColumns·searchColGap·searchRowGap으로 바꿉니다. title이 없으면 actions·검색 폼·접기 props는 쓰이지 않습니다.
Preview
접기 (defaultCollapsed, collapseDisabled)
title이 있을 때 씁니다. 위는 접힌 채 시작하고, 아래는 접고 펼 수 없습니다.
Preview
빈 상태
데이터가 없으면 emptyText를 보입니다.
Preview
데이터가 없습니다
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
series | FunnelChartSeries<Row>[] | - | 시리즈 배열. 첫 시리즈만 쓴다 |
shape | "funnel" | "pyramid" | "funnel" | 도형. funnel은 값 내림차순, pyramid는 오름차순으로 쌓는다 |
neckWidth | number | 0.3 | 깔때기 목 너비 비율(0–1). shape="funnel"에서만 쓴다 |
neckHeight | number | 0.25 | 깔때기 목 높이 비율(0–1). shape="funnel"에서만 쓴다 |
colors | string[] | 기본 8색 | 행(입력) 순서대로 쓰는 색. 정렬과 무관하고 범례 색도 같다. 모자라면 처음부터 다시 쓴다 |
legend | boolean | true | 범례 표시 |
legendToggle | boolean | true | 범례 항목을 눌러 항목 숨김·표시. 숨긴 항목은 범례에 흐리게 남는다 |
tooltip | boolean | true | 툴팁 표시 |
thousandSeparator | boolean | false | 천 단위 구분자. 툴팁 |
height | number | 350 | 차트 높이 (px) |
emptyText | string | "데이터가 없습니다" | 데이터가 없을 때 문구. 값이 전부 0이면 빈 상태가 아니라 높이 0 세그먼트와 범례를 그린다 |
onPointClick | (data: FunnelChartPointClickData<Row>) => void | - | 세그먼트 클릭 콜백. payload는 원본 행 |
title | ReactNode | - | 제목. 주면 접고 펼 수 있는 머리가 생긴다 |
actions | ReactNode | - | title이 있을 때. 머리 오른쪽 도구 영역 |
defaultCollapsed | boolean | false | title이 있을 때. 접힌 채 시작 |
collapseDisabled | boolean | false | title이 있을 때. 접기·펼치기 막기 |
searchContent | ReactNode | - | title이 있을 때. 검색 폼 영역 (FormCol 등) |
searchColumns | number | 24 | title이 있을 때. 검색 폼 격자 칸 수 |
searchColGap | number | 15 | title이 있을 때. 검색 폼 가로 간격 (px) |
searchRowGap | number | 20 | title이 있을 때. 검색 폼 세로 간격 (px) |
readOnly | boolean | - | title이 있을 때. 검색 폼 읽기 전용 |
className | string | - | 차트 루트 CSS 클래스 |
style | CSSProperties | - | 차트 루트 인라인 스타일 |
FunnelChartSeries
| Field | Type | Required | Description |
|---|---|---|---|
data | Row[] | ✅ | 데이터 행 배열 |
xKey | string | ✅ | 항목 이름을 읽을 행 필드 키 |
yKey | string | ✅ | 값을 읽을 행 필드 키 |
name | string | - | 쓰지 않는다 (범례·툴팁은 항목 이름) |
FunnelChartPointClickData
| Field | Type | Description |
|---|---|---|
seriesName | string | 항목 이름 |
seriesIndex | number | 항목의 행(입력) 인덱스. 정렬·숨김과 무관하고 깔때기·피라미드에서 같다 |
xValue | unknown | 항목 이름 (행의 원값) |
yValue | unknown | 값 (행의 원값) |
payload | Row | 클릭한 세그먼트의 원본 행 (series[0].data[j] 그 객체. 정렬 뒤에도 원래 행) |
행 타입 (Row)
Props·Series·PointClickData는 행 타입 Row를 받습니다(기본 Record<string, unknown>). series의 data에서 추론되므로 onPointClick의 payload를 형 변환 없이 읽을 수 있습니다.
type SalesRow = { stage: string; count: number; code: string }
const rows: SalesRow[] = [/* … */]
<FunnelChart
series={[{ data: rows, xKey: "stage", yKey: "count" }]}
onPointClick={(d) => openDetail(d.payload.code)} // d.payload: SalesRow
/>접근성
권장 사항
- ✅ 빈 차트 시 대체 텍스트(emptyText) 제공
- ✅ 범례 항목은
aria-pressed버튼이라 키보드로 토글할 수 있다