-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Relative Gradient on Bar Chart #1968
Comments
@tahaimt It's recommended to use |
You can render this shape const renderShape = (key, pixel = 10) => ({ height, width, fill, x, y, ...rest }) => {
const xpercent = Math.trunc((pixel * 100) / Math.trunc(height || 1));
return (
<svg x={x} y={y} fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id={key} x1="0%" y1="0%" x2="0%" y2={`${xpercent}%`}>
<stop offset="50%" stopColor="white" />
<stop offset="50%" stopColor={fill} stopOpacity="1" />
</linearGradient>
</defs>
<rect fill={`url(#${key})`} width={width} height={height} />
</svg>
);
<Bar
fill="red"
dataKey={'aa}
stackId="1"
shape={renderShape('a') }
/>
};
`` |
Hey thanks for this answer, it didn't work for me but I used it as a basis for my own implementation, which is sort of buggy so I'm still looking for the cleanest way to do things.
The rect therefore has a static gradient, and the clip path hides or shows it making it look like it's growing and shrinking. (Here is a gif: https://imgur.com/a/7s27o3i )
|
It's a little bit freaky in case of using large legend area. Look at this for example: Here we can see that gradient used for bars. Whatever component You'll make (with custom shape or fill of Bar or something else) it will cause incorrect way of gradient - "min" value of gradient will be for area somewhere behind legend. SVG element of recharts surface has size equal to size of recharts wrapper and wrapper has not only surface but also legend, positioned as absolute. And I can't figure out how to properly work with it :) If it's better for You (as I can see) to have svg element with empty space for legend, that is not in svg element, but sibling absolute div - it's your choice. And I see the way of resolving this with a calculating of stop element offset value according to size of legend and chart at all. But am I really have to do this just because You put all of chart with a legend into svg? Or may be I'm missing something? |
How to use hex values for the color? |
How to apply gradient to cells in pie chart? |
This is another similar implementation in case anybody need it: import { useId } from "react";
import { Bar, BarChart, Rectangle, ResponsiveContainer, XAxis } from "recharts";
import { type BarRectangleItem } from "recharts/types/cartesian/Bar";
const data = [
{
name: "Page A",
uv: 4000,
pv: 2400,
amt: 2400,
},
{
name: "Page B",
uv: 3000,
pv: 1398,
amt: 2210,
},
{
name: "Page C",
uv: 2000,
pv: 9800,
amt: 2290,
},
{
name: "Page D",
uv: 2780,
pv: 3908,
amt: 2000,
},
{
name: "Page E",
uv: 1890,
pv: 4800,
amt: 2181,
},
{
name: "Page F",
uv: 2390,
pv: 3800,
amt: 2500,
},
{
name: "Page G",
uv: 3490,
pv: 4300,
amt: 2100,
},
];
function BarGradient(props: BarRectangleItem) {
const id = useId();
const gradientId = `gradient-${id}`;
const clipPathId = `clipPath-${id}`;
return (
<>
<defs>
<linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="100%">
<stop offset="0%" stopColor="red" />
<stop offset="64.43%" stopColor="blue" />
<stop offset="100%" stopColor="green" />
</linearGradient>
<clipPath id={clipPathId}>
<Rectangle {...props} />
</clipPath>
</defs>
<rect
x={props.x}
width={props.width}
height={props.background?.height}
fill={`url(#${gradientId})`}
y={props.background?.y}
clipPath={`url(#${clipPathId})`}
/>
</>
);
}
export function ChartBar() {
return (
<div style={{ width: 500, height: 300 }}>
<ResponsiveContainer width="100%" height="100%">
<BarChart data={data}>
<Bar
dataKey="uv"
shape={<BarGradient />}
activeBar={<BarGradient />}
/>
<XAxis dataKey="name" />
</BarChart>
</ResponsiveContainer>
</div>
);
} |
Reproduction link
Steps to reproduce
Open the link in Sandbox
What is expected?
The gradient on the bars should be on the same scale on all bars, or you can say that the gradient should be relative and should be applied on the bars with reference to the minimum and maximum values in all bars in the chart. Lets say a gradient of red is applied on the top 50% and green is applied on the bottom 50%, if a bar is only erected to 40% it should only be of green color. If a bar is erected to 90%, the bottom 50% should be of green color and the top 40% be of red.
What is actually happening?
Gradient is being applied on each bar from its own minimum to its own maximum.
The text was updated successfully, but these errors were encountered: