Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions docs/data/charts/bars/BarLabel.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { BarChart } from '@mui/x-charts/BarChart';

const dollarFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 0,
});

export default function BarLabel() {
return (
<BarChart
xAxis={[{ data: ['group A', 'group B', 'group C'] }]}
series={[{ data: [4, 3, 5] }, { data: [1, 6, 3] }, { data: [2, 5, 6] }]}
series={[
{ data: [4, 3, 5], barLabel: 'value' },
{
data: [1, 6, 3],
barLabel: (item) => dollarFormatter.format(item.value),
},
{ data: [2, 5, 6] },
]}
height={300}
barLabel="value"
margin={{ left: 0 }}
yAxis={[{ width: 30 }]}
/>
Expand Down
16 changes: 14 additions & 2 deletions docs/data/charts/bars/BarLabel.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { BarChart } from '@mui/x-charts/BarChart';

const dollarFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 0,
});

export default function BarLabel() {
return (
<BarChart
xAxis={[{ data: ['group A', 'group B', 'group C'] }]}
series={[{ data: [4, 3, 5] }, { data: [1, 6, 3] }, { data: [2, 5, 6] }]}
series={[
{ data: [4, 3, 5], barLabel: 'value' },
{
data: [1, 6, 3],
barLabel: (item) => dollarFormatter.format(item.value!),
},
{ data: [2, 5, 6] },
]}
height={300}
barLabel="value"
margin={{ left: 0 }}
yAxis={[{ width: 30 }]}
/>
Expand Down
10 changes: 8 additions & 2 deletions docs/data/charts/bars/BarLabel.tsx.preview
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<BarChart
xAxis={[{ data: ['group A', 'group B', 'group C'] }]}
series={[{ data: [4, 3, 5] }, { data: [1, 6, 3] }, { data: [2, 5, 6] }]}
series={[
{ data: [4, 3, 5], barLabel: 'value' },
{
data: [1, 6, 3],
barLabel: (item) => dollarFormatter.format(item.value!),
},
{ data: [2, 5, 6] },
]}
height={300}
barLabel="value"
margin={{ left: 0 }}
yAxis={[{ width: 30 }]}
/>
10 changes: 6 additions & 4 deletions docs/data/charts/bars/bars.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,12 @@

## Labels

You can display labels on the bars.
To do so, the `BarChart` or `BarPlot` accepts a `barLabel` prop.
It can either get a function that gets the bar item and some context.
Or you can pass `'value'` to display the raw value of the bar.
You can display labels on the bars. This can be useful to show the value of each bar directly on the chart.

If you provide `'value'` to the `barLabel` property of a bar series, the value of that bar is shown.
Alternatively, the `barLabel` property accepts a function that is called with the bar item and context about the bar.

In the example below, the value of the first series is displayed using the default formatter, and format the value of the second series as US dollars. The labels of the third series are hidden.

Check warning on line 178 in docs/data/charts/bars/bars.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.We] Try to avoid using first-person plural like 'US'. Raw Output: {"message": "[Google.We] Try to avoid using first-person plural like 'US'.", "location": {"path": "docs/data/charts/bars/bars.md", "range": {"start": {"line": 178, "column": 140}}}, "severity": "WARNING"}

{{"demo": "BarLabel.js"}}

Expand Down
1 change: 0 additions & 1 deletion docs/pages/x/api/charts/bar-chart-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"text": "highlighting docs"
}
},
"barLabel": { "type": { "name": "union", "description": "'value'<br>&#124;&nbsp;func" } },
"borderRadius": { "type": { "name": "number" } },
"brushConfig": {
"type": {
Expand Down
1 change: 0 additions & 1 deletion docs/pages/x/api/charts/bar-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"text": "highlighting docs"
}
},
"barLabel": { "type": { "name": "union", "description": "'value'<br>&#124;&nbsp;func" } },
"borderRadius": { "type": { "name": "number" } },
"brushConfig": {
"type": {
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/x/api/charts/bar-plot.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
}
],
"classes": [],
"spread": true,
"themeDefaultProps": null,
"muiName": "MuiBarPlot",
"filename": "/packages/x-charts/src/BarChart/BarPlot.tsx",
"inheritance": null,
Expand Down
5 changes: 5 additions & 0 deletions docs/pages/x/api/charts/bar-series.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
],
"properties": {
"type": { "type": { "description": "'bar'" }, "required": true },
"barLabel": {
"type": {
"description": "'value' | ((item: BarItem, context: BarLabelContext) =&gt; string | null | undefined)"
}
},
"color": { "type": { "description": "string" } },
"colorGetter": {
"type": { "description": "(data: ColorCallbackValue&lt;TValue&gt;) =&gt; string" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
"description": "The configuration of axes highlight. Default is set to &#39;band&#39; in the bar direction. Depends on <code>layout</code> prop.",
"seeMoreText": "See {{link}} for more details."
},
"barLabel": {
"description": "If provided, the function will be used to format the label of the bar. It can be set to &#39;value&#39; to display the current value."
},
"borderRadius": { "description": "Defines the border radius of the bar element." },
"brushConfig": { "description": "Configuration for the brush interaction." },
"colors": { "description": "Color palette used to colorize multiple series." },
Expand Down
3 changes: 0 additions & 3 deletions docs/translations/api-docs/charts/bar-chart/bar-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
"description": "The configuration of axes highlight. Default is set to &#39;band&#39; in the bar direction. Depends on <code>layout</code> prop.",
"seeMoreText": "See {{link}} for more details."
},
"barLabel": {
"description": "If provided, the function will be used to format the label of the bar. It can be set to &#39;value&#39; to display the current value."
},
"borderRadius": { "description": "Defines the border radius of the bar element." },
"brushConfig": { "description": "Configuration for the brush interaction." },
"colors": { "description": "Color palette used to colorize multiple series." },
Expand Down
3 changes: 3 additions & 0 deletions docs/translations/api-docs/charts/bar-series.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"interfaceDescription": "",
"propertiesDescriptions": {
"type": { "description": "" },
"barLabel": {
"description": "If provided, the function will be used to format the label of the bar.<br />It can be set to &#39;value&#39; to display the current value."
},
"color": {
"description": "Color to use when displaying the series.<br />If <code>colorGetter</code> is provided, it will be used to get the color for each data point instead.<br />Otherwise, this color will be used for all data points in the series."
},
Expand Down
1 change: 1 addition & 0 deletions packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ BarChartPro.propTypes = {
y: PropTypes.oneOf(['band', 'line', 'none']),
}),
/**
* @deprecated Use `barLabel` in the chart series instead.
* If provided, the function will be used to format the label of the bar.
* It can be set to 'value' to display the current value.
* @param {BarItem} item The item to format.
Expand Down
31 changes: 31 additions & 0 deletions packages/x-charts/src/BarChart/BarChart.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,37 @@ describe('<BarChart />', () => {
expect(screen.getByText('No data to display')).toBeVisible();
});

it('prioritizes `barLabel` from series over `barLabel` prop', () => {
render(
<BarChart
barLabel={() => 'Bar label from prop'}
series={[{ data: [1], barLabel: () => 'Bar label from series' }]}
width={100}
height={100}
xAxis={[{ data: ['A'] }]}
yAxis={[]}
/>,
);

expect(screen.getByText('Bar label from series')).toBeVisible();
});

it("defaults to `barLabel` prop when `barLabel` from series isn't defined", () => {
render(
<BarChart
barLabel={() => 'Bar label from prop'}
series={[{ data: [1] }, { data: [1], barLabel: () => 'Bar label from 2nd series' }]}
width={100}
height={100}
xAxis={[{ data: ['A'] }]}
yAxis={[]}
/>,
);

expect(screen.getByText('Bar label from prop')).toBeVisible();
expect(screen.getByText('Bar label from 2nd series')).toBeVisible();
});

const wrapper = ({ children }: { children?: React.ReactNode }) => (
<div style={{ width: 400, height: 400 }}>{children}</div>
);
Expand Down
1 change: 1 addition & 0 deletions packages/x-charts/src/BarChart/BarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ BarChart.propTypes = {
y: PropTypes.oneOf(['band', 'line', 'none']),
}),
/**
* @deprecated Use `barLabel` in the chart series instead.
* If provided, the function will be used to format the label of the bar.
* It can be set to 'value' to display the current value.
* @param {BarItem} item The item to format.
Expand Down
56 changes: 29 additions & 27 deletions packages/x-charts/src/BarChart/BarLabel/BarLabelPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BarLabelItem, BarLabelItemProps } from './BarLabelItem';
import { useUtilityClasses } from '../barClasses';

type BarLabelPlotProps = {
bars: ProcessedBarSeriesData[];
processedSeries: ProcessedBarSeriesData;
skipAnimation?: boolean;
barLabel?: BarLabelItemProps['barLabel'];
};
Expand All @@ -13,36 +13,38 @@ type BarLabelPlotProps = {
* @ignore - internal component.
*/
function BarLabelPlot(props: BarLabelPlotProps) {
const { bars, skipAnimation, ...other } = props;
const { processedSeries, skipAnimation, ...other } = props;
const { seriesId, data } = processedSeries;
const classes = useUtilityClasses();

const barLabel = processedSeries.barLabel ?? props.barLabel;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to allow composition?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not, we probably need to have a test for users that are currently passing barLabel in the composition of the BarPlot

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to allow composition?

No, the goal is to maintain the current API without breaking changes.

If not, we probably need to have a test for users that are currently passing barLabel in the composition of the BarPlot

We're indirectly testing this through the BarChart tests that I added. Do you think it makes sense to test it separately for the BarPlot?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point is that we should keep compatibility for users providing this through composition to the BarPlot, so it would be good to have a test of the composition working to ensure we don't create a regression.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍


if (!barLabel) {
return null;
}

return (
<React.Fragment>
{bars.flatMap(({ seriesId, data }) => (
<g key={seriesId} className={classes.seriesLabels} data-series={seriesId}>
{data.map(
({ xOrigin, yOrigin, x, y, dataIndex, color, value, width, height, layout }) => (
<BarLabelItem
key={dataIndex}
seriesId={seriesId}
dataIndex={dataIndex}
value={value}
color={color}
xOrigin={xOrigin}
yOrigin={yOrigin}
x={x}
y={y}
width={width}
height={height}
skipAnimation={skipAnimation ?? false}
layout={layout ?? 'vertical'}
{...other}
/>
),
)}
</g>
<g key={seriesId} className={classes.seriesLabels} data-series={seriesId}>
{data.map(({ xOrigin, yOrigin, x, y, dataIndex, color, value, width, height, layout }) => (
<BarLabelItem
key={dataIndex}
seriesId={seriesId}
dataIndex={dataIndex}
value={value}
color={color}
xOrigin={xOrigin}
yOrigin={yOrigin}
x={x}
y={y}
width={width}
height={height}
skipAnimation={skipAnimation ?? false}
layout={layout ?? 'vertical'}
{...other}
barLabel={barLabel}
/>
))}
</React.Fragment>
</g>
);
}

Expand Down
60 changes: 60 additions & 0 deletions packages/x-charts/src/BarChart/BarPlot.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { screen, createRenderer } from '@mui/internal-test-utils';
import * as React from 'react';
import { ChartContainer } from '../ChartContainer';
import { BarPlot } from './BarPlot';

describe('BarPlot', () => {
const { render } = createRenderer();

it('`barLabel` prop works', () => {
render(
<ChartContainer
series={[{ type: 'bar', data: [1] }]}
width={100}
height={100}
xAxis={[{ scaleType: 'band', data: ['A'] }]}
yAxis={[]}
>
<BarPlot barLabel={() => 'Bar label from prop'} />
</ChartContainer>,
);

expect(screen.getByText('Bar label from prop')).toBeVisible();
});

it('prioritizes `barLabel` from series over `barLabel` prop', () => {
render(
<ChartContainer
series={[{ type: 'bar', data: [1], barLabel: () => 'Bar label from series' }]}
width={100}
height={100}
xAxis={[{ scaleType: 'band', data: ['A'] }]}
yAxis={[]}
>
<BarPlot barLabel={() => 'Bar label from prop'} />
</ChartContainer>,
);

expect(screen.getByText('Bar label from series')).toBeVisible();
});

it("defaults to `barLabel` prop when `barLabel` from series isn't defined", () => {
render(
<ChartContainer
series={[
{ type: 'bar', data: [1] },
{ type: 'bar', data: [1], barLabel: () => 'Bar label from 2nd series' },
]}
width={100}
height={100}
xAxis={[{ scaleType: 'band', data: ['A'] }]}
yAxis={[]}
>
<BarPlot barLabel={() => 'Bar label from prop'} />
</ChartContainer>,
);

expect(screen.getByText('Bar label from prop')).toBeVisible();
expect(screen.getByText('Bar label from 2nd series')).toBeVisible();
});
});
Loading
Loading