Reputation: 71
I am being asked to put long string values as my X axis tick labels.
I tried other charting libraries, but this one overall has worked the best for my situation. I just cannot figure out what to do with the x axis labels.
I tried to create a separate div
and map
through the values underneath the chart, but I can't maintain the alignment between the chart and the values when there are more than 7 or 8 x axis values.
I had a tickFormatter
function that cut the string at a certain number of characters/hid the overflow and was set at an angle on the x axis, but they still aren't happy with that.
This is my code currently and I feel like it is so close to being workable and I just wish that I could get the text to wrap onto more lines.
Working with SVGs is extremely confusing to me and I've tried to write functions that return SVG text elements as a custom tick, but I couldn't get it to work. Or when I pass something and it returns [object Object] as the label.
const data = React.useMemo(() => {
return orderOfItems?.map((claim, i) => ({
Item: i + 1,
Claim: claim.split(" ").join("\n"),
Reach: (
incrementalReachSummary[claim]?.Summary_Metrics.Reach * 100
).toFixed(1),
}));
}, [orderOfItems, incrementalReachSummary]);
const tickFormatter = (value: string) => {
const limit = 10; // put your maximum character
if (value.length < limit) return value;
return `${value.split(" ").join("\n")}...`;
};
return (
<>
<ResponsiveContainer
align={"end"}
w={"60%"}
height={200}
aspect={2}
minWidth={"undefined"}
maxHeight={"undefined"}
>
<LineChart
data={data}
margin={{
top: 50,
right: 250,
left: 250,
bottom: 500,
}}
>
<CartesianGrid
strokeDasharray="3"
opacity={colorMode === "dark" ? 0.3 : 0.9}
/>
<XAxis
// hide={true}
dataKey={"Claim"}
interval="preserveStartEnd"
angle={-35}
tickFormatter={tickFormatter}
textAnchor={"end"}
axisLine={false}
offset={5}
tickMargin={10}
style={{
fill: colorMode === "dark" ? "#FFFFFF" : "#1A202C",
textAlign: "center",
}}
>
{/*<Label value="Claim" offset={100} position="bottom" />*/}
</XAxis>
<YAxis
type={"number"}
domain={[0, 100]}
axisLine={false}
tickLine={false}
tickCount={7}
tickMargin={10}
tickFormatter={(Reach) => `${Reach}%`}
style={{ fill: colorMode === "dark" ? "#FFFFFF" : "#1A202C" }}
/>
<Tooltip content={<CustomToolTip />} />
<Line
type="monotone"
strokeWidth={3}
dataKey="Reach"
stroke="#3182CE"
activeDot={{ r: 9 }}
>
<LabelList
dataKey="Reach"
offset={14}
position="insideTopLeft"
formatter={(Reach) => `${Reach}%`}
fill={colorMode === "dark" ? "#FFFFFF" : "#1A202C"}
/>
</Line>
</LineChart>
</ResponsiveContainer>
Upvotes: 6
Views: 13194
Reputation: 11
I wrote a component that outputs multiline string in more accurately way. Just add \n
(ex. June\n2024
) in you label string and it would output label as multiline string.
You can use it this way
<XAxis tick={<CustomizedAxisTick />} />
And this is custom tick component
function CustomizedAxisTick(props: TickProps) {
const { fill, height, orientation, payload, stroke, textAnchor, type, width, x, y } = props;
return (
<text
{...{ fill, height, orientation, stroke, textAnchor, type, width, x, y }}
className="recharts-text recharts-cartesian-axis-tick-value"
>
{payload.value.split('\n').map((value: string, index: number) => {
const dy = 0.71 * (index + 1) + 'em';
return (
<tspan dy={dy} key={index} x={payload.tickCoord}>
{value}
</tspan>
);
})}
</text>
);
}
Upvotes: 1
Reputation: 61
Actually it is easier and cleaner to just use the <Text> component and set a width in order to force a wrap. see https://recharts.org/en-US/api/Text
In my case, I also needed to alternate the y position in order to keep text from overlapping.
<Text x={x} y={y+offset} style={{fontSize: "12px"}} fill="#000000" textAnchor="middle" width="170" verticalAnchor="start">
{payload.value}
</Text>
Upvotes: 1
Reputation: 22617
You need to create a custom tick react component. Line breaks will not work. You will need to use multiple <tspan>
components with correct dy
or vertical position. Also increase the chart bottom
so lines are not hidden.
Use payload.value
to access the original value & create as many tspans
required.
<XAxis tick={<CustomizedTick />} />
Example
function CustomizedTick(props) {
const { x, y, stroke, payload } = props;
return (
<g transform={`translate(${x},${y})`}>
<text x={0} y={0} dy={16} fill="#666">
<tspan textAnchor="middle" x="0">
Line 1
</tspan>
<tspan textAnchor="middle" x="0" dy="20">
Line 2
</tspan>
<tspan textAnchor="middle" x="0" dy="40">
Line 3
</tspan>
</text>
</g>
);
}
Working codesandbox.
Upvotes: 4