Skip to content

Commit

Permalink
[charts] Support rounded corners on BarChart (#12834)
Browse files Browse the repository at this point in the history
Signed-off-by: Jose C Quintas Jr <[email protected]>
Co-authored-by: Alexandre Fauquette <[email protected]>
Co-authored-by: José Rodolfo Freitas <[email protected]>
Co-authored-by: Nora <[email protected]>
Co-authored-by: Lukas <[email protected]>
  • Loading branch information
5 people authored May 7, 2024
1 parent 3588698 commit 339c34e
Show file tree
Hide file tree
Showing 15 changed files with 587 additions and 135 deletions.
102 changes: 70 additions & 32 deletions docs/data/charts/bars/BorderRadius.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,90 @@
import * as React from 'react';
import { BarChart } from '@mui/x-charts/BarChart';
import { axisClasses } from '@mui/x-charts/ChartsAxis';
import Stack from '@mui/material/Stack';
import { HighlightedCode } from '@mui/docs/HighlightedCode';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';
import Slider from '@mui/material/Slider';
import Typography from '@mui/material/Typography';

export default function BorderRadius() {
const [layout, setLayout] = React.useState('vertical');
const [radius, setRadius] = React.useState(10);

return (
<div style={{ width: '100%' }}>
<Stack direction="column" spacing={1} sx={{ width: '100%', maxWidth: 600 }}>
<Stack direction="row" spacing={4}>
<Stack direction="column" spacing={1} flex={1}>
<Typography gutterBottom>Border Radius</Typography>
<Slider
value={radius}
onChange={(e, v) => setRadius(v)}
valueLabelDisplay="auto"
min={0}
max={50}
sx={{ mt: 2 }}
/>
</Stack>
<TextField
select
sx={{ minWidth: 150 }}
label="layout"
value={layout}
onChange={(event) => setLayout(event.target.value)}
>
<MenuItem value="horizontal">Horizontal</MenuItem>
<MenuItem value="vertical">Vertical</MenuItem>
</TextField>
</Stack>
<BarChart
dataset={dataset}
{...chartSetting}
slotProps={{
bar: {
clipPath: `inset(0px round 10px 10px 0px 0px)`,
},
}}
series={[
{ dataKey: 'high', label: 'High', layout, stack: 'stack' },
{ dataKey: 'low', label: 'Low', layout, stack: 'stack' },
]}
{...(layout === 'vertical' ? chartSettingsV : chartSettingsH)}
borderRadius={radius}
/>
<HighlightedCode
code={[`<BarChart`, ` /* ... */`, ` borderRadius={${radius}}`, `/>`].join(
'\n',
)}
language="jsx"
copyButtonHidden
/>
</div>
</Stack>
);
}

const dataset = [
[59, 57, 86, 21, 'Jan'],
[50, 52, 78, 28, 'Fev'],
[47, 53, 106, 41, 'Mar'],
[54, 56, 92, 73, 'Apr'],
[57, 69, 92, 99, 'May'],
[60, 63, 103, 144, 'June'],
[59, 60, 105, 319, 'July'],
[65, 60, 106, 249, 'Aug'],
[51, 51, 95, 131, 'Sept'],
[60, 65, 97, 55, 'Oct'],
[67, 64, 76, 48, 'Nov'],
[61, 70, 103, 25, 'Dec'],
].map(([london, paris, newYork, seoul, month]) => ({
london,
paris,
newYork,
seoul,
month,
[3, -7, 'First'],
[0, -5, 'Second'],
[10, 0, 'Third'],
[9, 6, 'Fourth'],
].map(([high, low, order]) => ({
high,
low,
order,
}));

const valueFormatter = (value) => `${value}mm`;

const chartSetting = {
series: [{ dataKey: 'seoul', label: 'Seoul rainfall', valueFormatter }],
const chartSettingsH = {
dataset,
height: 300,
yAxis: [{ scaleType: 'band', dataKey: 'order' }],
sx: {
[`& .${axisClasses.directionY} .${axisClasses.label}`]: {
transform: 'translateX(-10px)',
},
},
slotProps: {
legend: {
direction: 'row',
position: { vertical: 'bottom', horizontal: 'middle' },
padding: -5,
},
},
};
const chartSettingsV = {
...chartSettingsH,
xAxis: [{ scaleType: 'band', dataKey: 'order' }],
yAxis: undefined,
};
106 changes: 73 additions & 33 deletions docs/data/charts/bars/BorderRadius.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,92 @@
import * as React from 'react';
import { BarChart } from '@mui/x-charts/BarChart';
import { BarChart, BarChartProps } from '@mui/x-charts/BarChart';
import { axisClasses } from '@mui/x-charts/ChartsAxis';
import Stack from '@mui/material/Stack';
import { HighlightedCode } from '@mui/docs/HighlightedCode';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';
import Slider from '@mui/material/Slider';
import Typography from '@mui/material/Typography';

export default function BorderRadius() {
const [layout, setLayout] = React.useState<'horizontal' | 'vertical'>('vertical');
const [radius, setRadius] = React.useState(10);

return (
<div style={{ width: '100%' }}>
<Stack direction="column" spacing={1} sx={{ width: '100%', maxWidth: 600 }}>
<Stack direction="row" spacing={4}>
<Stack direction="column" spacing={1} flex={1}>
<Typography gutterBottom>Border Radius</Typography>
<Slider
value={radius}
onChange={(e, v) => setRadius(v as number)}
valueLabelDisplay="auto"
min={0}
max={50}
sx={{ mt: 2 }}
/>
</Stack>
<TextField
select
sx={{ minWidth: 150 }}
label="layout"
value={layout}
onChange={(event) =>
setLayout(event.target.value as 'horizontal' | 'vertical')
}
>
<MenuItem value="horizontal">Horizontal</MenuItem>
<MenuItem value="vertical">Vertical</MenuItem>
</TextField>
</Stack>
<BarChart
dataset={dataset}
{...chartSetting}
slotProps={{
bar: {
clipPath: `inset(0px round 10px 10px 0px 0px)`,
},
}}
series={[
{ dataKey: 'high', label: 'High', layout, stack: 'stack' },
{ dataKey: 'low', label: 'Low', layout, stack: 'stack' },
]}
{...(layout === 'vertical' ? chartSettingsV : chartSettingsH)}
borderRadius={radius}
/>
<HighlightedCode
code={[`<BarChart`, ` /* ... */`, ` borderRadius={${radius}}`, `/>`].join(
'\n',
)}
language="jsx"
copyButtonHidden
/>
</div>
</Stack>
);
}

const dataset = [
[59, 57, 86, 21, 'Jan'],
[50, 52, 78, 28, 'Fev'],
[47, 53, 106, 41, 'Mar'],
[54, 56, 92, 73, 'Apr'],
[57, 69, 92, 99, 'May'],
[60, 63, 103, 144, 'June'],
[59, 60, 105, 319, 'July'],
[65, 60, 106, 249, 'Aug'],
[51, 51, 95, 131, 'Sept'],
[60, 65, 97, 55, 'Oct'],
[67, 64, 76, 48, 'Nov'],
[61, 70, 103, 25, 'Dec'],
].map(([london, paris, newYork, seoul, month]) => ({
london,
paris,
newYork,
seoul,
month,
[3, -7, 'First'],
[0, -5, 'Second'],
[10, 0, 'Third'],
[9, 6, 'Fourth'],
].map(([high, low, order]) => ({
high,
low,
order,
}));

const valueFormatter = (value: number | null) => `${value}mm`;

const chartSetting = {
series: [{ dataKey: 'seoul', label: 'Seoul rainfall', valueFormatter }],
const chartSettingsH: Partial<BarChartProps> = {
dataset,
height: 300,
yAxis: [{ scaleType: 'band', dataKey: 'order' }],
sx: {
[`& .${axisClasses.directionY} .${axisClasses.label}`]: {
transform: 'translateX(-10px)',
},
},
slotProps: {
legend: {
direction: 'row',
position: { vertical: 'bottom', horizontal: 'middle' },
padding: -5,
},
},
};
const chartSettingsV: Partial<BarChartProps> = {
...chartSettingsH,
xAxis: [{ scaleType: 'band', dataKey: 'order' }],
yAxis: undefined,
};
9 changes: 0 additions & 9 deletions docs/data/charts/bars/BorderRadius.tsx.preview

This file was deleted.

17 changes: 2 additions & 15 deletions docs/data/charts/bars/bars.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,25 +102,12 @@ Learn more about the `colorMap` properties in the [Styling docs](/x/react-charts

### Border Radius

The border radius can be set by using a [clipPath](https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path) with
[inset](https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape/inset) on the BarChart's `bar` [slot](/x/api/charts/bar-chart/#bar-chart-prop-slots)
To give your bar chart rounded corners, you can change the value of the `borderRadius` property on the [BarChart](/x/api/charts/bar-chart/#bar-chart-prop-slots).

You can customize any of properties inside `inset`, the first property is "distance from border" and should be left at `0px` else it might break the bars alignment.

```css
inset(0px round <top-left> <top-right> <bottom-right> <bottom-left>)
```
It will work with any positive value and will be properly applied to horizontal layouts, stacks and negative values.

{{"demo": "BorderRadius.js"}}

:::warning
There are few limitations to this method though.

- [Stacking](/x/react-charts/bars/#stacking) won't look right with border radius.
- On charts containing `Negative` and `Positive` values, rounding will apply to all of them in the same way, which might be undesirable.

:::

## Click event

Bar charts provides two click handlers:
Expand Down
1 change: 1 addition & 0 deletions docs/pages/x/api/charts/bar-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"text": "highlight docs"
}
},
"borderRadius": { "type": { "name": "number" } },
"bottomAxis": {
"type": { "name": "union", "description": "object<br>&#124;&nbsp;string" },
"default": "xAxisIds[0] The id of the first provided axis"
Expand Down
1 change: 1 addition & 0 deletions docs/pages/x/api/charts/bar-plot.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"props": {
"borderRadius": { "type": { "name": "number" } },
"onItemClick": {
"type": { "name": "func" },
"signature": {
Expand Down
1 change: 1 addition & 0 deletions docs/translations/api-docs/charts/bar-chart/bar-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"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."
},
"borderRadius": { "description": "Defines the border radius of the bar element." },
"bottomAxis": {
"description": "Indicate which axis to display the bottom of the charts. Can be a string (the id of the axis) or an object <code>ChartsXAxisProps</code>."
},
Expand Down
1 change: 1 addition & 0 deletions docs/translations/api-docs/charts/bar-plot/bar-plot.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"componentDescription": "",
"propDescriptions": {
"borderRadius": { "description": "Defines the border radius of the bar element." },
"onItemClick": {
"description": "Callback fired when a bar item is clicked.",
"typeDescriptions": {
Expand Down
6 changes: 6 additions & 0 deletions packages/x-charts/src/BarChart/BarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ const BarChart = React.forwardRef(function BarChart(props: BarChartProps, ref) {
rightAxis,
bottomAxis,
skipAnimation,
borderRadius,
onItemClick,
onAxisClick,
children,
Expand Down Expand Up @@ -195,6 +196,7 @@ const BarChart = React.forwardRef(function BarChart(props: BarChartProps, ref) {
slotProps={slotProps}
skipAnimation={skipAnimation}
onItemClick={onItemClick}
borderRadius={borderRadius}
/>
<ChartsOverlay loading={loading} slots={slots} slotProps={slotProps} />
</g>
Expand Down Expand Up @@ -230,6 +232,10 @@ BarChart.propTypes = {
x: PropTypes.oneOf(['band', 'line', 'none']),
y: PropTypes.oneOf(['band', 'line', 'none']),
}),
/**
* Defines the border radius of the bar element.
*/
borderRadius: PropTypes.number,
/**
* Indicate which axis to display the bottom of the charts.
* Can be a string (the id of the axis) or an object `ChartsXAxisProps`.
Expand Down
Loading

0 comments on commit 339c34e

Please sign in to comment.