From 05520a6928e9ac04650eb4cd8335db720ce1ce42 Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:01:21 +1100 Subject: [PATCH 01/28] add @visx/legend to package and update lockfile --- pnpm-lock.yaml | 17 +++++++++++++++++ projects/js-packages/charts/package.json | 1 + 2 files changed, 18 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4af216da4b55c..36e104e9f2fad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -304,6 +304,9 @@ importers: '@visx/group': specifier: ^3.12.0 version: 3.12.0(react@18.3.1) + '@visx/legend': + specifier: ^3.12.0 + version: 3.12.0(react@18.3.1) '@visx/scale': specifier: ^3.12.0 version: 3.12.0 @@ -7911,6 +7914,11 @@ packages: peerDependencies: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 + '@visx/legend@3.12.0': + resolution: {integrity: sha512-Tr6hdauEDXRXVNeNgIQ9JtCCrxn8Fbr8UCVlO9XsSxenk2hBC/2PIY5QPzpnKFEEEuH/C8vhj8T0JfFZV+D9zQ==} + peerDependencies: + react: ^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0 + '@visx/point@3.12.0': resolution: {integrity: sha512-I6UrHoJAEVbx3RORQNupgTiX5EzjuZpiwLPxn8L2mI5nfERotPKi1Yus12Cq2WtXqEBR/WgqTnoImlqOXBykcA==} @@ -18507,6 +18515,15 @@ snapshots: prop-types: 15.8.1 react: 18.3.1 + '@visx/legend@3.12.0(react@18.3.1)': + dependencies: + '@types/react': 18.3.13 + '@visx/group': 3.12.0(react@18.3.1) + '@visx/scale': 3.12.0 + classnames: 2.5.1 + prop-types: 15.8.1 + react: 18.3.1 + '@visx/point@3.12.0': {} '@visx/react-spring@3.12.0(@react-spring/web@9.7.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': diff --git a/projects/js-packages/charts/package.json b/projects/js-packages/charts/package.json index 41e7c7118aaa1..a71136cf6df8e 100644 --- a/projects/js-packages/charts/package.json +++ b/projects/js-packages/charts/package.json @@ -23,6 +23,7 @@ "@react-spring/web": "9.7.3", "@visx/axis": "^3.12.0", "@visx/group": "^3.12.0", + "@visx/legend": "^3.12.0", "@visx/scale": "^3.12.0", "@visx/shape": "^3.12.0", "@visx/text": "3.12.0", From 016a1e4204db2b37503566e29e19b0033d1ecbda Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:01:39 +1100 Subject: [PATCH 02/28] create index file for legend component --- projects/js-packages/charts/src/components/legend/index.ts | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 projects/js-packages/charts/src/components/legend/index.ts diff --git a/projects/js-packages/charts/src/components/legend/index.ts b/projects/js-packages/charts/src/components/legend/index.ts new file mode 100644 index 0000000000000..546a0d202245d --- /dev/null +++ b/projects/js-packages/charts/src/components/legend/index.ts @@ -0,0 +1,2 @@ +export { BaseLegend } from './base-legend'; +export type { LegendProps } from './types'; From 3735c0da594e0fe75fc52601633310865b821382 Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:01:57 +1100 Subject: [PATCH 03/28] add base default/fallback legend --- .../src/components/legend/base-legend.tsx | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 projects/js-packages/charts/src/components/legend/base-legend.tsx diff --git a/projects/js-packages/charts/src/components/legend/base-legend.tsx b/projects/js-packages/charts/src/components/legend/base-legend.tsx new file mode 100644 index 0000000000000..762b53f5ffe52 --- /dev/null +++ b/projects/js-packages/charts/src/components/legend/base-legend.tsx @@ -0,0 +1,60 @@ +import { LegendOrdinal } from '@visx/legend'; +import { scaleOrdinal } from '@visx/scale'; +import clsx from 'clsx'; +import { FC, useCallback } from 'react'; +import styles from './legend.module.scss'; +import type { LegendProps } from './types'; + +/** + * Base legend component that displays color-coded items with labels using visx + * @param {object} props - Component properties + * @param {Array} props.items - Array of legend items to display + * @param {string} props.className - Additional CSS class names + * @param {string} props.orientation - Layout orientation (horizontal/vertical) + * @return {JSX.Element} Rendered legend component + */ +const orientationToFlexDirection = { + horizontal: 'row' as const, + vertical: 'column' as const, +}; + +export const BaseLegend: FC< LegendProps > = ( { + items, + className, + orientation = 'horizontal', +} ) => { + const legendScale = scaleOrdinal( { + domain: items.map( item => item.label ), + range: items.map( item => item.color ), + } ); + + const handleLabelFormat = useCallback( + ( label: string ) => { + const item = items.find( i => i.label === label ); + return `${ label }${ item?.value ? ` ${ item.value }` : '' }`; + }, + [ items ] + ); + + return ( +
+ +
+ ); +}; From 7514de767c5e2dc2d148bcaaa1b968e3140b0251 Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:02:10 +1100 Subject: [PATCH 04/28] add legend module scss for styling --- .../src/components/legend/legend.module.scss | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 projects/js-packages/charts/src/components/legend/legend.module.scss diff --git a/projects/js-packages/charts/src/components/legend/legend.module.scss b/projects/js-packages/charts/src/components/legend/legend.module.scss new file mode 100644 index 0000000000000..b0eaa3ee20d41 --- /dev/null +++ b/projects/js-packages/charts/src/components/legend/legend.module.scss @@ -0,0 +1,43 @@ +.legend { + &--vertical { + .legend-items { + flex-direction: column; + } + } + + &--horizontal { + .legend-items { + flex-direction: row; + flex-wrap: wrap; + } + } +} + +.legend-items { + display: flex; + gap: 1rem; +} + +.legend-item { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.875rem; +} + +.legend-item-swatch { + width: 1rem !important; + height: 1rem !important; + border-radius: 2px; +} + +.legend-item-label { + color: var(--jp-gray-80); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.legend-item-value { + font-weight: 500; +} From ede92ce2a8df74c1ef357ff48775f0affb4ac71c Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:02:17 +1100 Subject: [PATCH 05/28] add legend types --- .../charts/src/components/legend/types.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 projects/js-packages/charts/src/components/legend/types.ts diff --git a/projects/js-packages/charts/src/components/legend/types.ts b/projects/js-packages/charts/src/components/legend/types.ts new file mode 100644 index 0000000000000..ab66fa1210c0f --- /dev/null +++ b/projects/js-packages/charts/src/components/legend/types.ts @@ -0,0 +1,14 @@ +import { scaleOrdinal } from '@visx/scale'; + +export type LegendItem = { + label: string; + value: number | string; + color: string; +}; + +export type LegendProps = { + items: LegendItem[]; + className?: string; + orientation?: 'horizontal' | 'vertical'; + scale?: ReturnType< typeof scaleOrdinal >; +}; From 503542e73f311c8b2161d2358fe93b1d1504d40a Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:02:28 +1100 Subject: [PATCH 06/28] add legend to storybook --- .../legend/stories/index.stories.tsx | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 projects/js-packages/charts/src/components/legend/stories/index.stories.tsx diff --git a/projects/js-packages/charts/src/components/legend/stories/index.stories.tsx b/projects/js-packages/charts/src/components/legend/stories/index.stories.tsx new file mode 100644 index 0000000000000..dfba38d008992 --- /dev/null +++ b/projects/js-packages/charts/src/components/legend/stories/index.stories.tsx @@ -0,0 +1,35 @@ +import { BaseLegend } from '../index'; +import type { Meta } from '@storybook/react'; + +const data = [ + { label: 'Desktop', value: '86%', color: '#3858E9' }, + { label: 'Mobile', value: '52%', color: '#80C8FF' }, +]; + +export default { + title: 'JS Packages/Charts/Legend', + component: BaseLegend, + parameters: { + layout: 'centered', + docs: { + description: { + component: + 'A flexible legend component that can be customized with different styles and orientations.', + }, + }, + }, +} satisfies Meta< typeof BaseLegend >; + +const Template = args => ; + +export const Default = Template.bind( {} ); +Default.args = { + items: data, + orientation: 'horizontal', +}; + +export const Vertical = Template.bind( {} ); +Vertical.args = { + items: data, + orientation: 'vertical', +}; From 00e2383a7db5b1b46b87b6124998e0b545ea625e Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:32:20 +1100 Subject: [PATCH 07/28] add both vertical and horizontal orientations for legend --- .../src/components/legend/base-legend.tsx | 48 ++++++++++-------- .../src/components/legend/legend.module.scss | 27 ++++------ .../legend/stories/index.stories.tsx | 50 ++++++++++++------- 3 files changed, 70 insertions(+), 55 deletions(-) diff --git a/projects/js-packages/charts/src/components/legend/base-legend.tsx b/projects/js-packages/charts/src/components/legend/base-legend.tsx index 762b53f5ffe52..66e9406ed1aef 100644 --- a/projects/js-packages/charts/src/components/legend/base-legend.tsx +++ b/projects/js-packages/charts/src/components/legend/base-legend.tsx @@ -1,7 +1,7 @@ import { LegendOrdinal } from '@visx/legend'; import { scaleOrdinal } from '@visx/scale'; import clsx from 'clsx'; -import { FC, useCallback } from 'react'; +import { FC } from 'react'; import styles from './legend.module.scss'; import type { LegendProps } from './types'; @@ -28,33 +28,41 @@ export const BaseLegend: FC< LegendProps > = ( { range: items.map( item => item.color ), } ); - const handleLabelFormat = useCallback( - ( label: string ) => { - const item = items.find( i => i.label === label ); - return `${ label }${ item?.value ? ` ${ item.value }` : '' }`; - }, - [ items ] - ); - return ( -
+
+ { labels => ( +
+ { labels.map( label => ( +
+ + + + + { label.text } + { items.find( item => item.label === label.text )?.value && ( + + { items.find( item => item.label === label.text )?.value } + + ) } + +
+ ) ) } +
) } - labelFormat={ handleLabelFormat } - /> +
); }; diff --git a/projects/js-packages/charts/src/components/legend/legend.module.scss b/projects/js-packages/charts/src/components/legend/legend.module.scss index b0eaa3ee20d41..e6b654d5896d5 100644 --- a/projects/js-packages/charts/src/components/legend/legend.module.scss +++ b/projects/js-packages/charts/src/components/legend/legend.module.scss @@ -1,33 +1,26 @@ .legend { - &--vertical { - .legend-items { - flex-direction: column; - } - } - &--horizontal { - .legend-items { - flex-direction: row; - flex-wrap: wrap; - } + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 16px; } -} -.legend-items { - display: flex; - gap: 1rem; + &--vertical { + display: flex; + flex-direction: column; + gap: 8px; + } } .legend-item { display: flex; align-items: center; - gap: 0.5rem; + gap: 8px; font-size: 0.875rem; } .legend-item-swatch { - width: 1rem !important; - height: 1rem !important; border-radius: 2px; } diff --git a/projects/js-packages/charts/src/components/legend/stories/index.stories.tsx b/projects/js-packages/charts/src/components/legend/stories/index.stories.tsx index dfba38d008992..2844ecbfd8ea4 100644 --- a/projects/js-packages/charts/src/components/legend/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/legend/stories/index.stories.tsx @@ -1,12 +1,7 @@ -import { BaseLegend } from '../index'; -import type { Meta } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; +import { BaseLegend } from '../base-legend'; -const data = [ - { label: 'Desktop', value: '86%', color: '#3858E9' }, - { label: 'Mobile', value: '52%', color: '#80C8FF' }, -]; - -export default { +const meta: Meta< typeof BaseLegend > = { title: 'JS Packages/Charts/Legend', component: BaseLegend, parameters: { @@ -18,18 +13,37 @@ export default { }, }, }, -} satisfies Meta< typeof BaseLegend >; +}; + +export default meta; +type Story = StoryObj< typeof BaseLegend >; + +const mockData = [ + { label: 'Desktop', value: '86%', color: '#3858E9' }, + { label: 'Mobile', value: '52%', color: '#80C8FF' }, +]; -const Template = args => ; +export const Horizontal: Story = { + args: { + items: mockData, + orientation: 'horizontal', + }, +}; -export const Default = Template.bind( {} ); -Default.args = { - items: data, - orientation: 'horizontal', +export const Vertical: Story = { + args: { + items: mockData, + orientation: 'vertical', + }, }; -export const Vertical = Template.bind( {} ); -Vertical.args = { - items: data, - orientation: 'vertical', +export const WithLongLabels: Story = { + args: { + items: [ + { label: 'Very Long Desktop Usage', value: '86%', color: '#3858E9' }, + { label: 'Extended Mobile Sessions', value: '52%', color: '#80C8FF' }, + { label: 'Tablet Device Access', value: '35%', color: '#44B556' }, + ], + orientation: 'horizontal', + }, }; From 776d17b4d64cb33091cdd4d460f4788a18086342 Mon Sep 17 00:00:00 2001 From: annacmc Date: Fri, 13 Dec 2024 00:32:54 +1100 Subject: [PATCH 08/28] changelog --- .../charts/changelog/add-chart-library-legend-component | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 projects/js-packages/charts/changelog/add-chart-library-legend-component diff --git a/projects/js-packages/charts/changelog/add-chart-library-legend-component b/projects/js-packages/charts/changelog/add-chart-library-legend-component new file mode 100644 index 0000000000000..47958063ac1fa --- /dev/null +++ b/projects/js-packages/charts/changelog/add-chart-library-legend-component @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Chart library: add legend component From 6bf77ea0faf491c0d5a0d001471c78d80cebdf56 Mon Sep 17 00:00:00 2001 From: annacmc Date: Mon, 16 Dec 2024 13:02:36 +1100 Subject: [PATCH 09/28] add legend support to bar chart --- .../src/components/bar-chart/bar-chart.tsx | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index ee4fe451fe464..e5bc11fc1bbc6 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -7,8 +7,10 @@ import { useTooltip } from '@visx/tooltip'; import clsx from 'clsx'; import { FC, useCallback } from 'react'; import { useChartTheme } from '../../providers/theme'; +import { BaseLegend } from '../legend'; import { BaseTooltip } from '../tooltip'; import styles from './bar-chart.module.scss'; +import type { LegendItem } from '../legend/types'; import type { DataPoint } from '../shared/types'; type BarChartProps = { @@ -37,6 +39,14 @@ type BarChartProps = { * Whether to show tooltips on hover */ showTooltips?: boolean; + /** + * Whether to show legend + */ + showLegend?: boolean; + /** + * Legend orientation + */ + legendOrientation?: 'horizontal' | 'vertical'; }; const BarChart: FC< BarChartProps > = ( { @@ -45,6 +55,8 @@ const BarChart: FC< BarChartProps > = ( { height, margin = { top: 20, right: 20, bottom: 40, left: 40 }, showTooltips = false, + showLegend = false, + legendOrientation = 'horizontal', } ) => { const theme = useChartTheme(); const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = @@ -90,9 +102,20 @@ const BarChart: FC< BarChartProps > = ( { [ handleMouseMove ] ); + // Create legend items from data and theme colors + const legendItems: LegendItem[] = data.map( ( item, index ) => ( { + label: item.label, + value: item.value, + color: theme.colors[ index % theme.colors.length ], + } ) ); + + // Calculate chart dimensions accounting for legend + const legendHeight = showLegend && legendOrientation === 'horizontal' ? 50 : 0; + const chartHeight = height - legendHeight; + return (
- + { data.map( d => ( = ( { left={ tooltipLeft } /> ) } + + { showLegend && ( + + ) }
); }; From fbe7460d50285ac895e014e347bb7c8193ba2f7b Mon Sep 17 00:00:00 2001 From: annacmc Date: Mon, 16 Dec 2024 13:04:01 +1100 Subject: [PATCH 10/28] bar chart legend styling update --- .../charts/src/components/bar-chart/bar-chart.module.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.module.scss b/projects/js-packages/charts/src/components/bar-chart/bar-chart.module.scss index ec94022ab4d88..cdf8d80241671 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.module.scss +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.module.scss @@ -1,3 +1,7 @@ .bar-chart { position: relative; + + &-legend { + margin-top: 1rem; + } } From d2b2667c56b19fcf1cda843d5575dffa6497be11 Mon Sep 17 00:00:00 2001 From: annacmc Date: Mon, 16 Dec 2024 13:13:43 +1100 Subject: [PATCH 11/28] add horizontsl and vertical legends to barchart stories --- .../bar-chart/stories/index.stories.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx index adeffc6a73811..1e758eb30126e 100644 --- a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx @@ -49,3 +49,22 @@ WithTooltips.parameters = { }, }, }; + +export const WithLegend = { + args: { + width: 500, + height: 350, + margin: { top: 20, right: 20, bottom: 40, left: 40 }, + data, + showTooltips: true, + showLegend: true, + legendOrientation: 'horizontal', + }, +}; + +export const WithVerticalLegend = { + args: { + ...WithLegend.args, + legendOrientation: 'vertical', + }, +}; From 5b802e5c0e2d2fd22558819a580faecf9922199d Mon Sep 17 00:00:00 2001 From: annacmc Date: Mon, 16 Dec 2024 16:09:17 +1100 Subject: [PATCH 12/28] Add legend to barchart --- .../src/components/bar-chart/bar-chart.tsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index e5bc11fc1bbc6..54c4986762ebb 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -66,6 +66,7 @@ const BarChart: FC< BarChartProps > = ( { const xMax = width - margins.left - margins.right; const yMax = height - margins.top - margins.bottom; + // Create scales const xScale = scaleBand< string >( { range: [ 0, xMax ], domain: data.map( d => d.label ), @@ -103,19 +104,21 @@ const BarChart: FC< BarChartProps > = ( { ); // Create legend items from data and theme colors - const legendItems: LegendItem[] = data.map( ( item, index ) => ( { + const legendItems: LegendItem[] = data.map( item => ( { label: item.label, - value: item.value, - color: theme.colors[ index % theme.colors.length ], + value: item.value.toString(), + color: theme.colors[ 0 ], } ) ); - // Calculate chart dimensions accounting for legend - const legendHeight = showLegend && legendOrientation === 'horizontal' ? 50 : 0; - const chartHeight = height - legendHeight; - return ( -
- +
+ { data.map( d => ( = ( { onMouseLeave={ handleMouseLeave } /> ) ) } + + { /* Axes */ } From a047836c2fb53c7ba1e0276abdd3e293c34b0315 Mon Sep 17 00:00:00 2001 From: annacmc Date: Mon, 16 Dec 2024 16:09:56 +1100 Subject: [PATCH 13/28] add legend orientation styles --- .../js-packages/charts/src/components/legend/base-legend.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/projects/js-packages/charts/src/components/legend/base-legend.tsx b/projects/js-packages/charts/src/components/legend/base-legend.tsx index 66e9406ed1aef..fb6a32f1aa28a 100644 --- a/projects/js-packages/charts/src/components/legend/base-legend.tsx +++ b/projects/js-packages/charts/src/components/legend/base-legend.tsx @@ -29,7 +29,10 @@ export const BaseLegend: FC< LegendProps > = ( { } ); return ( -
+
Date: Mon, 16 Dec 2024 16:47:30 +1100 Subject: [PATCH 14/28] add legend to PieSemiCircleChartProps --- .../pie-semi-circle-chart.module.scss | 4 +++ .../pie-semi-circle-chart.tsx | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss index 54c0bfb01e098..92f0495c28a0e 100644 --- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss @@ -2,6 +2,10 @@ position: relative; text-align: center; + &-legend { + margin-top: 1rem; + } + .label { margin-bottom: 0px; // Add space between label and pie chart font-weight: 600; // Make label more prominent than note 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..742ce1834992e 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 @@ -6,6 +6,7 @@ import { useTooltip } from '@visx/tooltip'; import clsx from 'clsx'; import { FC, useCallback } from 'react'; import { useChartTheme } from '../../providers/theme/theme-provider'; +import { BaseLegend } from '../legend'; import { BaseTooltip } from '../tooltip'; import styles from './pie-semi-circle-chart.module.scss'; import type { DataPointPercentage } from '../shared/types'; @@ -37,6 +38,14 @@ interface PieSemiCircleChartProps { * Whether to show tooltips */ showTooltips?: boolean; + /** + * Whether to show legend + */ + showLegend?: boolean; + /** + * Orientation of the legend + */ + legendOrientation?: 'horizontal' | 'vertical'; } const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { @@ -46,6 +55,8 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { label, note, showTooltips = false, + showLegend = false, + legendOrientation = 'horizontal', } ) => { const providerTheme = useChartTheme(); const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = @@ -96,6 +107,13 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { [ handleMouseMove ] ); + // Create legend items + const legendItems = data.map( ( item, index ) => ( { + label: item.label, + value: item.valueDisplay || item.value.toString(), + color: accessors.fill( { ...item, index } ), + } ) ); + return (
@@ -158,6 +176,14 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { left={ tooltipLeft } /> ) } + + { showLegend && ( + + ) }
); }; From 860336a4c9ee9d362e5843212287cef7c4737316 Mon Sep 17 00:00:00 2001 From: annacmc Date: Mon, 16 Dec 2024 16:49:36 +1100 Subject: [PATCH 15/28] create legend story for pie semi circle chart --- .../stories/index.stories.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx index 1910ff47ce4ac..ef80021430e50 100644 --- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx @@ -57,3 +57,17 @@ WithTooltips.args = { note: 'Windows +10%', showTooltips: true, }; + +export const WithHorizontalLegend = Template.bind( {} ); +WithHorizontalLegend.args = { + ...Default.args, + showLegend: true, + legendOrientation: 'horizontal', +}; + +export const WithVerticalLegend = Template.bind( {} ); +WithVerticalLegend.args = { + ...Default.args, + showLegend: true, + legendOrientation: 'vertical', +}; From f8bb1dc2b12155d0ea43f93197ed0b25b0075ce5 Mon Sep 17 00:00:00 2001 From: annacmc Date: Mon, 16 Dec 2024 21:21:33 +1100 Subject: [PATCH 16/28] update legend barrelfile export/imports --- .../js-packages/charts/src/components/bar-chart/bar-chart.tsx | 4 ++-- projects/js-packages/charts/src/components/legend/index.ts | 2 +- .../pie-semi-circle-chart/pie-semi-circle-chart.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index 54c4986762ebb..e9f33025cd281 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -7,7 +7,7 @@ import { useTooltip } from '@visx/tooltip'; import clsx from 'clsx'; import { FC, useCallback } from 'react'; import { useChartTheme } from '../../providers/theme'; -import { BaseLegend } from '../legend'; +import { Legend } from '../legend'; import { BaseTooltip } from '../tooltip'; import styles from './bar-chart.module.scss'; import type { LegendItem } from '../legend/types'; @@ -151,7 +151,7 @@ const BarChart: FC< BarChartProps > = ( { ) } { showLegend && ( - = ( { ) } { showLegend && ( - Date: Tue, 17 Dec 2024 18:28:46 +1100 Subject: [PATCH 17/28] remove legendItem from barchart for now --- .../js-packages/charts/src/components/bar-chart/bar-chart.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index 8c4d0217e93c9..0697a41a7c496 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -10,7 +10,6 @@ import { useChartTheme } from '../../providers/theme'; import { Legend } from '../legend'; import { BaseTooltip } from '../tooltip'; import styles from './bar-chart.module.scss'; -import type { LegendItem } from '../legend/types'; import type { BaseChartProps, DataPoint } from '../shared/types'; interface BarChartProps extends BaseChartProps { From b3ec02e163d7e486bf52dcc226f3bd0b932ce8ec Mon Sep 17 00:00:00 2001 From: annacmc Date: Tue, 17 Dec 2024 20:55:14 +1100 Subject: [PATCH 18/28] fix data structure for legend barchart --- .../charts/src/components/bar-chart/stories/index.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx index 10392ec03cf3e..6cbe77894dc85 100644 --- a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx @@ -47,7 +47,7 @@ export const WithLegend = { width: 500, height: 350, margin: { top: 20, right: 20, bottom: 40, left: 40 }, - data, + data: data[ 0 ].data, showTooltips: true, showLegend: true, legendOrientation: 'horizontal', From 2edbe8bb37715b795c2896c97a2971c63bd3e539 Mon Sep 17 00:00:00 2001 From: annacmc Date: Tue, 17 Dec 2024 20:58:47 +1100 Subject: [PATCH 19/28] fix up legend items display --- .../charts/src/components/bar-chart/bar-chart.tsx | 7 ++++++- .../pie-semi-circle-chart/pie-semi-circle-chart.tsx | 2 ++ .../js-packages/charts/src/components/shared/types.d.ts | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index 0697a41a7c496..40c6a11557fc3 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -67,6 +67,12 @@ const BarChart: FC< BarChartProps > = ( { hideTooltip(); }, [ hideTooltip ] ); + const legendItems = data.map( d => ( { + label: d.label, + value: d.value.toString(), + color: theme.colors[ 0 ], + } ) ); + return (
@@ -115,5 +121,4 @@ const BarChart: FC< BarChartProps > = ( { }; BarChart.displayName = 'BarChart'; - export default BarChart; 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 8376a6a6faa48..5545a82286f9b 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 @@ -42,6 +42,8 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { withTooltips = false, clockwise = true, thickness = 0.4, + showLegend = false, + legendOrientation = 'horizontal', } ) => { const providerTheme = useChartTheme(); const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = diff --git a/projects/js-packages/charts/src/components/shared/types.d.ts b/projects/js-packages/charts/src/components/shared/types.d.ts index 4b0836d7b4770..f21641b23b4f1 100644 --- a/projects/js-packages/charts/src/components/shared/types.d.ts +++ b/projects/js-packages/charts/src/components/shared/types.d.ts @@ -96,4 +96,12 @@ export type BaseChartProps< T = DataPoint | DataPointDate > = { * Whether to show tooltips on hover. False by default. */ withTooltips?: boolean; + /** + * Whether to show legend + */ + showLegend?: boolean; + /** + * Legend orientation + */ + legendOrientation?: 'horizontal' | 'vertical'; }; From 4e90189779d932ae2127bab026549e7d7c4c7aa5 Mon Sep 17 00:00:00 2001 From: annacmc Date: Tue, 17 Dec 2024 21:08:57 +1100 Subject: [PATCH 20/28] tidy up --- pnpm-lock.yaml | 17 ++ .../components/bar-chart/bar-chart.tsx.orig | 202 ----------------- .../pie-semi-circle-chart.tsx.orig | 203 ------------------ 3 files changed, 17 insertions(+), 405 deletions(-) delete mode 100644 projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx.orig delete mode 100644 projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx.orig diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2a2a658b2b2a..eba1d19846d96 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -304,6 +304,9 @@ importers: '@visx/group': specifier: ^3.12.0 version: 3.12.0(react@18.3.1) + '@visx/legend': + specifier: ^3.12.0 + version: 3.12.0(react@18.3.1) '@visx/responsive': specifier: 3.12.0 version: 3.12.0(react@18.3.1) @@ -7914,6 +7917,11 @@ packages: peerDependencies: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 + '@visx/legend@3.12.0': + resolution: {integrity: sha512-Tr6hdauEDXRXVNeNgIQ9JtCCrxn8Fbr8UCVlO9XsSxenk2hBC/2PIY5QPzpnKFEEEuH/C8vhj8T0JfFZV+D9zQ==} + peerDependencies: + react: ^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0 + '@visx/point@3.12.0': resolution: {integrity: sha512-I6UrHoJAEVbx3RORQNupgTiX5EzjuZpiwLPxn8L2mI5nfERotPKi1Yus12Cq2WtXqEBR/WgqTnoImlqOXBykcA==} @@ -18510,6 +18518,15 @@ snapshots: prop-types: 15.8.1 react: 18.3.1 + '@visx/legend@3.12.0(react@18.3.1)': + dependencies: + '@types/react': 18.3.13 + '@visx/group': 3.12.0(react@18.3.1) + '@visx/scale': 3.12.0 + classnames: 2.5.1 + prop-types: 15.8.1 + react: 18.3.1 + '@visx/point@3.12.0': {} '@visx/react-spring@3.12.0(@react-spring/web@9.7.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx.orig b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx.orig deleted file mode 100644 index 120e1e3981087..0000000000000 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx.orig +++ /dev/null @@ -1,202 +0,0 @@ -import { AxisLeft, AxisBottom } from '@visx/axis'; -import { localPoint } from '@visx/event'; -import { Group } from '@visx/group'; -import { scaleBand, scaleLinear } from '@visx/scale'; -import { Bar } from '@visx/shape'; -import { useTooltip } from '@visx/tooltip'; -import clsx from 'clsx'; -import { FC, useCallback, type MouseEvent } from 'react'; -import { useChartTheme } from '../../providers/theme'; -import { Legend } from '../legend'; -import { BaseTooltip } from '../tooltip'; -import styles from './bar-chart.module.scss'; -<<<<<<< HEAD -import type { LegendItem } from '../legend/types'; -import type { DataPoint } from '../shared/types'; -======= -import type { BaseChartProps, DataPoint } from '../shared/types'; ->>>>>>> trunk - -interface BarChartProps extends BaseChartProps { - /** - * Array of data points to display in the chart - */ - data: DataPoint[]; -<<<<<<< HEAD - /** - * 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 - */ - showTooltips?: boolean; - /** - * Whether to show legend - */ - showLegend?: boolean; - /** - * Legend orientation - */ - legendOrientation?: 'horizontal' | 'vertical'; -}; -======= -} ->>>>>>> trunk - -const BarChart: FC< BarChartProps > = ( { - data, - width, - height, - margin = { top: 20, right: 20, bottom: 40, left: 40 }, -<<<<<<< HEAD - showTooltips = false, - showLegend = false, - legendOrientation = 'horizontal', -======= - withTooltips = false, - className, ->>>>>>> trunk -} ) => { - const theme = useChartTheme(); - const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = - useTooltip< DataPoint >(); - - const margins = margin; - const xMax = width - margins.left - margins.right; - const yMax = height - margins.top - margins.bottom; - - // Create scales - const xScale = scaleBand< string >( { - range: [ 0, xMax ], - domain: data.map( d => d.label ), - padding: 0.2, - } ); - - const yScale = scaleLinear< number >( { - range: [ yMax, 0 ], - domain: [ 0, Math.max( ...data.map( d => d.value ) ) ], - } ); - - const handleMouseMove = useCallback( - ( event: MouseEvent< SVGRectElement >, datum: DataPoint ) => { - const coords = localPoint( event ); - if ( ! coords ) return; - - showTooltip( { - tooltipData: datum, - tooltipLeft: coords.x, - tooltipTop: coords.y - 10, - } ); - }, - [ showTooltip ] - ); - - const handleMouseLeave = useCallback( () => { - hideTooltip(); - }, [ hideTooltip ] ); - -<<<<<<< HEAD - const handleBarMouseMove = useCallback( - ( d: DataPoint ) => ( event: React.MouseEvent< SVGRectElement > ) => { - handleMouseMove( event, d ); - }, - [ handleMouseMove ] - ); - - // Create legend items from data and theme colors - const legendItems: LegendItem[] = data.map( item => ( { - label: item.label, - value: item.value.toString(), - color: theme.colors[ 0 ], - } ) ); - - return ( -
- - - { data.map( d => ( - - ) ) } - - { /* Axes */ } -======= - return ( -
- - - { data.map( d => { - const handleBarMouseMove = event => handleMouseMove( event, d ); - - return ( - - ); - } ) } ->>>>>>> trunk - - - - - - { withTooltips && tooltipOpen && tooltipData && ( - - ) } - - { showLegend && ( - - ) } -
- ); -}; - -BarChart.displayName = 'BarChart'; - -export default BarChart; diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx.orig b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx.orig deleted file mode 100644 index 89b6d610f2210..0000000000000 --- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx.orig +++ /dev/null @@ -1,203 +0,0 @@ -import { localPoint } from '@visx/event'; -import { Group } from '@visx/group'; -import Pie, { PieArcDatum } from '@visx/shape/lib/shapes/Pie'; -import { Text } from '@visx/text'; -import { useTooltip } from '@visx/tooltip'; -import clsx from 'clsx'; -import { FC, useCallback } from 'react'; -import { useChartTheme } from '../../providers/theme/theme-provider'; -import { Legend } from '../legend'; -import { BaseTooltip } from '../tooltip'; -import styles from './pie-semi-circle-chart.module.scss'; -import type { BaseChartProps, DataPointPercentage } from '../shared/types'; - -interface PieSemiCircleChartProps extends BaseChartProps< DataPointPercentage[] > { - /** - * Label text to display above the chart - */ - label: string; - /** - * Note text to display below the label - */ - note: string; - /** - * Direction of chart rendering - * true for clockwise, false for counter-clockwise - */ -<<<<<<< HEAD - showTooltips?: boolean; - /** - * Whether to show legend - */ - showLegend?: boolean; - /** - * Orientation of the legend - */ - legendOrientation?: 'horizontal' | 'vertical'; -======= - clockwise?: boolean; - /** - * Thickness of the pie chart. A value between 0 and 1 - */ - thickness?: number; ->>>>>>> trunk -} - -type ArcData = PieArcDatum< DataPointPercentage >; - -const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { - data, - width, - label, - note, -<<<<<<< HEAD - showTooltips = false, - showLegend = false, - legendOrientation = 'horizontal', -======= - className, - withTooltips = false, - clockwise = true, - thickness = 0.4, ->>>>>>> trunk -} ) => { - const providerTheme = useChartTheme(); - const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = - useTooltip< DataPointPercentage >(); - - const centerX = width / 2; - const height = width / 2; - const radius = width / 2; - const pad = 0.03; - const innerRadius = radius * ( 1 - thickness + pad ); - - // Map the data to include index for color assignment - const dataWithIndex = data.map( ( d, index ) => ( { - ...d, - index, - } ) ); - - // Set the clockwise direction based on the prop - const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2; - const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2; - - const accessors = { - value: ( d: DataPointPercentage & { index: number } ) => d.value, - sort: ( - a: DataPointPercentage & { index: number }, - b: DataPointPercentage & { index: number } - ) => b.value - a.value, - // Use the color property from the data object as a last resort. The theme provides colours by default. - fill: ( d: DataPointPercentage & { index: number } ) => - d.color || providerTheme.colors[ d.index % providerTheme.colors.length ], - }; - - const handleMouseMove = useCallback( - ( event: React.MouseEvent, arc: ArcData ) => { - const coords = localPoint( event ); - if ( ! coords ) return; - - showTooltip( { - tooltipData: arc.data, - tooltipLeft: coords.x, - tooltipTop: coords.y - 10, - } ); - }, - [ showTooltip ] - ); - - const handleMouseLeave = useCallback( () => { - hideTooltip(); - }, [ hideTooltip ] ); - - const handleArcMouseMove = useCallback( - ( arc: ArcData ) => ( event: React.MouseEvent ) => { - handleMouseMove( event, arc ); - }, - [ handleMouseMove ] - ); - - // Create legend items - const legendItems = data.map( ( item, index ) => ( { - label: item.label, - value: item.valueDisplay || item.value.toString(), - color: accessors.fill( { ...item, index } ), - } ) ); - - return ( -
- - { /* Main chart group that contains both the pie and text elements */ } - - { /* Pie chart */ } - - data={ dataWithIndex } - pieValue={ accessors.value } - outerRadius={ radius } - innerRadius={ innerRadius } - cornerRadius={ 3 } - padAngle={ pad } - startAngle={ startAngle } - endAngle={ endAngle } - pieSort={ accessors.sort } - > - { pie => { - return pie.arcs.map( arc => ( - - - - ) ); - } } - - - - - { label } - - - { note } - - - - - - { withTooltips && tooltipOpen && tooltipData && ( - - ) } - - { showLegend && ( - - ) } -
- ); -}; - -export default PieSemiCircleChart; From 65513e8ed7d8f4da6f9caa03a85f5c5117ecdee4 Mon Sep 17 00:00:00 2001 From: annacmc Date: Tue, 17 Dec 2024 21:38:08 +1100 Subject: [PATCH 21/28] remove redundant legend prop defaults from chart components --- .../js-packages/charts/src/components/bar-chart/bar-chart.tsx | 4 ++-- .../pie-semi-circle-chart/pie-semi-circle-chart.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index 40c6a11557fc3..d069aee89c48c 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -25,8 +25,8 @@ const BarChart: FC< BarChartProps > = ( { height, margin = { top: 20, right: 20, bottom: 40, left: 40 }, withTooltips = false, - showLegend = false, - legendOrientation = 'horizontal', + showLegend, + legendOrientation, className, } ) => { const theme = useChartTheme(); 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 5545a82286f9b..54b83de38f78b 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 @@ -42,8 +42,8 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { withTooltips = false, clockwise = true, thickness = 0.4, - showLegend = false, - legendOrientation = 'horizontal', + showLegend, + legendOrientation, } ) => { const providerTheme = useChartTheme(); const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = From a8dcc5abd8176137de1ec495539fa1d6e0011336 Mon Sep 17 00:00:00 2001 From: annacmc Date: Tue, 17 Dec 2024 22:30:51 +1100 Subject: [PATCH 22/28] fix up the data source for bar chart legend source --- .../src/components/bar-chart/bar-chart.tsx | 22 +++++++++++++------ .../bar-chart/stories/index.stories.tsx | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index d069aee89c48c..a075c939c8b5e 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -17,6 +17,10 @@ interface BarChartProps extends BaseChartProps { * Array of data points to display in the chart */ data: DataPoint[]; + /** + * Label for the data series + */ + seriesLabel?: string; } const BarChart: FC< BarChartProps > = ( { @@ -25,9 +29,10 @@ const BarChart: FC< BarChartProps > = ( { height, margin = { top: 20, right: 20, bottom: 40, left: 40 }, withTooltips = false, - showLegend, - legendOrientation, + showLegend = false, + legendOrientation = 'horizontal', className, + seriesLabel, } ) => { const theme = useChartTheme(); const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = @@ -67,11 +72,14 @@ const BarChart: FC< BarChartProps > = ( { hideTooltip(); }, [ hideTooltip ] ); - const legendItems = data.map( d => ( { - label: d.label, - value: d.value.toString(), - color: theme.colors[ 0 ], - } ) ); + // Create a single legend item + const legendItems = [ + { + label: seriesLabel, + value: '', // Empty string since we don't want to show a specific value + color: theme.colors[ 0 ], + }, + ]; return (
diff --git a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx index 6cbe77894dc85..cfe8730620e9f 100644 --- a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx @@ -26,6 +26,7 @@ Default.args = { margin: { top: 20, right: 20, bottom: 40, left: 40 }, withTooltips: false, data: data[ 0 ].data, + seriesLabel: data[ 0 ].group, }; export const WithTooltips = Template.bind( {} ); @@ -48,6 +49,7 @@ export const WithLegend = { height: 350, margin: { top: 20, right: 20, bottom: 40, left: 40 }, data: data[ 0 ].data, + seriesLabel: data[ 0 ].group, showTooltips: true, showLegend: true, legendOrientation: 'horizontal', From 487f5590b3f581ba2c4b1a0569cc5782e8e6e298 Mon Sep 17 00:00:00 2001 From: annacmc Date: Tue, 17 Dec 2024 22:42:07 +1100 Subject: [PATCH 23/28] add legend to line chart --- .../src/components/line-chart/line-chart.tsx | 18 ++++++++++++++++ .../line-chart/stories/index.stories.tsx | 21 +++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/projects/js-packages/charts/src/components/line-chart/line-chart.tsx b/projects/js-packages/charts/src/components/line-chart/line-chart.tsx index 155f2adee032a..e0a1726e05c49 100644 --- a/projects/js-packages/charts/src/components/line-chart/line-chart.tsx +++ b/projects/js-packages/charts/src/components/line-chart/line-chart.tsx @@ -9,6 +9,7 @@ import { import clsx from 'clsx'; import { FC } from 'react'; import { useChartTheme } from '../../providers/theme/theme-provider'; +import { Legend } from '../legend'; import styles from './line-chart.module.scss'; import type { BaseChartProps, DataPointDate, SeriesData } from '../shared/types'; @@ -77,6 +78,8 @@ const LineChart: FC< LineChartProps > = ( { margin = { top: 20, right: 20, bottom: 40, left: 40 }, className, withTooltips = true, + showLegend = false, + legendOrientation = 'horizontal', } ) => { const providerTheme = useChartTheme(); @@ -86,6 +89,13 @@ const LineChart: FC< LineChartProps > = ( { ); } + // Create legend items from series data + const legendItems = data.map( ( series, index ) => ( { + label: series.label, + value: '', // Empty string since we don't want to show a specific value + color: providerTheme.colors[ index % providerTheme.colors.length ], + } ) ); + const accessors = { xAccessor: ( d: DataPointDate ) => d.date, yAccessor: ( d: DataPointDate ) => d.value, @@ -134,6 +144,14 @@ const LineChart: FC< LineChartProps > = ( { /> ) } + + { showLegend && ( + + ) }
); }; 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 b09bc9594c4fd..ffa39a583bad9 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 @@ -40,10 +40,7 @@ SingleSeries.args = { // 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, + ...Default.args, withTooltips: false, }; @@ -55,3 +52,19 @@ CustomDimensions.args = { margin: { top: 20, right: 20, bottom: 30, left: 40 }, data: sampleData, }; + +// Story with horizontal legend +export const WithLegend = Template.bind( {} ); +WithLegend.args = { + ...Default.args, + showLegend: true, + legendOrientation: 'horizontal', +}; + +// Story with vertical legend +export const WithVerticalLegend = Template.bind( {} ); +WithVerticalLegend.args = { + ...Default.args, + showLegend: true, + legendOrientation: 'vertical', +}; From 3a74ec4974f769acf5477a4f1618b99a0ef397bb Mon Sep 17 00:00:00 2001 From: annacmc Date: Tue, 17 Dec 2024 23:19:17 +1100 Subject: [PATCH 24/28] add legend to pie chart --- .../src/components/pie-chart/pie-chart.tsx | 19 +++++++++++++++++++ .../pie-chart/stories/index.stories.tsx | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) 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 764910bfa82f7..74fdcefe4711e 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 @@ -4,6 +4,7 @@ import clsx from 'clsx'; import { SVGProps } from 'react'; import useChartMouseHandler from '../../hooks/use-chart-mouse-handler'; import { useChartTheme, defaultTheme } from '../../providers/theme'; +import { Legend } from '../legend'; import { BaseTooltip } from '../tooltip'; import styles from './pie-chart.module.scss'; import type { BaseChartProps, DataPoint } from '../shared/types'; @@ -30,6 +31,8 @@ const PieChart = ( { withTooltips = false, innerRadius = 0, className, + showLegend, + legendOrientation, }: PieChartProps ) => { const providerTheme = useChartTheme(); const { onMouseMove, onMouseLeave, tooltipOpen, tooltipData, tooltipLeft, tooltipTop } = @@ -48,6 +51,13 @@ const PieChart = ( { fill: d => d.color || providerTheme.colors[ d.index ], }; + // Create legend items from data + const legendItems = data.map( ( item, index ) => ( { + label: item.label, + value: item.value.toString(), + color: providerTheme.colors[ index % providerTheme.colors.length ], + } ) ); + return (
@@ -99,6 +109,15 @@ const PieChart = ( { + + { showLegend && ( + + ) } + { withTooltips && tooltipOpen && tooltipData && ( Date: Wed, 18 Dec 2024 10:32:09 +1100 Subject: [PATCH 25/28] update naming and comments for line chart legend generation --- .../charts/src/components/line-chart/line-chart.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/js-packages/charts/src/components/line-chart/line-chart.tsx b/projects/js-packages/charts/src/components/line-chart/line-chart.tsx index e0a1726e05c49..0b1f19acca72f 100644 --- a/projects/js-packages/charts/src/components/line-chart/line-chart.tsx +++ b/projects/js-packages/charts/src/components/line-chart/line-chart.tsx @@ -89,9 +89,9 @@ const LineChart: FC< LineChartProps > = ( { ); } - // Create legend items from series data - const legendItems = data.map( ( series, index ) => ( { - label: series.label, + // Create legend items from group labels, this iterates over groups rather than data points + const legendItems = data.map( ( group, index ) => ( { + label: group.label, // Label for each unique group value: '', // Empty string since we don't want to show a specific value color: providerTheme.colors[ index % providerTheme.colors.length ], } ) ); From 7ae5ff09a9e7f0002a9edb233734d8ab75412af8 Mon Sep 17 00:00:00 2001 From: annacmc Date: Wed, 18 Dec 2024 10:36:39 +1100 Subject: [PATCH 26/28] add a fallback in case --jp is not available --- .../js-packages/charts/src/components/bar-chart/bar-chart.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx index a075c939c8b5e..5c1b03a1d3d98 100644 --- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -72,7 +72,6 @@ const BarChart: FC< BarChartProps > = ( { hideTooltip(); }, [ hideTooltip ] ); - // Create a single legend item const legendItems = [ { label: seriesLabel, From 8fb265daa7007979aa0d1c4389a49065dfd730eb Mon Sep 17 00:00:00 2001 From: annacmc Date: Wed, 18 Dec 2024 11:07:28 +1100 Subject: [PATCH 27/28] add legend = false value to all chart default stories --- .../charts/src/components/bar-chart/stories/index.stories.tsx | 1 + .../charts/src/components/line-chart/stories/index.stories.tsx | 3 +-- .../charts/src/components/pie-chart/stories/index.stories.tsx | 1 + .../components/pie-semi-circle-chart/stories/index.stories.tsx | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx index cfe8730620e9f..4959d277fea84 100644 --- a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx @@ -27,6 +27,7 @@ Default.args = { withTooltips: false, data: data[ 0 ].data, seriesLabel: data[ 0 ].group, + showLegend: false, }; export const WithTooltips = Template.bind( {} ); 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 ffa39a583bad9..aa909fc534a47 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 @@ -26,6 +26,7 @@ Default.args = { height: 300, margin: { top: 20, right: 20, bottom: 30, left: 40 }, data: sampleData, + showLegend: false, }; // Story with single data series @@ -57,8 +58,6 @@ CustomDimensions.args = { export const WithLegend = Template.bind( {} ); WithLegend.args = { ...Default.args, - showLegend: true, - legendOrientation: 'horizontal', }; // Story with vertical legend 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 index 688b6d499c2c0..036dd326f169f 100644 --- 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 @@ -47,6 +47,7 @@ export const Default: StoryType = { data, theme: 'default', innerRadius: 0, + showLegend: false, }, }; diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx index 5da889e3ffe23..b59d9e28ab693 100644 --- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx @@ -65,6 +65,7 @@ Default.args = { note: 'Windows +10%', thickness: 0.4, clockwise: true, + showLegend: false, }; export const WithTooltips = Template.bind( {} ); From ff2a881c2c6206713336744d9fba549be4a83eca Mon Sep 17 00:00:00 2001 From: annacmc Date: Wed, 18 Dec 2024 11:11:36 +1100 Subject: [PATCH 28/28] add legendOrientation to default args in storybook --- .../charts/src/components/bar-chart/stories/index.stories.tsx | 1 + .../js-packages/charts/src/components/legend/legend.module.scss | 2 +- .../charts/src/components/line-chart/stories/index.stories.tsx | 1 + .../charts/src/components/pie-chart/stories/index.stories.tsx | 1 + .../components/pie-semi-circle-chart/stories/index.stories.tsx | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx index 4959d277fea84..5712257d6d35e 100644 --- a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx @@ -28,6 +28,7 @@ Default.args = { data: data[ 0 ].data, seriesLabel: data[ 0 ].group, showLegend: false, + legendOrientation: 'horizontal', }; export const WithTooltips = Template.bind( {} ); diff --git a/projects/js-packages/charts/src/components/legend/legend.module.scss b/projects/js-packages/charts/src/components/legend/legend.module.scss index e6b654d5896d5..4158534e0b2dc 100644 --- a/projects/js-packages/charts/src/components/legend/legend.module.scss +++ b/projects/js-packages/charts/src/components/legend/legend.module.scss @@ -25,7 +25,7 @@ } .legend-item-label { - color: var(--jp-gray-80); + color: var(--jp-gray-80, #2c3338); display: flex; align-items: center; gap: 0.5rem; 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 aa909fc534a47..8dcd69849cac8 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 @@ -27,6 +27,7 @@ Default.args = { margin: { top: 20, right: 20, bottom: 30, left: 40 }, data: sampleData, showLegend: false, + legendOrientation: 'horizontal', }; // Story with single data series 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 index 036dd326f169f..2276a61b39c35 100644 --- 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 @@ -48,6 +48,7 @@ export const Default: StoryType = { theme: 'default', innerRadius: 0, showLegend: false, + legendOrientation: 'horizontal', }, }; diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx index b59d9e28ab693..6878a91700544 100644 --- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx @@ -66,6 +66,7 @@ Default.args = { thickness: 0.4, clockwise: true, showLegend: false, + legendOrientation: 'horizontal', }; export const WithTooltips = Template.bind( {} );