SankeyChart
Data Visualization
visx 기반 생키 다이어그램.
Usage
import
API Reference
예제
Usage
여러 단계 사이에서 항목이나 양이 어디로 이동하는지 흐름 너비로 표현할 때 사용한다.
import
import
import { SankeyChart } from '@mildang/design-system/Chart';예제를 복사해 쓸 때 필요한 준비
• @mildang/styled-system 은 이 저장소에서 Panda 가 생성하는 산출물이다. 저장소 안에서는 turbo run ship 이후 쓸 수 있고, 패키지 소비자는 자기 Panda 산출물이나 다른 레이아웃 수단으로 바꿔야 한다.
API Reference
SankeyChart Props
Prop
Type
Default
links
필수
SankeyChartLink[]
지정 안 함
nodes
필수
SankeyChartNode[]
지정 안 함
className
string
지정 안 함
colors
string[]
지정 안 함
formatValue
(value: number) => string
(value: number) => value.toLocaleString()
legendPosition
"bottom" | "left" | "right" | "top"
bottom
linkOpacity
number
0.3
margin
Partial<ChartMargin>
지정 안 함
nodePadding
number
12
nodeWidth
number
16
showLabels
boolean
true
showLegend
boolean
false
showTooltip
boolean
false
valueLabel
string
값
예제
기본
import { SankeyChart } from '@mildang/design-system/Chart';
// 학년 → 계열 → 진로 흐름 (명 단위)
const careerNodes = [
{ id: '고1', label: '고1' },
{ id: '고2', label: '고2' },
{ id: '문과', label: '문과' },
{ id: '이과', label: '이과' },
{ id: '인문대', label: '인문대' },
{ id: '공대', label: '공대' },
{ id: '의대', label: '의대' },
];
const careerLinks = [
{ source: '고1', target: '문과', value: 80 },
{ source: '고1', target: '이과', value: 120 },
{ source: '고2', target: '문과', value: 60 },
{ source: '고2', target: '이과', value: 90 },
{ source: '문과', target: '인문대', value: 140 },
{ source: '이과', target: '공대', value: 150 },
{ source: '이과', target: '의대', value: 60 },
];
const SankeyChartDefaultExample = () => <SankeyChart nodes={careerNodes} links={careerLinks} />;
export default SankeyChartDefaultExample;
Hover Tooltip
import { SankeyChart } from '@mildang/design-system/Chart';
// 학년 → 계열 → 진로 흐름 (명 단위)
const careerNodes = [
{ id: '고1', label: '고1' },
{ id: '고2', label: '고2' },
{ id: '문과', label: '문과' },
{ id: '이과', label: '이과' },
{ id: '인문대', label: '인문대' },
{ id: '공대', label: '공대' },
{ id: '의대', label: '의대' },
];
const careerLinks = [
{ source: '고1', target: '문과', value: 80 },
{ source: '고1', target: '이과', value: 120 },
{ source: '고2', target: '문과', value: 60 },
{ source: '고2', target: '이과', value: 90 },
{ source: '문과', target: '인문대', value: 140 },
{ source: '이과', target: '공대', value: 150 },
{ source: '이과', target: '의대', value: 60 },
];
const SankeyChartHoverTooltipExample = () => <SankeyChart nodes={careerNodes} links={careerLinks} showTooltip valueLabel="학생 수" />;
export default SankeyChartHoverTooltipExample;
라벨 숨김 + 범례
import { SankeyChart } from '@mildang/design-system/Chart';
// 학년 → 계열 → 진로 흐름 (명 단위)
const careerNodes = [
{ id: '고1', label: '고1' },
{ id: '고2', label: '고2' },
{ id: '문과', label: '문과' },
{ id: '이과', label: '이과' },
{ id: '인문대', label: '인문대' },
{ id: '공대', label: '공대' },
{ id: '의대', label: '의대' },
];
const careerLinks = [
{ source: '고1', target: '문과', value: 80 },
{ source: '고1', target: '이과', value: 120 },
{ source: '고2', target: '문과', value: 60 },
{ source: '고2', target: '이과', value: 90 },
{ source: '문과', target: '인문대', value: 140 },
{ source: '이과', target: '공대', value: 150 },
{ source: '이과', target: '의대', value: 60 },
];
const SankeyChartWithLegendExample = () => <SankeyChart nodes={careerNodes} links={careerLinks} showLabels={false} showLegend />;
export default SankeyChartWithLegendExample;
노드 두께·간격 커스텀
import { SankeyChart } from '@mildang/design-system/Chart';
// 학년 → 계열 → 진로 흐름 (명 단위)
const careerNodes = [
{ id: '고1', label: '고1' },
{ id: '고2', label: '고2' },
{ id: '문과', label: '문과' },
{ id: '이과', label: '이과' },
{ id: '인문대', label: '인문대' },
{ id: '공대', label: '공대' },
{ id: '의대', label: '의대' },
];
const careerLinks = [
{ source: '고1', target: '문과', value: 80 },
{ source: '고1', target: '이과', value: 120 },
{ source: '고2', target: '문과', value: 60 },
{ source: '고2', target: '이과', value: 90 },
{ source: '문과', target: '인문대', value: 140 },
{ source: '이과', target: '공대', value: 150 },
{ source: '이과', target: '의대', value: 60 },
];
const SankeyChartCustomNodeStyleExample = () => (
<SankeyChart nodes={careerNodes} links={careerLinks} nodeWidth={28} nodePadding={24} linkOpacity={0.5} />
);
export default SankeyChartCustomNodeStyleExample;
커스텀 색상 (순환)
import { SankeyChart } from '@mildang/design-system/Chart';
import { token } from '@mildang/styled-system/tokens';
// 학년 → 계열 → 진로 흐름 (명 단위)
const careerNodes = [
{ id: '고1', label: '고1' },
{ id: '고2', label: '고2' },
{ id: '문과', label: '문과' },
{ id: '이과', label: '이과' },
{ id: '인문대', label: '인문대' },
{ id: '공대', label: '공대' },
{ id: '의대', label: '의대' },
];
const careerLinks = [
{ source: '고1', target: '문과', value: 80 },
{ source: '고1', target: '이과', value: 120 },
{ source: '고2', target: '문과', value: 60 },
{ source: '고2', target: '이과', value: 90 },
{ source: '문과', target: '인문대', value: 140 },
{ source: '이과', target: '공대', value: 150 },
{ source: '이과', target: '의대', value: 60 },
];
const SankeyChartCustomColorsExample = () => (
<SankeyChart
nodes={careerNodes}
links={careerLinks}
colors={[
token('colors.mildangPT.light.400'),
token('colors.blue.light.400'),
token('colors.green.light.400'),
]}
/>
);
export default SankeyChartCustomColorsExample;
링크 1개
import { SankeyChart } from '@mildang/design-system/Chart';
const SankeyChartSingleLinkExample = () => (
<SankeyChart
nodes={[
{ id: 'enroll', label: '수강 신청' },
{ id: 'complete', label: '완강' },
]}
links={[{ source: 'enroll', target: 'complete', value: 42 }]}
showTooltip
/>
);
export default SankeyChartSingleLinkExample;
빈 데이터
import { SankeyChart } from '@mildang/design-system/Chart';
const SankeyChartEmptyExample = () => <SankeyChart nodes={[]} links={[]} />;
export default SankeyChartEmptyExample;
잘못된 링크 무시 (미등록 노드·자기 참조)
import { SankeyChart } from '@mildang/design-system/Chart';
// 학년 → 계열 → 진로 흐름 (명 단위)
const careerNodes = [
{ id: '고1', label: '고1' },
{ id: '고2', label: '고2' },
{ id: '문과', label: '문과' },
{ id: '이과', label: '이과' },
{ id: '인문대', label: '인문대' },
{ id: '공대', label: '공대' },
{ id: '의대', label: '의대' },
];
const careerLinks = [
{ source: '고1', target: '문과', value: 80 },
{ source: '고1', target: '이과', value: 120 },
{ source: '고2', target: '문과', value: 60 },
{ source: '고2', target: '이과', value: 90 },
{ source: '문과', target: '인문대', value: 140 },
{ source: '이과', target: '공대', value: 150 },
{ source: '이과', target: '의대', value: 60 },
];
const SankeyChartInvalidLinksIgnoredExample = () => (
<SankeyChart
nodes={careerNodes}
links={[
...careerLinks,
{ source: '고1', target: '고1', value: 50 },
{ source: '없는노드', target: '이과', value: 30 },
]}
/>
);
export default SankeyChartInvalidLinksIgnoredExample;
반응형 (너비 자동 조정)
import { token } from '@mildang/styled-system/tokens';
import { SankeyChart } from '@mildang/design-system/Chart';
// 학년 → 계열 → 진로 흐름 (명 단위)
const careerNodes = [
{ id: '고1', label: '고1' },
{ id: '고2', label: '고2' },
{ id: '문과', label: '문과' },
{ id: '이과', label: '이과' },
{ id: '인문대', label: '인문대' },
{ id: '공대', label: '공대' },
{ id: '의대', label: '의대' },
];
const careerLinks = [
{ source: '고1', target: '문과', value: 80 },
{ source: '고1', target: '이과', value: 120 },
{ source: '고2', target: '문과', value: 60 },
{ source: '고2', target: '이과', value: 90 },
{ source: '문과', target: '인문대', value: 140 },
{ source: '이과', target: '공대', value: 150 },
{ source: '이과', target: '의대', value: 60 },
];
const SankeyChartResponsiveExample = () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: 32, width: '100%' }}>
{([320, 520, 720] as const).map((w) => (
<div key={w} style={{ width: w }}>
<div style={{ marginBottom: 4, fontSize: 11, color: token('colors.neutral.text.lowest') }}>{w}px</div>
<div style={{ width: w, height: 260 }}>
<SankeyChart nodes={careerNodes} links={careerLinks} />
</div>
</div>
))}
</div>
);
export default SankeyChartResponsiveExample;