);
};
@@ -65,35 +70,38 @@ const formatDateTick = ( value: number ) => {
} );
};
-// TODO: add support for multiple data sets
-
const LineChart: FC< LineChartProps > = ( {
data,
width,
height,
margin = { top: 20, right: 20, bottom: 40, left: 40 },
+ className,
+ withTooltips = true,
} ) => {
const providerTheme = useChartTheme();
+
+ if ( ! data.length ) {
+ return (
+
Empty...
+ );
+ }
+
const accessors = {
xAccessor: ( d: DataPointDate ) => d.date,
yAccessor: ( d: DataPointDate ) => d.value,
};
- // Use theme to construct XYChart theme
- const chartTheme = {
+ const theme = buildChartTheme( {
backgroundColor: providerTheme.backgroundColor,
colors: providerTheme.colors,
gridStyles: providerTheme.gridStyles,
tickLength: providerTheme?.tickLength || 0,
gridColor: providerTheme?.gridColor || '',
gridColorDark: providerTheme?.gridColorDark || '',
- };
-
- const theme = buildChartTheme( chartTheme );
+ } );
- //
return (
-
+
= ( {
yScale={ { type: 'linear', nice: true } }
>
-
-
-
-
+ { data.map( ( seriesData, index ) => (
+
+ ) ) }
+
+ { withTooltips && (
+
+ ) }
);
diff --git a/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx
index 40a11b9c67364..b09bc9594c4fd 100644
--- a/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx
+++ b/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx
@@ -1,13 +1,7 @@
import { LineChart } from '../index';
+import sampleData from './sample-data';
import type { Meta } from '@storybook/react';
-const data = [
- { date: new Date( '2023-01-01' ), value: 10 },
- { date: new Date( '2023-02-01' ), value: 20 },
- { date: new Date( '2023-03-01' ), value: 15 },
- { date: new Date( '2023-04-01' ), value: 25 },
-];
-
export default {
title: 'JS Packages/Charts/Types/Line Chart',
component: LineChart,
@@ -25,10 +19,39 @@ export default {
const Template = args =>
;
+// Default story with multiple series
export const Default = Template.bind( {} );
Default.args = {
width: 500,
height: 300,
margin: { top: 20, right: 20, bottom: 30, left: 40 },
- data,
+ data: sampleData,
+};
+
+// Story with single data series
+export const SingleSeries = Template.bind( {} );
+SingleSeries.args = {
+ width: 500,
+ height: 300,
+ margin: { top: 20, right: 20, bottom: 30, left: 40 },
+ data: [ sampleData[ 0 ] ], // Only London temperature data
+};
+
+// Story without tooltip
+export const WithoutTooltip = Template.bind( {} );
+WithoutTooltip.args = {
+ width: 500,
+ height: 300,
+ margin: { top: 20, right: 20, bottom: 30, left: 40 },
+ data: sampleData,
+ withTooltips: false,
+};
+
+// Story with custom dimensions
+export const CustomDimensions = Template.bind( {} );
+CustomDimensions.args = {
+ width: 800,
+ height: 400,
+ margin: { top: 20, right: 20, bottom: 30, left: 40 },
+ data: sampleData,
};
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
new file mode 100644
index 0000000000000..1231466c476d4
--- /dev/null
+++ b/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts
@@ -0,0 +1,346 @@
+import type { SeriesData } from '../../shared/types';
+
+// Sample data
+const temperatureData: SeriesData[] = [
+ {
+ label: 'London',
+ data: [
+ // 2022 data
+ { date: new Date( '2022-01-01' ), value: 7.8 },
+ { date: new Date( '2022-01-08' ), value: 7.2 },
+ { date: new Date( '2022-01-15' ), value: 6.9 },
+ { date: new Date( '2022-01-22' ), value: 6.5 },
+ { date: new Date( '2022-01-29' ), value: 7.1 },
+ { date: new Date( '2022-02-05' ), value: 8.3 },
+ { date: new Date( '2022-02-12' ), value: 8.9 },
+ { date: new Date( '2022-02-19' ), value: 9.2 },
+ { date: new Date( '2022-02-26' ), value: 8.7 },
+ { date: new Date( '2022-03-05' ), value: 9.4 },
+ { date: new Date( '2022-03-12' ), value: 10.2 },
+ { date: new Date( '2022-03-19' ), value: 11.5 },
+ { date: new Date( '2022-03-26' ), value: 12.3 },
+ { date: new Date( '2022-04-02' ), value: 13.1 },
+ { date: new Date( '2022-04-09' ), value: 13.8 },
+ { date: new Date( '2022-04-16' ), value: 14.6 },
+ { date: new Date( '2022-04-23' ), value: 15.2 },
+ { date: new Date( '2022-04-30' ), value: 15.9 },
+ { date: new Date( '2022-05-07' ), value: 16.7 },
+ { date: new Date( '2022-05-14' ), value: 17.4 },
+ { date: new Date( '2022-05-21' ), value: 18.2 },
+ { date: new Date( '2022-05-28' ), value: 18.9 },
+ { date: new Date( '2022-06-04' ), value: 19.7 },
+ { date: new Date( '2022-06-11' ), value: 20.5 },
+ { date: new Date( '2022-06-18' ), value: 21.3 },
+ { date: new Date( '2022-06-25' ), value: 22.1 },
+ { date: new Date( '2022-07-02' ), value: 22.8 },
+ { date: new Date( '2022-07-09' ), value: 23.6 },
+ { date: new Date( '2022-07-16' ), value: 24.4 },
+ { date: new Date( '2022-07-23' ), value: 25.2 },
+ { date: new Date( '2022-07-30' ), value: 24.8 },
+ { date: new Date( '2022-08-06' ), value: 24.1 },
+ { date: new Date( '2022-08-13' ), value: 23.5 },
+ { date: new Date( '2022-08-20' ), value: 22.8 },
+ { date: new Date( '2022-08-27' ), value: 21.9 },
+ { date: new Date( '2022-09-03' ), value: 20.7 },
+ { date: new Date( '2022-09-10' ), value: 19.5 },
+ { date: new Date( '2022-09-17' ), value: 18.3 },
+ { date: new Date( '2022-09-24' ), value: 17.1 },
+ { date: new Date( '2022-10-01' ), value: 16.2 },
+ { date: new Date( '2022-10-08' ), value: 15.1 },
+ { date: new Date( '2022-10-15' ), value: 14.2 },
+ { date: new Date( '2022-10-22' ), value: 13.1 },
+ { date: new Date( '2022-10-29' ), value: 12.2 },
+ { date: new Date( '2022-11-05' ), value: 11.1 },
+ { date: new Date( '2022-11-12' ), value: 10.2 },
+ { date: new Date( '2022-11-19' ), value: 9.1 },
+ { date: new Date( '2022-11-26' ), value: 8.2 },
+ { date: new Date( '2022-12-03' ), value: 7.1 },
+ { date: new Date( '2022-12-10' ), value: 6.2 },
+ { date: new Date( '2022-12-17' ), value: 5.5 },
+ { date: new Date( '2022-12-24' ), value: 5.2 },
+ { date: new Date( '2022-12-31' ), value: 6.8 },
+ // 2023 data
+ { date: new Date( '2023-01-01' ), value: 8.2 },
+ { date: new Date( '2023-01-08' ), value: 7.9 },
+ { date: new Date( '2023-01-15' ), value: 5.1 },
+ { date: new Date( '2023-01-22' ), value: 4.8 },
+ { date: new Date( '2023-01-29' ), value: 6.3 },
+ { date: new Date( '2023-02-05' ), value: 7.2 },
+ { date: new Date( '2023-02-12' ), value: 9.4 },
+ { date: new Date( '2023-02-19' ), value: 8.7 },
+ { date: new Date( '2023-02-26' ), value: 7.1 },
+ { date: new Date( '2023-03-05' ), value: 8.3 },
+ { date: new Date( '2023-03-12' ), value: 9.5 },
+ { date: new Date( '2023-03-19' ), value: 11.2 },
+ { date: new Date( '2023-03-26' ), value: 12.8 },
+ { date: new Date( '2023-04-02' ), value: 13.4 },
+ { date: new Date( '2023-04-09' ), value: 14.1 },
+ { date: new Date( '2023-04-16' ), value: 15.3 },
+ { date: new Date( '2023-04-23' ), value: 14.8 },
+ { date: new Date( '2023-04-30' ), value: 15.7 },
+ { date: new Date( '2023-05-07' ), value: 16.9 },
+ { date: new Date( '2023-05-14' ), value: 17.2 },
+ { date: new Date( '2023-05-21' ), value: 18.4 },
+ { date: new Date( '2023-05-28' ), value: 19.1 },
+ { date: new Date( '2023-06-04' ), value: 20.3 },
+ { date: new Date( '2023-06-11' ), value: 21.5 },
+ { date: new Date( '2023-06-18' ), value: 22.8 },
+ { date: new Date( '2023-06-25' ), value: 21.9 },
+ { date: new Date( '2023-07-02' ), value: 23.1 },
+ { date: new Date( '2023-07-09' ), value: 22.7 },
+ { date: new Date( '2023-07-16' ), value: 24.2 },
+ { date: new Date( '2023-07-23' ), value: 23.8 },
+ { date: new Date( '2023-07-30' ), value: 22.9 },
+ { date: new Date( '2023-08-06' ), value: 23.4 },
+ { date: new Date( '2023-08-13' ), value: 22.8 },
+ { date: new Date( '2023-08-20' ), value: 21.9 },
+ { date: new Date( '2023-08-27' ), value: 20.7 },
+ { date: new Date( '2023-09-03' ), value: 19.8 },
+ { date: new Date( '2023-09-10' ), value: 18.9 },
+ { date: new Date( '2023-09-17' ), value: 17.6 },
+ { date: new Date( '2023-09-24' ), value: 16.8 },
+ { date: new Date( '2023-10-01' ), value: 15.9 },
+ { date: new Date( '2023-10-08' ), value: 14.7 },
+ { date: new Date( '2023-10-15' ), value: 13.8 },
+ { date: new Date( '2023-10-22' ), value: 12.9 },
+ { date: new Date( '2023-10-29' ), value: 11.7 },
+ { date: new Date( '2023-11-05' ), value: 10.8 },
+ { date: new Date( '2023-11-12' ), value: 9.9 },
+ { date: new Date( '2023-11-19' ), value: 8.7 },
+ { date: new Date( '2023-11-26' ), value: 7.8 },
+ { date: new Date( '2023-12-03' ), value: 6.9 },
+ { date: new Date( '2023-12-10' ), value: 5.8 },
+ { date: new Date( '2023-12-17' ), value: 4.9 },
+ { date: new Date( '2023-12-24' ), value: 5.7 },
+ { date: new Date( '2023-12-31' ), value: 6.2 },
+ ],
+ },
+ {
+ label: 'Canberra',
+ data: [
+ // 2022 data
+ { date: new Date( '2022-01-01' ), value: 27.9 },
+ { date: new Date( '2022-01-08' ), value: 28.4 },
+ { date: new Date( '2022-01-15' ), value: 29.2 },
+ { date: new Date( '2022-01-22' ), value: 28.9 },
+ { date: new Date( '2022-01-29' ), value: 28.1 },
+ { date: new Date( '2022-02-05' ), value: 27.3 },
+ { date: new Date( '2022-02-12' ), value: 26.5 },
+ { date: new Date( '2022-02-19' ), value: 25.4 },
+ { date: new Date( '2022-02-26' ), value: 24.2 },
+ { date: new Date( '2022-03-05' ), value: 23.1 },
+ { date: new Date( '2022-03-12' ), value: 22.3 },
+ { date: new Date( '2022-03-19' ), value: 21.2 },
+ { date: new Date( '2022-03-26' ), value: 20.1 },
+ { date: new Date( '2022-04-02' ), value: 19.2 },
+ { date: new Date( '2022-04-09' ), value: 18.1 },
+ { date: new Date( '2022-04-16' ), value: 16.9 },
+ { date: new Date( '2022-04-23' ), value: 15.8 },
+ { date: new Date( '2022-04-30' ), value: 14.9 },
+ { date: new Date( '2022-05-07' ), value: 13.8 },
+ { date: new Date( '2022-05-14' ), value: 12.9 },
+ { date: new Date( '2022-05-21' ), value: 11.8 },
+ { date: new Date( '2022-05-28' ), value: 10.9 },
+ { date: new Date( '2022-06-04' ), value: 9.8 },
+ { date: new Date( '2022-06-11' ), value: 8.9 },
+ { date: new Date( '2022-06-18' ), value: 8.1 },
+ { date: new Date( '2022-06-25' ), value: 7.5 },
+ { date: new Date( '2022-07-02' ), value: 6.9 },
+ { date: new Date( '2022-07-09' ), value: 6.7 },
+ { date: new Date( '2022-07-16' ), value: 7.1 },
+ { date: new Date( '2022-07-23' ), value: 7.9 },
+ { date: new Date( '2022-07-30' ), value: 8.8 },
+ { date: new Date( '2022-08-06' ), value: 9.9 },
+ { date: new Date( '2022-08-13' ), value: 11.2 },
+ { date: new Date( '2022-08-20' ), value: 12.4 },
+ { date: new Date( '2022-08-27' ), value: 13.6 },
+ { date: new Date( '2022-09-03' ), value: 14.8 },
+ { date: new Date( '2022-09-10' ), value: 16.1 },
+ { date: new Date( '2022-09-17' ), value: 17.3 },
+ { date: new Date( '2022-09-24' ), value: 18.5 },
+ { date: new Date( '2022-10-01' ), value: 19.8 },
+ { date: new Date( '2022-10-08' ), value: 21.1 },
+ { date: new Date( '2022-10-15' ), value: 22.3 },
+ { date: new Date( '2022-10-22' ), value: 23.5 },
+ { date: new Date( '2022-10-29' ), value: 24.6 },
+ { date: new Date( '2022-11-05' ), value: 25.7 },
+ { date: new Date( '2022-11-12' ), value: 26.5 },
+ { date: new Date( '2022-11-19' ), value: 27.4 },
+ { date: new Date( '2022-11-26' ), value: 28.2 },
+ { date: new Date( '2022-12-03' ), value: 28.9 },
+ { date: new Date( '2022-12-10' ), value: 29.5 },
+ { date: new Date( '2022-12-17' ), value: 29.1 },
+ { date: new Date( '2022-12-24' ), value: 28.2 },
+ { date: new Date( '2022-12-31' ), value: 28.7 },
+ // 2023 data
+ { date: new Date( '2023-01-01' ), value: 28.5 },
+ { date: new Date( '2023-01-08' ), value: 29.2 },
+ { date: new Date( '2023-01-15' ), value: 30.1 },
+ { date: new Date( '2023-01-22' ), value: 29.8 },
+ { date: new Date( '2023-01-29' ), value: 28.9 },
+ { date: new Date( '2023-02-05' ), value: 27.8 },
+ { date: new Date( '2023-02-12' ), value: 26.9 },
+ { date: new Date( '2023-02-19' ), value: 25.7 },
+ { date: new Date( '2023-02-26' ), value: 24.8 },
+ { date: new Date( '2023-03-05' ), value: 23.9 },
+ { date: new Date( '2023-03-12' ), value: 22.8 },
+ { date: new Date( '2023-03-19' ), value: 21.7 },
+ { date: new Date( '2023-03-26' ), value: 20.8 },
+ { date: new Date( '2023-04-02' ), value: 19.6 },
+ { date: new Date( '2023-04-09' ), value: 18.4 },
+ { date: new Date( '2023-04-16' ), value: 17.2 },
+ { date: new Date( '2023-04-23' ), value: 16.1 },
+ { date: new Date( '2023-04-30' ), value: 15.3 },
+ { date: new Date( '2023-05-07' ), value: 14.2 },
+ { date: new Date( '2023-05-14' ), value: 13.1 },
+ { date: new Date( '2023-05-21' ), value: 12.3 },
+ { date: new Date( '2023-05-28' ), value: 11.4 },
+ { date: new Date( '2023-06-04' ), value: 10.2 },
+ { date: new Date( '2023-06-11' ), value: 9.1 },
+ { date: new Date( '2023-06-18' ), value: 8.3 },
+ { date: new Date( '2023-06-25' ), value: 7.8 },
+ { date: new Date( '2023-07-02' ), value: 7.1 },
+ { date: new Date( '2023-07-09' ), value: 6.9 },
+ { date: new Date( '2023-07-16' ), value: 7.2 },
+ { date: new Date( '2023-07-23' ), value: 8.1 },
+ { date: new Date( '2023-07-30' ), value: 9.3 },
+ { date: new Date( '2023-08-06' ), value: 10.4 },
+ { date: new Date( '2023-08-13' ), value: 11.6 },
+ { date: new Date( '2023-08-20' ), value: 12.8 },
+ { date: new Date( '2023-08-27' ), value: 13.9 },
+ { date: new Date( '2023-09-03' ), value: 15.2 },
+ { date: new Date( '2023-09-10' ), value: 16.4 },
+ { date: new Date( '2023-09-17' ), value: 17.6 },
+ { date: new Date( '2023-09-24' ), value: 18.9 },
+ { date: new Date( '2023-10-01' ), value: 20.1 },
+ { date: new Date( '2023-10-08' ), value: 21.3 },
+ { date: new Date( '2023-10-15' ), value: 22.5 },
+ { date: new Date( '2023-10-22' ), value: 23.7 },
+ { date: new Date( '2023-10-29' ), value: 24.8 },
+ { date: new Date( '2023-11-05' ), value: 25.9 },
+ { date: new Date( '2023-11-12' ), value: 26.7 },
+ { date: new Date( '2023-11-19' ), value: 27.8 },
+ { date: new Date( '2023-11-26' ), value: 28.6 },
+ { date: new Date( '2023-12-03' ), value: 29.4 },
+ { date: new Date( '2023-12-10' ), value: 30.2 },
+ { date: new Date( '2023-12-17' ), value: 29.8 },
+ { date: new Date( '2023-12-24' ), value: 28.9 },
+ { date: new Date( '2023-12-31' ), value: 29.3 },
+ ],
+ },
+ {
+ label: 'Mars',
+ data: [
+ // 2022 data
+ { date: new Date( '2022-01-01' ), value: -62 },
+ { date: new Date( '2022-01-08' ), value: -63 },
+ { date: new Date( '2022-01-15' ), value: -64 },
+ { date: new Date( '2022-01-22' ), value: -62 },
+ { date: new Date( '2022-01-29' ), value: -61 },
+ { date: new Date( '2022-02-05' ), value: -59 },
+ { date: new Date( '2022-02-12' ), value: -56 },
+ { date: new Date( '2022-02-19' ), value: -53 },
+ { date: new Date( '2022-02-26' ), value: -50 },
+ { date: new Date( '2022-03-05' ), value: -47 },
+ { date: new Date( '2022-03-12' ), value: -44 },
+ { date: new Date( '2022-03-19' ), value: -41 },
+ { date: new Date( '2022-03-26' ), value: -37 },
+ { date: new Date( '2022-04-02' ), value: -34 },
+ { date: new Date( '2022-04-09' ), value: -31 },
+ { date: new Date( '2022-04-16' ), value: -27 },
+ { date: new Date( '2022-04-23' ), value: -24 },
+ { date: new Date( '2022-04-30' ), value: -21 },
+ { date: new Date( '2022-05-07' ), value: -17 },
+ { date: new Date( '2022-05-14' ), value: -14 },
+ { date: new Date( '2022-05-21' ), value: -11 },
+ { date: new Date( '2022-05-28' ), value: -7 },
+ { date: new Date( '2022-06-04' ), value: -4 },
+ { date: new Date( '2022-06-11' ), value: -1 },
+ { date: new Date( '2022-06-18' ), value: 1 },
+ { date: new Date( '2022-06-25' ), value: 3 },
+ { date: new Date( '2022-07-02' ), value: 6 },
+ { date: new Date( '2022-07-09' ), value: 9 },
+ { date: new Date( '2022-07-16' ), value: 11 },
+ { date: new Date( '2022-07-23' ), value: 13 },
+ { date: new Date( '2022-07-30' ), value: 16 },
+ { date: new Date( '2022-08-06' ), value: 18 },
+ { date: new Date( '2022-08-13' ), value: 21 },
+ { date: new Date( '2022-08-20' ), value: 23 },
+ { date: new Date( '2022-08-27' ), value: 21 },
+ { date: new Date( '2022-09-03' ), value: 19 },
+ { date: new Date( '2022-09-10' ), value: 16 },
+ { date: new Date( '2022-09-17' ), value: 13 },
+ { date: new Date( '2022-09-24' ), value: 9 },
+ { date: new Date( '2022-10-01' ), value: 6 },
+ { date: new Date( '2022-10-08' ), value: 3 },
+ { date: new Date( '2022-10-15' ), value: -1 },
+ { date: new Date( '2022-10-22' ), value: -4 },
+ { date: new Date( '2022-10-29' ), value: -7 },
+ { date: new Date( '2022-11-05' ), value: -11 },
+ { date: new Date( '2022-11-12' ), value: -14 },
+ { date: new Date( '2022-11-19' ), value: -17 },
+ { date: new Date( '2022-11-26' ), value: -21 },
+ { date: new Date( '2022-12-03' ), value: -24 },
+ { date: new Date( '2022-12-10' ), value: -27 },
+ { date: new Date( '2022-12-17' ), value: -31 },
+ { date: new Date( '2022-12-24' ), value: -36 },
+ { date: new Date( '2022-12-31' ), value: -37 },
+ // 2023 data
+ { date: new Date( '2023-01-01' ), value: -63 },
+ { date: new Date( '2023-01-08' ), value: -64 },
+ { date: new Date( '2023-01-15' ), value: -65 },
+ { date: new Date( '2023-01-22' ), value: -63 },
+ { date: new Date( '2023-01-29' ), value: -62 },
+ { date: new Date( '2023-02-05' ), value: -60 },
+ { date: new Date( '2023-02-12' ), value: -58 },
+ { date: new Date( '2023-02-19' ), value: -55 },
+ { date: new Date( '2023-02-26' ), value: -52 },
+ { date: new Date( '2023-03-05' ), value: -48 },
+ { date: new Date( '2023-03-12' ), value: -45 },
+ { date: new Date( '2023-03-19' ), value: -42 },
+ { date: new Date( '2023-03-26' ), value: -38 },
+ { date: new Date( '2023-04-02' ), value: -35 },
+ { date: new Date( '2023-04-09' ), value: -32 },
+ { date: new Date( '2023-04-16' ), value: -28 },
+ { date: new Date( '2023-04-23' ), value: -25 },
+ { date: new Date( '2023-04-30' ), value: -22 },
+ { date: new Date( '2023-05-07' ), value: -18 },
+ { date: new Date( '2023-05-14' ), value: -15 },
+ { date: new Date( '2023-05-21' ), value: -12 },
+ { date: new Date( '2023-05-28' ), value: -8 },
+ { date: new Date( '2023-06-04' ), value: -5 },
+ { date: new Date( '2023-06-11' ), value: -2 },
+ { date: new Date( '2023-06-18' ), value: 0 },
+ { date: new Date( '2023-06-25' ), value: 2 },
+ { date: new Date( '2023-07-02' ), value: 5 },
+ { date: new Date( '2023-07-09' ), value: 8 },
+ { date: new Date( '2023-07-16' ), value: 10 },
+ { date: new Date( '2023-07-23' ), value: 12 },
+ { date: new Date( '2023-07-30' ), value: 15 },
+ { date: new Date( '2023-08-06' ), value: 17 },
+ { date: new Date( '2023-08-13' ), value: 20 },
+ { date: new Date( '2023-08-20' ), value: 22 },
+ { date: new Date( '2023-08-27' ), value: 20 },
+ { date: new Date( '2023-09-03' ), value: 18 },
+ { date: new Date( '2023-09-10' ), value: 15 },
+ { date: new Date( '2023-09-17' ), value: 12 },
+ { date: new Date( '2023-09-24' ), value: 8 },
+ { date: new Date( '2023-10-01' ), value: 5 },
+ { date: new Date( '2023-10-08' ), value: 2 },
+ { date: new Date( '2023-10-15' ), value: -2 },
+ { date: new Date( '2023-10-22' ), value: -5 },
+ { date: new Date( '2023-10-29' ), value: -8 },
+ { date: new Date( '2023-11-05' ), value: -12 },
+ { date: new Date( '2023-11-12' ), value: -15 },
+ { date: new Date( '2023-11-19' ), value: -18 },
+ { date: new Date( '2023-11-26' ), value: -22 },
+ { date: new Date( '2023-12-03' ), value: -25 },
+ { date: new Date( '2023-12-10' ), value: -28 },
+ { date: new Date( '2023-12-17' ), value: -32 },
+ { date: new Date( '2023-12-24' ), value: -35 },
+ { date: new Date( '2023-12-31' ), value: -38 },
+ ],
+ },
+];
+
+export default temperatureData;
diff --git a/projects/js-packages/charts/src/components/pie-chart/index.tsx b/projects/js-packages/charts/src/components/pie-chart/index.tsx
new file mode 100644
index 0000000000000..c5b0025459ea3
--- /dev/null
+++ b/projects/js-packages/charts/src/components/pie-chart/index.tsx
@@ -0,0 +1 @@
+export { default as PieChart } from './pie-chart';
diff --git a/projects/js-packages/charts/src/components/pie-chart/pie-chart.module.scss b/projects/js-packages/charts/src/components/pie-chart/pie-chart.module.scss
new file mode 100644
index 0000000000000..cbb24ea286735
--- /dev/null
+++ b/projects/js-packages/charts/src/components/pie-chart/pie-chart.module.scss
@@ -0,0 +1,3 @@
+.pie-chart {
+ position: relative;
+}
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
new file mode 100644
index 0000000000000..712ce212792e1
--- /dev/null
+++ b/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx
@@ -0,0 +1,116 @@
+import { Group } from '@visx/group';
+import { Pie } from '@visx/shape';
+import clsx from 'clsx';
+import { SVGProps } from 'react';
+import useChartMouseHandler from '../../hooks/use-chart-mouse-handler';
+import { useChartTheme, defaultTheme } from '../../providers/theme';
+import { Tooltip } from '../tooltip';
+import styles from './pie-chart.module.scss';
+import type { BaseChartProps, DataPoint } from '../shared/types';
+
+// TODO: add animation
+
+interface PieChartProps extends BaseChartProps< DataPoint[] > {
+ /**
+ * Inner radius in pixels. If > 0, creates a donut chart. Defaults to 0.
+ */
+ innerRadius?: number;
+}
+
+/**
+ * Renders a pie or donut chart using the provided data.
+ *
+ * @param {PieChartProps} props - Component props
+ * @return {JSX.Element} The rendered chart component
+ */
+const PieChart = ( {
+ data,
+ width,
+ height,
+ withTooltips = false,
+ innerRadius = 0,
+ className,
+}: PieChartProps ) => {
+ const providerTheme = useChartTheme();
+ const { onMouseMove, onMouseLeave, tooltipOpen, tooltipData, tooltipLeft, tooltipTop } =
+ useChartMouseHandler( {
+ withTooltips,
+ } );
+
+ // Calculate radius based on width/height
+ const radius = Math.min( width, height ) / 2;
+ const centerX = width / 2;
+ const centerY = height / 2;
+
+ const accessors = {
+ value: d => d.value,
+ // Use the color property from the data object as a last resort. The theme provides colours by default.
+ fill: d => d.color || providerTheme.colors[ d.index ],
+ };
+
+ return (
+
+
+ { withTooltips && tooltipOpen && tooltipData && (
+
+ ) }
+
+ );
+};
+
+export default PieChart;
diff --git a/projects/js-packages/charts/src/components/pie-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/pie-chart/stories/index.stories.tsx
new file mode 100644
index 0000000000000..ddad97895531d
--- /dev/null
+++ b/projects/js-packages/charts/src/components/pie-chart/stories/index.stories.tsx
@@ -0,0 +1,94 @@
+import { ThemeProvider, jetpackTheme, wooTheme } from '../../../providers/theme';
+import { PieChart } from '../index';
+import type { Meta, StoryObj } from '@storybook/react';
+
+const data = [
+ { label: 'A', value: 30 },
+ { label: 'B', value: 20 },
+ { label: 'C', value: 15 },
+ { label: 'D', value: 35 },
+];
+
+type StoryType = StoryObj< typeof PieChart >;
+
+export default {
+ title: 'JS Packages/Charts/Types/Pie Chart',
+ component: PieChart,
+ parameters: {
+ layout: 'centered',
+ },
+ argTypes: {
+ theme: {
+ control: 'select',
+ options: {
+ default: undefined,
+ jetpack: jetpackTheme,
+ woo: wooTheme,
+ },
+ defaultValue: undefined,
+ },
+ },
+ decorators: [
+ ( Story, { args } ) => (
+
+
+
+
+
+ ),
+ ],
+} satisfies Meta< typeof PieChart >;
+
+export const Default: StoryType = {
+ args: {
+ width: 400,
+ height: 400,
+ withTooltips: false,
+ data,
+ theme: 'default',
+ innerRadius: 0,
+ },
+};
+
+export const Doughnut: StoryType = {
+ args: {
+ ...Default.args,
+ innerRadius: 80,
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Doughnut chart variant with inner radius of 80px.',
+ },
+ },
+ },
+};
+
+export const WithTooltips: StoryType = {
+ args: {
+ ...Default.args,
+ withTooltips: true,
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Pie chart with interactive tooltips that appear on hover.',
+ },
+ },
+ },
+};
+
+export const WithTooltipsDoughnut: StoryType = {
+ args: {
+ ...Default.args,
+ withTooltips: true,
+ innerRadius: 100,
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Doughnut chart with interactive tooltips that appear on hover.',
+ },
+ },
+ },
+};
diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx
index 988e15412b003..a6f0d30e6d68b 100644
--- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx
+++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx
@@ -8,23 +8,9 @@ import { FC, useCallback } from 'react';
import { useChartTheme } from '../../providers/theme/theme-provider';
import { BaseTooltip } from '../tooltip';
import styles from './pie-semi-circle-chart.module.scss';
-import type { DataPointPercentage } from '../shared/types';
+import type { BaseChartProps, DataPointPercentage } from '../shared/types';
-type ArcData = PieArcDatum< DataPointPercentage >;
-
-interface PieSemiCircleChartProps {
- /**
- * Array of data points to display in the chart
- */
- data: DataPointPercentage[];
- /**
- * Width of the chart in pixels
- */
- width: number;
- /**
- * Height of the chart in pixels
- */
- height: number;
+interface PieSemiCircleChartProps extends BaseChartProps< DataPointPercentage[] > {
/**
* Label text to display above the chart
*/
@@ -33,19 +19,18 @@ interface PieSemiCircleChartProps {
* Note text to display below the label
*/
note: string;
- /**
- * Whether to show tooltips
- */
- showTooltips?: boolean;
}
+type ArcData = PieArcDatum< DataPointPercentage >;
+
const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( {
data,
width,
height,
label,
note,
- showTooltips = false,
+ className,
+ withTooltips = false,
} ) => {
const providerTheme = useChartTheme();
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } =
@@ -97,7 +82,9 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( {
);
return (
-
+
- { showTooltips && tooltipOpen && tooltipData && (
+ { withTooltips && tooltipOpen && tooltipData && (
= {
+ /**
+ * Array of data points to display in the chart
+ */
+ data: T extends DataPoint | DataPointDate ? T[] : T;
+ /**
+ * Additional CSS class name for the chart container
+ */
+ className?: string;
+ /**
+ * Width of the chart in pixels
+ */
+ width: number;
+ /**
+ * Height of the chart in pixels
+ */
+ height: number;
+ /**
+ * Chart margins
+ */
+ margin?: {
+ top: number;
+ right: number;
+ bottom: number;
+ left: number;
+ };
+ /**
+ * Whether to show tooltips on hover. False by default.
+ */
+ withTooltips?: boolean;
+};
diff --git a/projects/js-packages/charts/src/hooks/use-chart-mouse-handler.ts b/projects/js-packages/charts/src/hooks/use-chart-mouse-handler.ts
new file mode 100644
index 0000000000000..8a1739a90e4ec
--- /dev/null
+++ b/projects/js-packages/charts/src/hooks/use-chart-mouse-handler.ts
@@ -0,0 +1,90 @@
+import { localPoint } from '@visx/event';
+import { useTooltip } from '@visx/tooltip';
+import { useCallback, type MouseEvent } from 'react';
+import type { DataPoint } from '../components/shared/types';
+
+type UseChartMouseHandlerProps = {
+ /**
+ * Whether tooltips are enabled
+ */
+ withTooltips: boolean;
+};
+
+type UseChartMouseHandlerReturn = {
+ /**
+ * Handler for mouse move events
+ */
+ onMouseMove: ( event: React.MouseEvent< SVGElement >, data: DataPoint ) => void;
+ /**
+ * Handler for mouse leave events
+ */
+ onMouseLeave: () => void;
+ /**
+ * Whether the tooltip is currently open
+ */
+ tooltipOpen: boolean;
+ /**
+ * The current tooltip data
+ */
+ tooltipData: DataPoint | null;
+ /**
+ * The current tooltip left position
+ */
+ tooltipLeft: number | undefined;
+ /**
+ * The current tooltip top position
+ */
+ tooltipTop: number | undefined;
+};
+
+/**
+ * Hook to handle mouse interactions for chart components
+ *
+ * @param {UseChartMouseHandlerProps} props - Hook configuration
+ * @return {UseChartMouseHandlerReturn} Object containing handlers and tooltip state
+ */
+const useChartMouseHandler = ( {
+ withTooltips,
+}: UseChartMouseHandlerProps ): UseChartMouseHandlerReturn => {
+ const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } =
+ useTooltip< DataPoint >();
+
+ // TODO: either debounce/throttle or use useTooltipInPortal with built-in debounce
+ const onMouseMove = useCallback(
+ ( event: MouseEvent< SVGElement >, data: DataPoint ) => {
+ if ( ! withTooltips ) {
+ return;
+ }
+
+ const coords = localPoint( event );
+ if ( ! coords ) {
+ return;
+ }
+
+ showTooltip( {
+ tooltipData: data,
+ tooltipLeft: coords.x,
+ tooltipTop: coords.y - 10,
+ } );
+ },
+ [ withTooltips, showTooltip ]
+ );
+
+ const onMouseLeave = useCallback( () => {
+ if ( ! withTooltips ) {
+ return;
+ }
+ hideTooltip();
+ }, [ withTooltips, hideTooltip ] );
+
+ return {
+ onMouseMove,
+ onMouseLeave,
+ tooltipOpen,
+ tooltipData,
+ tooltipLeft,
+ tooltipTop,
+ };
+};
+
+export default useChartMouseHandler;
diff --git a/projects/js-packages/charts/src/index.ts b/projects/js-packages/charts/src/index.ts
index 8dc8f3221948a..b52a51461252c 100644
--- a/projects/js-packages/charts/src/index.ts
+++ b/projects/js-packages/charts/src/index.ts
@@ -1,6 +1,17 @@
+// Charts
export { default as BarChart } from './components/bar-chart';
export { LineChart } from './components/line-chart';
+export { PieChart } from './components/pie-chart';
export { PieSemiCircleChart } from './components/pie-semi-circle-chart';
-export type * from './components/shared/types';
+
+// Chart components
export { BaseTooltip } from './components/tooltip';
+
+// Providers
+export { ThemeProvider } from './providers/theme';
+
+// Hooks
+
+// Types
+export type * from './components/shared/types';
export type { BaseTooltipProps } from './components/tooltip';
diff --git a/projects/js-packages/charts/src/providers/theme/themes.ts b/projects/js-packages/charts/src/providers/theme/themes.ts
index b41d14bd845a1..58bcf3c3fcb31 100644
--- a/projects/js-packages/charts/src/providers/theme/themes.ts
+++ b/projects/js-packages/charts/src/providers/theme/themes.ts
@@ -4,7 +4,8 @@ import type { ChartTheme } from '../../components/shared/types';
* Default theme configuration
*/
const defaultTheme: ChartTheme = {
- backgroundColor: '#FFFFFF',
+ backgroundColor: '#FFFFFF', // chart background color
+ labelBackgroundColor: '#FFFFFF', // label background color
colors: [ '#98C8DF', '#006DAB', '#A6DC80', '#1F9828', '#FF8C8F' ],
gridStyles: {
stroke: '#787C82',
@@ -19,7 +20,8 @@ const defaultTheme: ChartTheme = {
* Jetpack theme configuration
*/
const jetpackTheme: ChartTheme = {
- backgroundColor: '#FFFFFF',
+ backgroundColor: '#FFFFFF', // chart background color
+ labelBackgroundColor: '#FFFFFF', // label background color
colors: [ '#98C8DF', '#006DAB', '#A6DC80', '#1F9828', '#FF8C8F' ],
gridStyles: {
stroke: '#787C82',
@@ -34,7 +36,8 @@ const jetpackTheme: ChartTheme = {
* Woo theme configuration
*/
const wooTheme: ChartTheme = {
- backgroundColor: '#FFFFFF',
+ backgroundColor: '#FFFFFF', // chart background color
+ labelBackgroundColor: '#FFFFFF', // label background color
colors: [ '#80C8FF', '#B999FF', '#3858E9' ],
gridStyles: {
stroke: '#787C82',