Skip to content

Commit f8f069a

Browse files
authored
feat(ColumnChartWithTrend): initial component implementation (#1824)
1 parent 556f537 commit f8f069a

File tree

19 files changed

+2429
-40
lines changed

19 files changed

+2429
-40
lines changed

packages/charts/src/components/BarChart/BarChart.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ const BarChart: FC<BarChartProps> = forwardRef((props: BarChartProps, ref: Ref<H
128128
style,
129129
className,
130130
tooltip,
131-
slot
131+
slot,
132+
syncId,
133+
ChartPlaceholder
132134
} = props;
133135

134136
const chartConfig = useMemo(() => {
@@ -198,7 +200,7 @@ const BarChart: FC<BarChartProps> = forwardRef((props: BarChartProps, ref: Ref<H
198200
<ChartContainer
199201
dataset={dataset}
200202
loading={loading}
201-
Placeholder={BarChartPlaceholder}
203+
Placeholder={ChartPlaceholder ?? BarChartPlaceholder}
202204
ref={chartRef}
203205
style={style}
204206
className={className}
@@ -208,6 +210,7 @@ const BarChart: FC<BarChartProps> = forwardRef((props: BarChartProps, ref: Ref<H
208210
{...passThroughProps}
209211
>
210212
<BarChartLib
213+
syncId={syncId}
211214
onClick={onClickInternal}
212215
stackOffset="sign"
213216
margin={marginChart}

packages/charts/src/components/ColumnChart/ColumnChart.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ const ColumnChart: FC<ColumnChartProps> = forwardRef((props: ColumnChartProps, r
126126
style,
127127
className,
128128
tooltip,
129-
slot
129+
slot,
130+
ChartPlaceholder,
131+
syncId
130132
} = props;
131133

132134
const chartConfig = useMemo(() => {
@@ -203,7 +205,7 @@ const ColumnChart: FC<ColumnChartProps> = forwardRef((props: ColumnChartProps, r
203205
<ChartContainer
204206
dataset={dataset}
205207
loading={loading}
206-
Placeholder={ColumnChartPlaceholder}
208+
Placeholder={ChartPlaceholder ?? ColumnChartPlaceholder}
207209
ref={chartRef}
208210
style={style}
209211
className={className}
@@ -213,6 +215,7 @@ const ColumnChart: FC<ColumnChartProps> = forwardRef((props: ColumnChartProps, r
213215
{...passThroughProps}
214216
>
215217
<ColumnChartLib
218+
syncId={syncId}
216219
onClick={onClickInternal}
217220
stackOffset="sign"
218221
margin={marginChart}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks';
2+
import { DocsHeader } from '@shared/stories/DocsHeader';
3+
import '@ui5/webcomponents-icons/dist/person-placeholder.js';
4+
import { ColumnChartWithTrend } from '@ui5/webcomponents-react-charts/dist/ColumnChartWithTrend';
5+
import { complexDataSet } from '../../resources/DemoProps';
6+
7+
<Meta
8+
title="Charts / ColumnChart with Trend"
9+
component={ColumnChartWithTrend}
10+
args={{
11+
dataset: complexDataSet,
12+
style: { height: '60vh' },
13+
dimensions: [
14+
{
15+
accessor: 'name',
16+
formatter: (d) => `${d} 2019`
17+
}
18+
],
19+
measures: [
20+
{
21+
accessor: 'users',
22+
label: 'Users',
23+
formatter: (val) => val.toLocaleString(),
24+
type: 'line'
25+
},
26+
{
27+
accessor: 'sessions',
28+
label: 'Active Sessions',
29+
type: 'column'
30+
}
31+
]
32+
}}
33+
argTypes={{
34+
dataset: {
35+
control: { disable: true }
36+
},
37+
children: {
38+
control: { disable: true }
39+
}
40+
}}
41+
/>
42+
43+
<DocsHeader />
44+
45+
## Example
46+
47+
<Canvas>
48+
<Story name="Default">{(props) => <ColumnChartWithTrend {...props} />}</Story>
49+
</Canvas>
50+
51+
### Loading Placeholder
52+
53+
<Canvas>
54+
<Story
55+
name="Loading Placeholder"
56+
args={{
57+
dataset: [],
58+
dimensions: [
59+
{
60+
accessor: 'name',
61+
formatter: (d) => `${d} 2019`,
62+
interval: 0
63+
}
64+
],
65+
measures: []
66+
}}
67+
>
68+
{(props) => <ColumnChartWithTrend {...props} />}
69+
</Story>
70+
</Canvas>
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { fireEvent, render, screen } from '@shared/tests';
2+
import * as React from 'react';
3+
import { complexDataSet } from '../../resources/DemoProps';
4+
import { ColumnChartWithTrend } from './ColumnChartWithTrend';
5+
import { createPassThroughPropsTest } from '@shared/tests/utils';
6+
7+
const dimensions = [
8+
{
9+
accessor: 'name',
10+
formatter: (d) => `${d} 2019`,
11+
interval: 0
12+
}
13+
];
14+
15+
const measures = [
16+
{
17+
accessor: 'users',
18+
label: 'Users',
19+
formatter: (val) => val.toLocaleString(),
20+
type: 'line'
21+
},
22+
{
23+
accessor: 'sessions',
24+
label: 'Active Sessions',
25+
type: 'column'
26+
}
27+
];
28+
29+
describe('ColumnChart', () => {
30+
it('Renders with data', async () => {
31+
const { container, asFragment } = render(
32+
<ColumnChartWithTrend dataset={complexDataSet} dimensions={dimensions} measures={measures} />
33+
);
34+
35+
// Check if two responsive containers are rendered
36+
const responsiveContainers = container.querySelectorAll('div.recharts-responsive-container');
37+
expect(responsiveContainers.length).toBe(2);
38+
39+
// Check if trend line container, trend line and the path of the line is rendered correctly
40+
const trendLineChartContainer = container.querySelector('g.recharts-line');
41+
expect(trendLineChartContainer).toBeInTheDocument();
42+
const trendLine = trendLineChartContainer.querySelector('path');
43+
expect(trendLine).not.toBeNull();
44+
expect(trendLine.getAttribute('d')[0]).toBe('M');
45+
46+
// Check if column chart container, bars and single bars are rendered
47+
const columnChartContainer = container.querySelector('g.recharts-bar');
48+
expect(columnChartContainer).toBeInTheDocument();
49+
const barContainer = columnChartContainer.querySelectorAll('g.recharts-bar-rectangles');
50+
expect(barContainer.length).toBeGreaterThanOrEqual(1);
51+
const singleBars = columnChartContainer.querySelectorAll('g.recharts-bar-rectangle');
52+
expect(singleBars.length).toBeGreaterThanOrEqual(1);
53+
54+
// Check if snapshot matches render
55+
expect(asFragment()).toMatchSnapshot();
56+
});
57+
58+
it('Check onClick events', async () => {
59+
const onClick = jest.fn();
60+
const onLegendClick = jest.fn();
61+
const { container, asFragment } = render(
62+
<ColumnChartWithTrend
63+
onLegendClick={onLegendClick}
64+
onClick={onClick}
65+
dataset={complexDataSet}
66+
dimensions={dimensions}
67+
measures={measures}
68+
/>
69+
);
70+
71+
// Check if click on axis label is working
72+
const firstXAxisLabel = screen.getByText(/January 2.../);
73+
fireEvent.click(firstXAxisLabel);
74+
expect(onClick).toBeCalled();
75+
76+
// Check if click on legend is working
77+
const legendContainer = screen.getByText(/Active Sessions/);
78+
fireEvent.click(legendContainer);
79+
expect(onLegendClick).toBeCalled();
80+
81+
// Check if click in column chart container is working
82+
fireEvent.click(container.querySelector('g.recharts-bar'));
83+
expect(onClick).toBeCalled();
84+
85+
// Check if click in trend line container is working
86+
fireEvent.click(container.querySelector('g.recharts-line'));
87+
expect(onClick).toBeCalled();
88+
89+
// Check if snapshot matches render
90+
expect(asFragment()).toMatchSnapshot();
91+
});
92+
93+
it('Loading placeholder', () => {
94+
const { container, asFragment } = render(<ColumnChartWithTrend dimensions={[]} measures={[]} />);
95+
96+
// Check if no responsive container is rendered
97+
const responsiveContainers = container.querySelectorAll('div.recharts-responsive-container');
98+
expect(responsiveContainers.length).toBe(0);
99+
100+
// Check if no trend line container is rendered
101+
const trendLineContainer = container.querySelector('g.recharts-line');
102+
expect(trendLineContainer).toBeNull();
103+
104+
// Check if no column chart container is rendered
105+
const columnChartContainer = container.querySelector('g.recharts-bar');
106+
expect(columnChartContainer).toBeNull();
107+
108+
// Check if snapshot matches render
109+
expect(asFragment()).toMatchSnapshot();
110+
});
111+
112+
it('onLegendClick should not crash when invalid handler is provided', () => {
113+
render(
114+
<ColumnChartWithTrend
115+
dataset={complexDataSet}
116+
dimensions={dimensions}
117+
measures={measures}
118+
onLegendClick={'123' as any}
119+
/>
120+
);
121+
122+
expect(() => {
123+
fireEvent.click(screen.getByText(/Active Sessions/));
124+
}).not.toThrow();
125+
});
126+
127+
createPassThroughPropsTest(ColumnChartWithTrend, { dimensions: [], measures: [] });
128+
});

0 commit comments

Comments
 (0)