Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 114 additions & 1 deletion src/components/area-chart/area-chart.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Label from '../label';
import Button from '../button';
import Badge from '../badge';
import Container from '../container';
import { ArrowUpRight, ArrowUp } from 'lucide-react';
import { ArrowUpRight, ArrowUp, AlertCircle } from 'lucide-react';

const areaChartData = [
{ month: 'January', sales: 186, expenses: 80 },
Expand All @@ -15,7 +15,21 @@ const areaChartData = [
{ month: 'June', sales: 214, expenses: 140 },
];

// Data with large values to demonstrate Y-axis formatting
const largeValuesData = [
{ month: 'January', pageviews: 1200, sessions: 800 },
{ month: 'February', pageviews: 2800, sessions: 1500 },
{ month: 'March', pageviews: 5500, sessions: 2900 },
{ month: 'April', pageviews: 8200, sessions: 4100 },
{ month: 'May', pageviews: 14000, sessions: 6200 },
{ month: 'June', pageviews: 18500, sessions: 8800 },
];

// Empty data for demonstrating custom no data component
const emptyData: { month: string; sales: number; expenses: number }[] = [];

const dataKeys = [ 'sales', 'expenses' ];
const largeDataKeys = [ 'pageviews', 'sessions' ];

const chartDataIteractive = [
{ date: '2024-04-01', desktop: 222, mobile: 150 },
Expand Down Expand Up @@ -121,6 +135,29 @@ const colors = [
// Custom tick formatter function for months
const monthFormatter = ( value: string ) => value.slice( 0, 3 );

// Custom Y-axis formatter function to display values in K/M format
const yAxisFormatter = ( value: number ) => {
if ( value >= 1000000 ) {
return `${ ( value / 1000000 ).toFixed( 1 ) }M`;
}
if ( value >= 1000 ) {
return `${ ( value / 1000 ).toFixed( 1 ) }K`;
}
return value.toString();
};

// Custom No Data Component
const CustomNoDataComponent = () => (
<div className="flex flex-col items-center justify-center p-6 rounded-lg bg-gray-50 text-gray-600">
<AlertCircle className="mb-3 text-amber-500" size={ 50 } />
<div className="text-base font-medium">No data found</div>
<p className="text-sm text-center text-gray-500 mt-1 max-w-xs">
There is no data available for this chart at the moment. Try
adjusting your filters or check back later.
</p>
</div>
);

const monthFormatterInteractive = ( value: string ) => {
const date = new Date( value );
return date.toLocaleDateString( 'en-US', {
Expand Down Expand Up @@ -187,7 +224,83 @@ export const AreaChartInteractive: Story = {
},
};

export const AreaChartWithFormattedYAxis: Story = {
args: {
chartWidth: 600,
chartHeight: 300,
data: largeValuesData,
dataKeys: largeDataKeys,
colors: [
{ stroke: '#3b82f6', fill: '#BFDBFE' },
{ stroke: '#f97316', fill: '#FFEDD5' },
],
variant: 'solid',
showXAxis: true,
xAxisDataKey: 'month',
showYAxis: true,
tickFormatter: monthFormatter,
yAxisTickFormatter: yAxisFormatter,
showLegend: true,
areaChartWrapperProps: {
margin: {
left: 35,
right: 14,
top: 6,
bottom: 6,
},
},
},
};

export const AreaChartGradientWithFormattedYAxis: Story = {
args: {
chartWidth: 600,
chartHeight: 300,
data: largeValuesData,
dataKeys: largeDataKeys,
colors: [
{ stroke: '#3b82f6', fill: '#BFDBFE' },
{ stroke: '#f97316', fill: '#FFEDD5' },
],
variant: 'gradient',
showXAxis: true,
xAxisDataKey: 'month',
showYAxis: true,
tickFormatter: monthFormatter,
yAxisTickFormatter: yAxisFormatter,
showLegend: true,
areaChartWrapperProps: {
margin: {
left: 35,
right: 14,
top: 6,
bottom: 6,
},
},
},
};

export const AreaChartWithCustomNoDataComponent: Story = {
args: {
chartWidth: 600,
chartHeight: 300,
data: emptyData,
dataKeys,
colors,
variant: 'solid',
showXAxis: true,
xAxisDataKey: 'month',
showYAxis: true,
noDataComponent: <CustomNoDataComponent />,
},
};

AreaChartInteractive.storyName = 'Area Chart Gradient with Legend';
AreaChartWithFormattedYAxis.storyName = 'Area Chart with Formatted Y-Axis';
AreaChartGradientWithFormattedYAxis.storyName =
'Area Chart Gradient with Formatted Y-Axis';
AreaChartWithCustomNoDataComponent.storyName =
'Area Chart with Custom No Data Component';

type Story1 = StoryFn<typeof AreaChart>;

Expand Down
50 changes: 36 additions & 14 deletions src/components/area-chart/area-chart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect, useState, type ReactNode } from 'react';
import {
AreaChart as AreaChartWrapper,
Area,
Expand All @@ -14,6 +14,13 @@ import ChartTooltipContent from './chart-tooltip-content';
import Label from '../label';
import type { CategoricalChartProps } from 'recharts/types/chart/generateCategoricalChart';

// Default color constants
const DEFAULT_FONT_COLOR = '#6B7280';
const DEFAULT_AREA_COLORS = [
{ stroke: '#2563EB', fill: '#BFDBFE' },
{ stroke: '#38BDF8', fill: '#BAE6FD' },
];

interface DataItem {
[key: string]: number | string; // Adjust based on your data structure
}
Expand Down Expand Up @@ -56,9 +63,18 @@ interface AreaChartProps {
/** Whether to display the `<CartesianGrid />`, adding horizontal and vertical grid lines. */
showCartesianGrid?: boolean;

/** A function used to format the ticks on the axes, e.g., for formatting dates or numbers. */
/** A function used to format the ticks on the x-axis, e.g., for formatting dates or numbers. */
xAxisTickFormatter?: ( value: string ) => string;

/**
* A function used to format the ticks on the x-axis, e.g., for formatting dates or numbers.
* @deprecated Use `xAxisTickFormatter` instead.
*/
tickFormatter?: ( value: string ) => string;

/** A function used to format the ticks on the y-axis, e.g., for converting 1000 to 1K. */
yAxisTickFormatter?: ( value: number ) => string;

/** The key in the data objects representing values for the x-axis. This is used to access the x-axis values from each data entry. */
xAxisDataKey?: string;

Expand All @@ -85,6 +101,12 @@ interface AreaChartProps {
CategoricalChartProps,
'width' | 'height' | 'data'
>;

/**
* Custom component to display when no data is available.
* If not provided, a default "No data available" message will be displayed.
*/
noDataComponent?: ReactNode;
}

const AreaChart = ( {
Expand All @@ -99,11 +121,13 @@ const AreaChart = ( {
tooltipLabelKey,
showLegend = true,
showCartesianGrid = true,
xAxisTickFormatter,
tickFormatter,
yAxisTickFormatter,
xAxisDataKey,
yAxisDataKey,
xAxisFontSize = 'sm', // sm, md, lg
xAxisFontColor = '#6B7280',
xAxisFontColor = DEFAULT_FONT_COLOR,
chartWidth = 350,
chartHeight = 200,
areaChartWrapperProps = {
Expand All @@ -114,17 +138,12 @@ const AreaChart = ( {
bottom: 6,
},
},
noDataComponent,
}: AreaChartProps ) => {
const [ width, setWidth ] = useState( chartWidth );
const [ height, setHeight ] = useState( chartHeight );

// Default colors
const defaultColors: Color[] = [
{ stroke: '#2563EB', fill: '#BFDBFE' },
{ stroke: '#38BDF8', fill: '#BAE6FD' },
];

const appliedColors = colors.length > 0 ? colors : defaultColors;
const appliedColors = colors.length > 0 ? colors : DEFAULT_AREA_COLORS;

useEffect( () => {
setWidth( chartWidth );
Expand Down Expand Up @@ -167,9 +186,11 @@ const AreaChart = ( {

if ( ! data || data.length === 0 ) {
return (
<Label size="sm" variant="help">
No data available
</Label>
noDataComponent || (
<Label size="sm" variant="help">
No data available
</Label>
)
);
}

Expand All @@ -182,7 +203,7 @@ const AreaChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
tickFormatter={ tickFormatter }
tickFormatter={ xAxisTickFormatter || tickFormatter }
tick={ {
fontSize: fontSizeVariant,
fill: xAxisFontColor,
Expand All @@ -195,6 +216,7 @@ const AreaChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
tickFormatter={ yAxisTickFormatter }
tick={ {
fontSize: fontSizeVariant,
fill: xAxisFontColor,
Expand Down
Loading
Loading