Skip to content

Commit

Permalink
[charts] Improve SVG pattern and gradient support (@JCQuintas) (#…
Browse files Browse the repository at this point in the history
…15724)

Signed-off-by: Jose C Quintas Jr <juniorquintas@gmail.com>
Co-authored-by: Jose C Quintas Jr <juniorquintas@gmail.com>
Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com>
  • Loading branch information
3 people authored Dec 4, 2024
1 parent 24927a7 commit e177f9d
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 8 deletions.
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

0 comments on commit e177f9d

Please sign in to comment.