Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[charts] Support rounded corners on BarChart #12834

Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a22a887
Initial proposal for rounded corners
JCQuintas Apr 29, 2024
3ee2deb
Working POC for clippath+borderradius
JCQuintas Apr 29, 2024
543fd23
try removing animation on bar themselves
JCQuintas Apr 29, 2024
20b4381
Divide BarGroup into its own file
JCQuintas Apr 29, 2024
7f90026
Bar element no need to be animated
JCQuintas Apr 29, 2024
db4e678
add animated inset
JCQuintas Apr 29, 2024
1006dea
Move getradius to its own and add tests
JCQuintas Apr 29, 2024
9c62fe8
doc getradius function
JCQuintas Apr 29, 2024
3e291e2
animate mask and bars together
JCQuintas Apr 29, 2024
457a00c
Update packages/x-charts/src/BarChart/BarChart.tsx
JCQuintas Apr 29, 2024
005457f
Update packages/x-charts/src/BarChart/BarElement.tsx
JCQuintas Apr 29, 2024
c7d8dc6
rename groupid back to groupindex
JCQuintas Apr 29, 2024
9cc862b
Fix incorrect value assignment in BarPlot.tsx
JCQuintas Apr 29, 2024
17885c5
Remove unnecessary defs
JCQuintas Apr 29, 2024
c46445b
Only render clip path if border radius is positive
JCQuintas Apr 30, 2024
2c15082
Separate mask creation
JCQuintas May 1, 2024
1090888
fix bleeding props
JCQuintas May 1, 2024
1eabc42
Only render necessary masks
JCQuintas May 1, 2024
8aeed1a
Cleanup types
JCQuintas May 1, 2024
1f87d38
Unify clippath logic in component
JCQuintas May 1, 2024
4075d79
Refactor clipPath logic in BarPlot.tsx
JCQuintas May 1, 2024
b750fdb
Add typedoc
JCQuintas May 1, 2024
a64fa13
Update border radius docs
JCQuintas May 1, 2024
407d4a3
Rename to barclippath
JCQuintas May 1, 2024
00718ed
Fix proptypes
JCQuintas May 1, 2024
7ddb5d7
Ignore internal component
JCQuintas May 1, 2024
60b43bc
Update docs/data/charts/bars/bars.md
JCQuintas May 7, 2024
909dfc2
Update docs/data/charts/bars/bars.md
JCQuintas May 7, 2024
970868b
Change animation style getter name
JCQuintas May 7, 2024
8597473
Improve values padding
JCQuintas May 7, 2024
c1a16db
Increase demo spacing
JCQuintas May 7, 2024
66794d6
better mask id
JCQuintas May 7, 2024
606dd70
Update packages/x-charts/src/BarChart/BarPlot.tsx
JCQuintas May 7, 2024
27a73ad
Update proptypes and api
JCQuintas May 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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={1}>
<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={1}>
<Stack direction="column" spacing={1} flex={1}>
JCQuintas marked this conversation as resolved.
Show resolved Hide resolved
<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>
noraleonte marked this conversation as resolved.
Show resolved Hide resolved
<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 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 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 @@ -132,6 +132,7 @@ const BarChart = React.forwardRef(function BarChart(props: BarChartProps, ref) {
rightAxis,
bottomAxis,
skipAnimation,
borderRadius,
onItemClick,
onAxisClick,
children,
Expand Down Expand Up @@ -196,6 +197,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 @@ -231,6 +233,10 @@ BarChart.propTypes = {
x: PropTypes.oneOf(['band', 'line', 'none']),
y: PropTypes.oneOf(['band', 'line', 'none']),
}),
/**
* Defines the 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