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] Improve SVG pattern and gradient support (@JCQuintas) #15724

Merged
merged 2 commits into from
Dec 4, 2024
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
37 changes: 37 additions & 0 deletions docs/data/charts/styling/GradientTooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import { BarChart } from '@mui/x-charts/BarChart';

export default function GradientTooltip() {
return (
<BarChart
sx={{
'--my-custom-gradient': 'url(#GlobalGradient)',
}}
slotProps={{
popper: {
sx: {
'--my-custom-gradient': 'linear-gradient(0deg, #123456, #81b2e4);',
},
},
}}
series={[
{
label: 'series A',
data: [50],
},
{
label: 'series B',
data: [100],
color: 'var(--my-custom-gradient, #123456)',
},
]}
width={400}
height={200}
>
<linearGradient id="GlobalGradient" x1="0%" y1="100%" x2="0%" y2="0%">
<stop offset="0" stopColor="#123456" />
<stop offset="1" stopColor="#81b2e4" />
</linearGradient>
</BarChart>
);
}
37 changes: 37 additions & 0 deletions docs/data/charts/styling/GradientTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import { BarChart } from '@mui/x-charts/BarChart';

export default function GradientTooltip() {
return (
<BarChart
sx={{
'--my-custom-gradient': 'url(#GlobalGradient)',
}}
slotProps={{
popper: {
sx: {
'--my-custom-gradient': 'linear-gradient(0deg, #123456, #81b2e4);',
},
},
}}
series={[
{
label: 'series A',
data: [50],
},
{
label: 'series B',
data: [100],
color: 'var(--my-custom-gradient, #123456)',
},
]}
width={400}
height={200}
>
<linearGradient id="GlobalGradient" x1="0%" y1="100%" x2="0%" y2="0%">
<stop offset="0" stopColor="#123456" />
<stop offset="1" stopColor="#81b2e4" />
</linearGradient>
</BarChart>
);
}
44 changes: 44 additions & 0 deletions docs/data/charts/styling/PatternPie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from 'react';
import { PieChart } from '@mui/x-charts/PieChart';

export default function PatternPie() {
return (
<PieChart
sx={{
'--my-custom-pattern': 'url(#Pattern)',
}}
series={[
{
data: [
{ id: 0, value: 10, label: 'series A' },
{ id: 1, value: 15, label: 'series B' },
{
id: 2,
value: 20,
label: 'series C',
color: 'var(--my-custom-pattern, #123456)',
},
],
},
]}
width={400}
height={200}
>
<pattern
id="Pattern"
patternUnits="userSpaceOnUse"
width="20"
height="40"
patternTransform="scale(0.5)"
>
<rect x="0" y="0" width="100%" height="100%" fill="#123456" />
<path
d="M0 30h20L10 50zm-10-20h20L0 30zm20 0h20L20 30zM0-10h20L10 10z"
strokeWidth="1"
stroke="#81b2e4"
fill="none"
/>
</pattern>
</PieChart>
);
}
44 changes: 44 additions & 0 deletions docs/data/charts/styling/PatternPie.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from 'react';
import { PieChart } from '@mui/x-charts/PieChart';

export default function PatternPie() {
return (
<PieChart
sx={{
'--my-custom-pattern': 'url(#Pattern)',
}}
series={[
{
data: [
{ id: 0, value: 10, label: 'series A' },
{ id: 1, value: 15, label: 'series B' },
{
id: 2,
value: 20,
label: 'series C',
color: 'var(--my-custom-pattern, #123456)',
},
],
},
]}
width={400}
height={200}
>
<pattern
id="Pattern"
patternUnits="userSpaceOnUse"
width="20"
height="40"
patternTransform="scale(0.5)"
>
<rect x="0" y="0" width="100%" height="100%" fill="#123456" />
<path
d="M0 30h20L10 50zm-10-20h20L0 30zm20 0h20L20 30zM0-10h20L10 10z"
strokeWidth="1"
stroke="#81b2e4"
fill="none"
/>
</pattern>
</PieChart>
);
}
19 changes: 19 additions & 0 deletions docs/data/charts/styling/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,22 @@ Chart components accept the `sx` props.
From here, you can target any subcomponents with its class name.

{{"demo": "SxStyling.js"}}

### Gradients and patterns

It is possible to use gradients and patterns to fill the charts.
This can be done by passing your gradient or pattern definition as children of the chart component.

Note that the gradient or pattern defined that way is only usable for SVG.
So a direct definition like `color: "url(#Pattern)'` would cause undefined colors in HTML elements such as the tooltip.
The demo solves this issue by using a CSS variable `'--my-custom-pattern': 'url(#Pattern)'` to specify fallback color with `color: 'var(--my-custom-pattern, #123456)'`.

{{"demo": "PatternPie.js"}}

#### Using gradients on tooltips

Gradients defined as SVG elements are not directly supported in HTML.
However you can use the [gradient functions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#gradient_functions) to define a gradient in CSS.
This gradient can be used in the tooltip by setting the `sx` prop on the tooltip component, instead of the fallback color used in the previous examples.

{{"demo": "GradientTooltip.js"}}
2 changes: 1 addition & 1 deletion packages/x-charts/src/ChartsTooltip/ChartsTooltipTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const ChartsTooltipMark = styled('div', {
height: theme.spacing(1),
borderRadius: '50%',
boxShadow: theme.shadows[1],
backgroundColor: color,
background: color,
borderColor: (theme.vars || theme).palette.background.paper,
border: `solid ${(theme.vars || theme).palette.background.paper} ${theme.spacing(0.25)}`,
boxSizing: 'content-box',
Expand Down
19 changes: 15 additions & 4 deletions packages/x-charts/src/PieChart/PieArc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,15 @@ export const pieArcClasses: PieArcClasses = generateUtilityClasses('MuiPieArc',
]);

const useUtilityClasses = (ownerState: PieArcOwnerState) => {
const { classes, id, isFaded, isHighlighted } = ownerState;
const { classes, id, isFaded, isHighlighted, dataIndex } = ownerState;
const slots = {
root: ['root', `series-${id}`, isHighlighted && 'highlighted', isFaded && 'faded'],
root: [
'root',
`series-${id}`,
`data-index-${dataIndex}`,
isHighlighted && 'highlighted',
isFaded && 'faded',
],
};

return composeClasses(slots, getPieArcUtilityClass, classes);
Expand All @@ -55,9 +61,9 @@ const PieArcRoot = styled(animated.path, {
slot: 'Root',
overridesResolver: (_, styles) => styles.arc,
})<{ ownerState: PieArcOwnerState }>(({ theme }) => ({
// Got to move stroke to an element prop instead of style.
stroke: (theme.vars || theme).palette.background.paper,
strokeWidth: 1,
strokeLinejoin: 'round',
transition: 'opacity 0.2s ease-in, fill 0.2s ease-in, filter 0.2s ease-in',
}));

export type PieArcProps = Omit<React.SVGProps<SVGPathElement>, 'ref' | 'id'> &
Expand Down Expand Up @@ -124,6 +130,11 @@ function PieArc(props: PieArcProps) {
cursor={onClick ? 'pointer' : 'unset'}
ownerState={ownerState}
className={classes.root}
fill={ownerState.color}
opacity={ownerState.isFaded ? 0.3 : 1}
filter={ownerState.isHighlighted ? 'brightness(120%)' : 'none'}
strokeWidth={1}
strokeLinejoin="round"
{...other}
{...getInteractionItemProps({ type: 'pie', seriesId: id, dataIndex })}
/>
Expand Down
3 changes: 0 additions & 3 deletions packages/x-charts/src/PieChart/PieArcPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,8 @@ function PieArcPlot(props: PieArcPlotProps) {
endAngle,
paddingAngle: pA,
innerRadius: iR,
arcLabelRadius,
outerRadius: oR,
cornerRadius: cR,
...style
},
item,
_,
Expand All @@ -129,7 +127,6 @@ function PieArcPlot(props: PieArcPlotProps) {
innerRadius={iR}
outerRadius={oR}
cornerRadius={cR}
style={style}
id={id}
color={item.color}
dataIndex={index}
Expand Down
Loading