Skip to content

Commit 4e33906

Browse files
authored
feat: add legend grouping (#292)
1 parent 24eaa67 commit 4e33906

39 files changed

+220
-88
lines changed
5.88 KB
Loading
6.79 KB
Loading
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type {Meta, StoryObj} from '@storybook/react-webpack5';
2+
3+
import {ChartStory} from '../../ChartStory';
4+
import {groupedLegend} from '../../__data__';
5+
6+
const meta: Meta<typeof ChartStory> = {
7+
title: 'Other/Legend',
8+
component: ChartStory,
9+
};
10+
11+
export default meta;
12+
13+
type Story = StoryObj<typeof ChartStory>;
14+
15+
export const SharedLegend = {
16+
name: 'Shared legend',
17+
args: {
18+
data: groupedLegend,
19+
},
20+
} satisfies Story;

src/__stories__/Other/LegendPosition.stories.tsx renamed to src/__stories__/Other/Legend/LegendPosition.stories.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ import React from 'react';
22

33
import type {Meta} from '@storybook/react-webpack5';
44

5-
import {ChartStory} from '../ChartStory';
6-
import {lineBasicData} from '../__data__';
5+
import {ChartStory} from '../../ChartStory';
6+
import {lineBasicData} from '../../__data__';
77

88
const meta: Meta<typeof ChartStory> = {
9-
title: 'Other',
9+
title: 'Other/Legend',
1010
component: ChartStory,
1111
};
1212

1313
export default meta;
1414

1515
export const LegendPosition = {
16-
name: 'Legend Position',
16+
name: 'Position',
1717
args: {
1818
position: 'bottom',
1919
},

src/__stories__/__data__/other/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './crosshair';
33
export * from './line-and-bar';
44
export * from './lines';
55
export * from './tooltip';
6+
export * from './legend';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type {ChartData} from '../../../../types';
2+
3+
export const groupedLegend: ChartData = {
4+
xAxis: {maxPadding: 0},
5+
yAxis: [{maxPadding: 0}],
6+
chart: {margin: {top: 10, bottom: 10, right: 10, left: 10}},
7+
series: {
8+
data: [
9+
{
10+
type: 'scatter',
11+
name: 'Series 1.1',
12+
data: [{x: 1.1, y: 1.1}],
13+
legend: {groupId: 's1', itemText: 'Series 1'},
14+
},
15+
{
16+
type: 'scatter',
17+
name: 'Series 1.2',
18+
data: [{x: 1.2, y: 1.2}],
19+
legend: {groupId: 's1'},
20+
},
21+
{type: 'scatter', name: 'Series 2', data: [{x: 2, y: 2}]},
22+
{type: 'scatter', name: 'Series 3', data: [{x: 3, y: 3}]},
23+
],
24+
},
25+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './grouping';

src/__tests__/legend.visual.test.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import range from 'lodash/range';
66
import set from 'lodash/set';
77

88
import {ChartTestStory} from '../../playwright/components/ChartTestStory';
9-
import {pieHtmlLegendData} from '../__stories__/__data__';
9+
import {groupedLegend, pieHtmlLegendData} from '../__stories__/__data__';
1010
import type {ChartData} from '../types';
1111

1212
const pieOverflowedLegendItemsData: ChartData = {
@@ -163,5 +163,15 @@ test.describe('Legend', () => {
163163
await expect(component.locator('svg')).toHaveScreenshot();
164164
});
165165
});
166+
167+
test('Grouped legend items', async ({mount}) => {
168+
const component = await mount(<ChartTestStory data={groupedLegend} />);
169+
170+
await expect(component.locator('svg')).toHaveScreenshot();
171+
172+
const legendItem = component.locator('.gcharts-legend__item text').first();
173+
await legendItem.click();
174+
await expect(component.locator('svg')).toHaveScreenshot();
175+
});
166176
});
167177
});

src/components/Legend/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export const Legend = (props: Props) => {
254254
.append('g')
255255
.attr('class', b('item'))
256256
.on('click', function (e, d) {
257-
onItemClick({name: d.name, metaKey: e.metaKey});
257+
onItemClick({id: d.id, name: d.name, metaKey: e.metaKey});
258258
onUpdate?.();
259259
});
260260

@@ -298,7 +298,7 @@ export const Legend = (props: Props) => {
298298
return '0px';
299299
})
300300
.on('click', function (e, d) {
301-
onItemClick({name: d.name, metaKey: e.metaKey});
301+
onItemClick({id: d.id, name: d.name, metaKey: e.metaKey});
302302
onUpdate?.();
303303
})
304304
[legend.html ? 'html' : 'text'](function (d) {

src/hooks/useSeries/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const useVisibleSeries = ({
3232
if (singleSeries.legend.enabled) {
3333
return {
3434
...singleSeries,
35-
visible: activeLegendItems.includes(singleSeries.name),
35+
visible: activeLegendItems.includes(singleSeries.legend.groupId),
3636
};
3737
}
3838

@@ -124,22 +124,22 @@ export const useSeries = (args: Args) => {
124124
const chartSeries = useVisibleSeries({preparedSeries, activeLegendItems});
125125

126126
const handleLegendItemClick: OnLegendItemClick = React.useCallback(
127-
({name, metaKey}) => {
127+
({id, metaKey}) => {
128128
const allItems = getAllLegendItems(preparedSeries);
129129
const onlyItemSelected =
130-
activeLegendItems.length === 1 && activeLegendItems.includes(name);
130+
activeLegendItems.length === 1 && activeLegendItems.includes(id);
131131
let nextActiveLegendItems: string[];
132132

133-
if (metaKey && activeLegendItems.includes(name)) {
134-
nextActiveLegendItems = activeLegendItems.filter((item) => item !== name);
135-
} else if (metaKey && !activeLegendItems.includes(name)) {
136-
nextActiveLegendItems = activeLegendItems.concat(name);
133+
if (metaKey && activeLegendItems.includes(id)) {
134+
nextActiveLegendItems = activeLegendItems.filter((item) => item !== id);
135+
} else if (metaKey && !activeLegendItems.includes(id)) {
136+
nextActiveLegendItems = activeLegendItems.concat(id);
137137
} else if (onlyItemSelected && allItems.length === 1) {
138138
nextActiveLegendItems = [];
139139
} else if (onlyItemSelected) {
140140
nextActiveLegendItems = allItems;
141141
} else {
142-
nextActiveLegendItems = [name];
142+
nextActiveLegendItems = [id];
143143
}
144144

145145
setActiveLegendItems(nextActiveLegendItems);

0 commit comments

Comments
 (0)