+
),
],
-} satisfies Meta< typeof LineChart >;
+};
+
+export default meta;
-const Template = args =>
;
+const Template: StoryFn< typeof LineChart > = args =>
;
// Default story with multiple series
-export const Default = Template.bind( {} );
+export const Default: StoryObj< typeof LineChart > = Template.bind( {} );
Default.args = {
- width: 500,
- height: 300,
data: sampleData,
showLegend: false,
legendOrientation: 'horizontal',
+ withGradientFill: false,
+ options: {
+ axis: {
+ x: {
+ orientation: 'bottom',
+ },
+ y: {
+ orientation: 'left',
+ },
+ },
+ },
};
// Story with single data series
-export const SingleSeries = Template.bind( {} );
+export const SingleSeries: StoryObj< typeof LineChart > = Template.bind( {} );
SingleSeries.args = {
- width: 500,
- height: 300,
data: [ sampleData[ 0 ] ], // Only London temperature data
};
// Story without tooltip
-export const WithoutTooltip = Template.bind( {} );
+export const WithoutTooltip: StoryObj< typeof LineChart > = Template.bind( {} );
WithoutTooltip.args = {
...Default.args,
withTooltips: false,
};
// Story with custom dimensions
-export const CustomDimensions = Template.bind( {} );
+export const CustomDimensions: StoryObj< typeof LineChart > = Template.bind( {} );
CustomDimensions.args = {
width: 800,
height: 400,
@@ -53,16 +73,44 @@ CustomDimensions.args = {
};
// Story with horizontal legend
-export const WithLegend = Template.bind( {} );
+export const WithLegend: StoryObj< typeof LineChart > = Template.bind( {} );
WithLegend.args = {
...Default.args,
showLegend: true,
};
// Story with vertical legend
-export const WithVerticalLegend = Template.bind( {} );
+export const WithVerticalLegend: StoryObj< typeof LineChart > = Template.bind( {} );
WithVerticalLegend.args = {
...Default.args,
showLegend: true,
legendOrientation: 'vertical',
};
+
+// Add after existing stories
+export const FixedDimensions: StoryObj< typeof LineChart > = Template.bind( {} );
+FixedDimensions.args = {
+ width: 800,
+ height: 400,
+ data: sampleData,
+ withTooltips: true,
+};
+
+FixedDimensions.parameters = {
+ docs: {
+ description: {
+ story: 'Line chart with fixed dimensions that override the responsive behavior.',
+ },
+ },
+};
+
+// Story with gradient filled line chart
+export const GridientFilled: StoryObj< typeof LineChart > = Template.bind( {} );
+GridientFilled.args = {
+ ...Default.args,
+ data: webTrafficData,
+ withGradientFill: true,
+ options: {
+ axis: { x: { numTicks: 10 }, y: { orientation: 'right' } },
+ },
+};
diff --git a/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts b/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts
index 1231466c476d4..2486715b1789f 100644
--- a/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts
+++ b/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts
@@ -1,4 +1,4 @@
-import type { SeriesData } from '../../shared/types';
+import type { SeriesData } from '../../../types';
// Sample data
const temperatureData: SeriesData[] = [
diff --git a/projects/js-packages/charts/src/components/line-chart/stories/site-traffic-sample.ts b/projects/js-packages/charts/src/components/line-chart/stories/site-traffic-sample.ts
new file mode 100644
index 0000000000000..fd95c704c3f84
--- /dev/null
+++ b/projects/js-packages/charts/src/components/line-chart/stories/site-traffic-sample.ts
@@ -0,0 +1,258 @@
+export default [
+ {
+ label: 'Views',
+ options: {
+ stroke: '#069e08',
+ },
+ data: [
+ {
+ date: new Date( '2024-01-01' ),
+ value: 2558,
+ },
+ {
+ date: new Date( '2024-01-02' ),
+ value: 3399,
+ },
+ {
+ date: new Date( '2024-01-03' ),
+ value: 2260,
+ },
+ {
+ date: new Date( '2024-01-04' ),
+ value: 2331,
+ },
+ {
+ date: new Date( '2024-01-05' ),
+ value: 3302,
+ },
+ {
+ date: new Date( '2024-01-06' ),
+ value: 1852,
+ },
+ {
+ date: new Date( '2024-01-07' ),
+ value: 2607,
+ },
+ {
+ date: new Date( '2024-01-08' ),
+ value: 2804,
+ },
+ {
+ date: new Date( '2024-01-09' ),
+ value: 3260,
+ },
+ {
+ date: new Date( '2024-01-10' ),
+ value: 2941,
+ },
+ {
+ date: new Date( '2024-01-11' ),
+ value: 2857,
+ },
+ {
+ date: new Date( '2024-01-12' ),
+ value: 3461,
+ },
+ {
+ date: new Date( '2024-01-13' ),
+ value: 1548,
+ },
+ {
+ date: new Date( '2024-01-14' ),
+ value: 2739,
+ },
+ {
+ date: new Date( '2024-01-15' ),
+ value: 3288,
+ },
+ {
+ date: new Date( '2024-01-16' ),
+ value: 2869,
+ },
+ {
+ date: new Date( '2024-01-17' ),
+ value: 2590,
+ },
+ {
+ date: new Date( '2024-01-18' ),
+ value: 2609,
+ },
+ {
+ date: new Date( '2024-01-19' ),
+ value: 2648,
+ },
+ {
+ date: new Date( '2024-01-20' ),
+ value: 1805,
+ },
+ {
+ date: new Date( '2024-01-21' ),
+ value: 2531,
+ },
+ {
+ date: new Date( '2024-01-22' ),
+ value: 3605,
+ },
+ {
+ date: new Date( '2024-01-23' ),
+ value: 2366,
+ },
+ {
+ date: new Date( '2024-01-24' ),
+ value: 2782,
+ },
+ {
+ date: new Date( '2024-01-25' ),
+ value: 2885,
+ },
+ {
+ date: new Date( '2024-01-26' ),
+ value: 2918,
+ },
+ {
+ date: new Date( '2024-01-27' ),
+ value: 2518,
+ },
+ {
+ date: new Date( '2024-01-28' ),
+ value: 2378,
+ },
+ {
+ date: new Date( '2024-01-29' ),
+ value: 2714,
+ },
+ {
+ date: new Date( '2024-01-30' ),
+ value: 3279,
+ },
+ ],
+ },
+ {
+ label: 'Visitors',
+ options: {
+ stroke: 'rgb(230, 139, 40)',
+ },
+ data: [
+ {
+ date: new Date( '2024-01-01' ),
+ value: 2412,
+ },
+ {
+ date: new Date( '2024-01-02' ),
+ value: 1899,
+ },
+ {
+ date: new Date( '2024-01-03' ),
+ value: 2061,
+ },
+ {
+ date: new Date( '2024-01-04' ),
+ value: 1939,
+ },
+ {
+ date: new Date( '2024-01-05' ),
+ value: 1986,
+ },
+ {
+ date: new Date( '2024-01-06' ),
+ value: 1560,
+ },
+ {
+ date: new Date( '2024-01-07' ),
+ value: 1741,
+ },
+ {
+ date: new Date( '2024-01-08' ),
+ value: 2120,
+ },
+ {
+ date: new Date( '2024-01-09' ),
+ value: 1889,
+ },
+ {
+ date: new Date( '2024-01-10' ),
+ value: 1666,
+ },
+ {
+ date: new Date( '2024-01-11' ),
+ value: 2396,
+ },
+ {
+ date: new Date( '2024-01-12' ),
+ value: 2276,
+ },
+ {
+ date: new Date( '2024-01-13' ),
+ value: 1218,
+ },
+ {
+ date: new Date( '2024-01-14' ),
+ value: 1228,
+ },
+ {
+ date: new Date( '2024-01-15' ),
+ value: 1600,
+ },
+ {
+ date: new Date( '2024-01-16' ),
+ value: 1814,
+ },
+ {
+ date: new Date( '2024-01-17' ),
+ value: 1701,
+ },
+ {
+ date: new Date( '2024-01-18' ),
+ value: 1507,
+ },
+ {
+ date: new Date( '2024-01-19' ),
+ value: 1833,
+ },
+ {
+ date: new Date( '2024-01-20' ),
+ value: 1407,
+ },
+ {
+ date: new Date( '2024-01-21' ),
+ value: 965,
+ },
+ {
+ date: new Date( '2024-01-22' ),
+ value: 2288,
+ },
+ {
+ date: new Date( '2024-01-23' ),
+ value: 2135,
+ },
+ {
+ date: new Date( '2024-01-24' ),
+ value: 1824,
+ },
+ {
+ date: new Date( '2024-01-25' ),
+ value: 2219,
+ },
+ {
+ date: new Date( '2024-01-26' ),
+ value: 1918,
+ },
+ {
+ date: new Date( '2024-01-27' ),
+ value: 1101,
+ },
+ {
+ date: new Date( '2024-01-28' ),
+ value: 1695,
+ },
+ {
+ date: new Date( '2024-01-29' ),
+ value: 1615,
+ },
+ {
+ date: new Date( '2024-01-30' ),
+ value: 2056,
+ },
+ ],
+ },
+];
diff --git a/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx b/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx
index f925ea7faa4c0..0fff77fc76494 100644
--- a/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx
+++ b/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx
@@ -5,18 +5,49 @@ import { SVGProps, type MouseEvent } from 'react';
import useChartMouseHandler from '../../hooks/use-chart-mouse-handler';
import { useChartTheme, defaultTheme } from '../../providers/theme';
import { Legend } from '../legend';
+import { withResponsive } from '../shared/with-responsive';
import { BaseTooltip } from '../tooltip';
import styles from './pie-chart.module.scss';
-import type { BaseChartProps, DataPointPercentage } from '../shared/types';
-import type { PieArcDatum } from '@visx/shape/lib/shapes/Pie';
+import type { BaseChartProps, DataPointPercentage } from '../../types';
// TODO: add animation
-interface PieChartProps extends BaseChartProps< DataPointPercentage[] > {
+type OmitBaseChartProps = Omit< BaseChartProps< DataPointPercentage[] >, 'width' | 'height' >;
+
+interface PieChartProps extends OmitBaseChartProps {
/**
* Inner radius in pixels. If > 0, creates a donut chart. Defaults to 0.
*/
innerRadius?: number;
+
+ /**
+ * Size of the chart in pixels
+ */
+ size?: number;
+
+ /**
+ * Add padding to the chart
+ */
+ padding?: number;
+
+ /**
+ * Thickness of the pie chart.
+ * A value between 0 and 1, where 0 means no thickness
+ * and 1 means the maximum thickness.
+ */
+ thickness?: number;
+
+ /**
+ * Scale of the gap between groups in the pie chart
+ * A value between 0 and 1, where 0 means no gap.
+ */
+ gapScale?: number;
+
+ /**
+ * Scale of the corner radius for the pie chart segments.
+ * A value between 0 and 1, where 0 means no corner radius.
+ */
+ cornerScale?: number;
}
/**
@@ -27,13 +58,15 @@ interface PieChartProps extends BaseChartProps< DataPointPercentage[] > {
*/
const PieChart = ( {
data,
- width = 500, //TODO: replace when making the components responsive
- height = 500, //TODO: replace when making the components responsive
withTooltips = false,
- innerRadius = 0,
className,
showLegend,
legendOrientation,
+ size,
+ thickness = 1,
+ padding = 20,
+ gapScale = 0,
+ cornerScale = 0,
}: PieChartProps ) => {
const providerTheme = useChartTheme();
const { onMouseMove, onMouseLeave, tooltipOpen, tooltipData, tooltipLeft, tooltipTop } =
@@ -41,15 +74,36 @@ const PieChart = ( {
withTooltips,
} );
+ const width = size;
+ const height = size;
+
// Calculate radius based on width/height
const radius = Math.min( width, height ) / 2;
+
+ // Center the chart in the available space
const centerX = width / 2;
const centerY = height / 2;
+ // Calculate the angle between each
+ const padAngle = gapScale * ( ( 2 * Math.PI ) / data.length );
+
+ const outerRadius = radius - padding;
+ const innerRadius = outerRadius * ( 1 - thickness );
+
+ const maxCornerRadius = ( outerRadius - innerRadius ) / 2;
+ const cornerRadius = cornerScale ? Math.min( cornerScale * outerRadius, maxCornerRadius ) : 0;
+
+ // Map the data to include index for color assignment
+ const dataWithIndex = data.map( ( d, index ) => ( {
+ ...d,
+ index,
+ } ) );
+
const accessors = {
- value: ( d: PieArcDatum< DataPointPercentage > ) => d.value,
+ value: ( d: DataPointPercentage ) => d.value,
// Use the color property from the data object as a last resort. The theme provides colours by default.
- fill: ( d: PieArcDatum< DataPointPercentage > ) => d?.color || providerTheme.colors[ d.index ],
+ fill: ( d: DataPointPercentage & { index: number } ) =>
+ d?.color || providerTheme.colors[ d.index ],
};
// Create legend items from data
@@ -61,13 +115,15 @@ const PieChart = ( {
return (
-