For each Stacked Bar element, I calculate its percentage
const valuePercent = attribute => ({payload}) => {
const keys = getKeys(chartData);
const total = keys.reduce((acc, curr) => {
return acc + payload[curr].count;
}, 0);
const ratio = total > 0 ? payload[attribute].count / total : 0;
return `${(ratio * 100).toFixed(0)}%`;
};
But when I substitute this value in the style, it doesn't work. What could be the problem?
return keys.map((item, index) => ( <
Bar key = {
index
}
dataKey = {
`${item}.count`
}
stackId = 'a'
style = {
{
fill: '#0452D7',
fillOpacity: valuePercent(item),
}
}
/>
));
May shape
properties of Bar
not work with hooks, so you need to customize using shape
. so as checked your codesandbox
code and update with solve code as below:
import "./styles.css";
import React from "react";
import { BarChart, Bar, XAxis, YAxis, LabelList } from "recharts";
const chartData = [
{
name: "data 1",
city1: { count: 1000, label: "data 1", price: 9999 },
city2: { count: 2400, label: "data 2", price: 9999 },
city3: { count: 2400, label: "data 3", price: 9999 }
},
{
name: "data 2",
city1: { count: 4000, label: "data 1", price: 9999 },
city2: { count: 2400, label: "data 2", price: 9999 },
city3: { count: 2400, label: "data 3", price: 9999 }
},
{
name: "data 3",
city1: { count: 4000, label: "data 1", price: 9999 },
city2: { count: 2400, label: "data 2", price: 9999 },
city3: { count: 2400, label: "data 3", price: 9999 }
},
{
name: "data 4",
city1: { count: 4000, label: "data 1", price: 9999 },
city2: { count: 2400, label: "data 2", price: 9999 },
city3: { count: 2400, label: "data 3", price: 9999 }
},
{
name: "data 5",
city1: { count: 4000, label: "data 1", price: 9999 },
city2: { count: 2400, label: "data 2", price: 9999 },
city3: { count: 2400, label: "data 3", price: 9999 }
},
{
name: "data 6",
city1: { count: 4000, label: "data 1", price: 9999 },
city4: { count: 2400, label: "data 3", price: 9999 }
}
];
export default function App() {
const getKeys = (data) => {
const keys = [...new Set(data.flatMap(Object.keys))];
return keys.filter((key) => key !== "name");
};
const valueAccessor = (attribute) => ({ payload }) => {
const keys = getKeys(chartData);
const total = keys.reduce((acc, curr) => {
if (payload.hasOwnProperty(curr)) {
return acc + payload[curr].count;
}
return acc;
}, 0);
if (payload.hasOwnProperty(attribute)) {
const ratio = total > 0 ? payload[attribute].count / total : 0;
return `${(ratio * 100).toFixed(0)}%`;
}
};
const getBarShape = (x, y, width, height, radius, newFillOpacity) => {
const [tl, tr, bl, br] = radius;
const d = `M${x},${y + tl}
a${tl},${tl} 0 0 1 ${tl},${-tl}
h${width - tl - tr}
a${tr},${tr} 0 0 1 ${tr},${tr}
v${height - tr - br}
a${br},${br} 0 0 1 ${-br},${br}
h${bl + (br - width)}
a${bl},${bl} 0 0 1 ${-bl},${-bl}
z`;
return ({ fill, fillOpacity, stroke }) => (
<path
d={d}
fill={fill}
fillOpacity={newFillOpacity ? newFillOpacity : fillOpacity}
stroke={stroke}
/>
);
};
const CustomleBar = ({ x, y, width, height, item, ...rest }) => {
const fillOpacity = valueAccessor(item)(rest);
const Bar = getBarShape(x, y, width, height, [0, 0, 0, 0], fillOpacity);
return (
<g>
<Bar stackId="a" fill="#0452D7" />
</g>
);
};
const renderBars = () => {
const keys = getKeys(chartData);
return keys.map((item, index) => {
return (
<Bar
key={index}
dataKey={`${item}.count`}
stackId="a"
shape={<CustomleBar item={item} />}
>
<LabelList
valueAccessor={(props) => valueAccessor(item)(props)}
fill="#fff"
/>
</Bar>
);
});
};
return (
<BarChart
width={500}
height={300}
data={chartData}
stackOffset="expand"
margin={{
top: 20,
right: 30,
left: 20,
bottom: 5
}}
>
<XAxis hide dataKey="name" />
<YAxis hide />
{renderBars()}
</BarChart>
);
}