konobangu/apps/storybook/stories/chart.stories.tsx

272 lines
6.5 KiB
TypeScript

import type { Meta, StoryObj } from '@storybook/react';
import { useMemo } from 'react';
import {
Area,
AreaChart,
Bar,
BarChart,
CartesianGrid,
Label,
Line,
LineChart,
Pie,
PieChart,
XAxis,
} from 'recharts';
import {
type ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from '@konobangu/design-system/components/ui/chart';
const multiSeriesData = [
{ month: 'January', desktop: 186, mobile: 80 },
{ month: 'February', desktop: 305, mobile: 200 },
{ month: 'March', desktop: 237, mobile: 120 },
{ month: 'April', desktop: 73, mobile: 190 },
{ month: 'May', desktop: 209, mobile: 130 },
{ month: 'June', desktop: 214, mobile: 140 },
];
const multiSeriesConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
},
} satisfies ChartConfig;
const singleSeriesData = [
{ browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
{ browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
{ browser: 'other', visitors: 190, fill: 'var(--color-other)' },
];
const singleSeriesConfig = {
visitors: {
label: 'Visitors',
},
chrome: {
label: 'Chrome',
color: 'hsl(var(--chart-1))',
},
safari: {
label: 'Safari',
color: 'hsl(var(--chart-2))',
},
other: {
label: 'Other',
color: 'hsl(var(--chart-5))',
},
} satisfies ChartConfig;
/**
* Beautiful charts. Built using Recharts. Copy and paste into your apps.
*/
const meta = {
title: 'ui/Chart',
component: ChartContainer,
tags: ['autodocs'],
argTypes: {},
args: {
children: <div />,
},
} satisfies Meta<typeof ChartContainer>;
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Combine multiple Area components to create a stacked area chart.
*/
export const StackedAreaChart: Story = {
args: {
config: multiSeriesConfig,
},
render: (args) => (
<ChartContainer {...args}>
<AreaChart
accessibilityLayer
data={multiSeriesData}
margin={{
left: 12,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="dot" />}
/>
<Area
dataKey="mobile"
type="natural"
fill="var(--color-mobile)"
fillOpacity={0.4}
stroke="var(--color-mobile)"
stackId="a"
/>
<Area
dataKey="desktop"
type="natural"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
stackId="a"
/>
</AreaChart>
</ChartContainer>
),
};
/**
* Combine multiple Bar components to create a stacked bar chart.
*/
export const StackedBarChart: Story = {
args: {
config: multiSeriesConfig,
},
render: (args) => (
<ChartContainer {...args}>
<BarChart accessibilityLayer data={multiSeriesData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="dashed" />}
/>
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
),
};
/**
* Combine multiple Line components to create a single line chart.
*/
export const MultiLineChart: Story = {
args: {
config: multiSeriesConfig,
},
render: (args) => (
<ChartContainer {...args}>
<LineChart
accessibilityLayer
data={multiSeriesData}
margin={{
left: 12,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel />}
/>
<Line
dataKey="desktop"
type="natural"
stroke="var(--color-desktop)"
strokeWidth={2}
dot={false}
/>
<Line
dataKey="mobile"
type="natural"
stroke="var(--color-mobile)"
strokeWidth={2}
dot={false}
/>
</LineChart>
</ChartContainer>
),
};
/**
* Combine Pie and Label components to create a doughnut chart.
*/
export const DoughnutChart: Story = {
args: {
config: singleSeriesConfig,
},
render: (args) => {
const totalVisitors = useMemo(() => {
return singleSeriesData.reduce((acc, curr) => acc + curr.visitors, 0);
}, []);
return (
<ChartContainer {...args}>
<PieChart>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel />}
/>
<Pie
data={singleSeriesData}
dataKey="visitors"
nameKey="browser"
innerRadius={48}
strokeWidth={5}
>
<Label
content={({ viewBox }) => {
if (viewBox && 'cx' in viewBox && 'cy' in viewBox) {
return (
<text
x={viewBox.cx}
y={viewBox.cy}
textAnchor="middle"
dominantBaseline="middle"
>
<tspan
x={viewBox.cx}
y={viewBox.cy}
className="fill-foreground font-bold text-3xl"
>
{totalVisitors.toLocaleString()}
</tspan>
<tspan
x={viewBox.cx}
y={(viewBox.cy || 0) + 24}
className="fill-muted-foreground"
>
Visitors
</tspan>
</text>
);
}
}}
/>
</Pie>
</PieChart>
</ChartContainer>
);
},
};