Files
HMDesign/packages/chart/src/examples/sample-data.ts
T
shkim4 dc9258599c feat(chart): add @hm-design/chart package with Bar, Line, Donut, Pie, Radar, Area and Radial charts
- new workspace package packages/chart (shadcn/ui Chart + Recharts, HM Theme tokens), examples entry with sample data
- Storybook Chart group (src/chart), consumer example (examples/chart), build:chart / build:chart-example scripts
- README rewritten as the AI usage guide (install, CSS wiring, chart selection, data rules, verification)
- docs: package count/list, Submodule guide (chart workspace, React dedupe), shared AI_GUIDE row, MAINTAINING, story inventory
2026-11-06 15:52:47 +09:00

190 lines
7.9 KiB
TypeScript

import { chartColors, type ChartSeries, type HMDonutDatum, type HMPieRing } from "../index"
// SAMPLE DATA ONLY. These values are invented to show the charts; they are not business data and must not be reported as such.
// Real data belongs to the consuming app and is passed to HMBarChart / HMLineChart / HMDonutChart as props.
export const sampleDataNotice = "예시 데이터 · 실제 업무 데이터가 아닙니다"
export const sampleBar = {
categoryKey: "month",
series: [
{ key: "received", label: "접수" },
{ key: "completed", label: "완료" },
] satisfies ChartSeries[],
data: [
{ month: "1월", received: 186, completed: 142 },
{ month: "2월", received: 305, completed: 238 },
{ month: "3월", received: 237, completed: 221 },
{ month: "4월", received: 173, completed: 190 },
{ month: "5월", received: 209, completed: 196 },
{ month: "6월", received: 264, completed: 231 },
],
}
export const sampleLine = {
categoryKey: "month",
series: [
{ key: "average", label: "평균 처리 시간" },
{ key: "target", label: "목표" },
] satisfies ChartSeries[],
data: [
{ month: "1월", average: 4.8, target: 4 },
{ month: "2월", average: 4.4, target: 4 },
{ month: "3월", average: 4.1, target: 4 },
{ month: "4월", average: 3.7, target: 4 },
{ month: "5월", average: 3.9, target: 4 },
{ month: "6월", average: 3.4, target: 4 },
],
}
export const sampleDonut = {
totalLabel: "전체(건)",
data: [
{ id: "done", label: "완료", value: 118 },
{ id: "inProgress", label: "진행 중", value: 42 },
{ id: "delayed", label: "지연", value: 12 },
{ id: "onHold", label: "보류", value: 8 },
] satisfies HMDonutDatum[],
}
// Item names are deliberately uneven: one very long name, short bars and a zero value exercise the label rules.
export const sampleHorizontalBar = {
categoryKey: "item",
valueKey: "count",
valueLabel: "처리 건수",
data: [
{ item: "종합 민원 접수 및 처리 현황 보고서 작성", count: 186 },
{ item: "시설 점검", count: 142 },
{ item: "예산 집행 검토", count: 96 },
{ item: "계약 변경 승인 요청 건", count: 38 },
{ item: "보류 항목", count: 3 },
{ item: "반려", count: 0 },
],
}
// Mixed signs with a zero value. A positive-only or negative-only list works the same way.
export const sampleSignedBar = {
categoryKey: "month",
valueKey: "change",
valueLabel: "순증감",
data: [
{ month: "1월", change: 120 },
{ month: "2월", change: -80 },
{ month: "3월", change: 45 },
{ month: "4월", change: -150 },
{ month: "5월", change: 0 },
{ month: "6월", change: 95 },
],
}
// One data set for all line examples (curve, straight, dots, per-point colors, step), so the connection styles compare directly on the same axis range.
// It is built to exercise the label rules: 3월 is a tie (40 = 40), 2월 and 4월 are close, the lines cross between 5월 and 6월, and 완료 drops to 0 in 5월.
const lineCompareRows = [
{ month: "1월", received: 48, completed: 30 },
{ month: "2월", received: 72, completed: 60 },
{ month: "3월", received: 40, completed: 40 },
{ month: "4월", received: 85, completed: 70 },
{ month: "5월", received: 20, completed: 0 },
{ month: "6월", received: 56, completed: 62 },
]
export const sampleLineCompare = {
categoryKey: "month",
series: [
{ key: "received", label: "접수" },
{ key: "completed", label: "완료" },
] satisfies ChartSeries[],
data: lineCompareRows,
}
// Per-point colors are HM palette tokens by value, one family per series: 접수 in greens, 완료 in browns, and the orange token below 30
// (all dark enough for the value label to read on the card).
const receivedColor = (value: number) =>
value >= 60 ? "var(--hm-sem-palette-green-light-1)"
: value >= 30 ? "var(--hm-sem-palette-green-tone-1)"
: "var(--hm-sem-palette-orange-default)"
const completedColor = (value: number) =>
value >= 60 ? "var(--hm-sem-palette-brown-light-1)"
: value >= 30 ? "var(--hm-sem-palette-brown-light-2)"
: "var(--hm-sem-palette-orange-default)"
export const sampleLinePointColors = {
...sampleLineCompare,
pointColorKey: { received: "receivedColor", completed: "completedColor" },
data: lineCompareRows.map(row => ({
...row,
receivedColor: receivedColor(row.received),
completedColor: completedColor(row.completed),
})),
}
// One data set for the four donut states (plain, center total, active, interactive), so they compare directly.
// It includes a long name (shortened in the center, complete in the legend and tooltip) and a zero item.
export const sampleDonutStates = {
totalLabel: "전체(건)",
/** The selected slice of the active and interactive examples. */
activeId: "inProgress",
data: [
{ id: "done", label: "완료", value: 118 },
{ id: "inProgress", label: "진행 중", value: 42 },
{ id: "review", label: "관계 기관 협의 및 보완 요청 대기", value: 24 },
{ id: "delayed", label: "지연", value: 12 },
{ id: "rejected", label: "반려", value: 0 },
] satisfies HMDonutDatum[],
}
// Pie examples. Items keep one color by id (the order of this list), in every pie and in both rings of the stacked pie.
// It includes a long name (omitted or shortened where it does not fit) and a very small slice.
const pieMaster = [
{ id: "done", label: "완료" },
{ id: "inProgress", label: "진행 중" },
{ id: "review", label: "관계 기관 협의 및 보완 요청 대기" },
{ id: "delayed", label: "지연" },
{ id: "onHold", label: "보류" },
]
const pieItem = (id: string, value: number): HMDonutDatum => {
const index = pieMaster.findIndex(item => item.id === id)
return { id, label: pieMaster[index].label, value, color: chartColors[index % chartColors.length] }
}
export const samplePie = {
data: [pieItem("done", 118), pieItem("inProgress", 42), pieItem("review", 24), pieItem("delayed", 12), pieItem("onHold", 3)],
}
export const sampleStackedPie = {
rings: [
{ id: "q1", label: "1분기", data: [pieItem("done", 80), pieItem("inProgress", 30), pieItem("delayed", 8)] },
{ id: "q2", label: "2분기", data: [pieItem("done", 118), pieItem("inProgress", 42), pieItem("review", 24), pieItem("delayed", 12)] },
] satisfies [HMPieRing, HMPieRing],
}
// Radar examples: six axes, two series on one 0-100 range. The first axis (top) has a long name to exercise the custom label.
export const sampleRadar = {
categoryKey: "area",
maxValue: 100,
series: [
{ key: "current", label: "이번 분기" },
{ key: "previous", label: "지난 분기" },
] satisfies ChartSeries[],
data: [
{ area: "관계 기관 협의 및 보완 요청", current: 62, previous: 48 },
{ area: "접수", current: 88, previous: 72 },
{ area: "검토", current: 70, previous: 82 },
{ area: "승인", current: 55, previous: 60 },
{ area: "배정", current: 92, previous: 65 },
{ area: "완료", current: 76, previous: 58 },
],
}
// Radial examples. Same items and color mapping as the pies (by id). Values are on the scale of the official examples so the arcs read
// the same way: five bars (simple, label, grid), one value (text: 200, shape: 1260) and one stacked row (570 + 1260).
const radialItem = (id: string, value: number) => pieItem(id, value)
export const sampleRadial = {
data: [radialItem("done", 275), radialItem("inProgress", 200), radialItem("review", 187), radialItem("delayed", 173), radialItem("onHold", 90)],
}
export const sampleRadialText = { item: radialItem("inProgress", 200), caption: "진행 중 건수" }
export const sampleRadialShape = { item: radialItem("inProgress", 1260), caption: "진행 중 건수" }
export const sampleRadialStacked = {
series: [
{ key: "inProgress", label: "진행 중", color: chartColors[1] },
{ key: "done", label: "완료", color: chartColors[0] },
] satisfies ChartSeries[],
row: { inProgress: 570, done: 1260 },
totalLabel: "전체(건)",
}