Skip to content

Add support for responsive y-axis width#5880

Merged
ckifer merged 18 commits into
recharts:3.xfrom
saurabhraj123:feature/responsive-y-axis-width
Jun 5, 2025
Merged

Add support for responsive y-axis width#5880
ckifer merged 18 commits into
recharts:3.xfrom
saurabhraj123:feature/responsive-y-axis-width

Conversation

@saurabhraj123

@saurabhraj123 saurabhraj123 commented May 29, 2025

Copy link
Copy Markdown
Contributor

Summary

A fixed width of 60px is given to the y-axis by default. If the label size increases, it overflows. Added a prop named isWidthResponsive, which dynamically calculates the yAxis width based on the width of the ticks.

Refer to this issue: #5861

Description

I have added a new prop named isWidthResponsive. When this is made true, it dynamically calculates the width of the y-axis when:

  • The label prop is either a string/number or an object.
  • If the label prop is a function or a react element, default width of 60px is used as the old flow.

The following logic is used to achieve the same:

  • Calculate width of each y-axis label and find out the maximum width.
  • If valid label prop is present, it calculates its width as well along with tickWidth and tickMargin.
  • Now the final calculated width = maxWidth + tickWidth + tickMargin + 5px. A 5px gap is for gap between the tick and the y-axis label.

This PR rotates the y-axis label to 270 degrees by default as its the most commonly used layout.

Related Issue

#5861 #2027

Motivation and Context

This feature is long awaited and being asked for since 2017 - Refer #947. When I worked on it, I had to do a lot of customisations to achieve this but I feel this feature should be present by default.

How Has This Been Tested?

I have done manual testing by examining different charts in the storybook. Also, the automated test cases are used.

Screenshots (if appropriate):

Before:

Screenshot 2025-05-29 at 11 54 04 PM

After:
Screenshot 2025-05-29 at 11 55 12 PM

Without labels:
Screenshot 2025-05-29 at 11 56 34 PM

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • I have added a storybook story or extended an existing story to show my changes

@ckifer

ckifer commented May 30, 2025

Copy link
Copy Markdown
Member

Can you add some unit tests

@PavelVanecek

Copy link
Copy Markdown
Collaborator

Before looking into code, is it possible to have the API as width="auto"? If we add a new prop then we have to define what happens when people pass in both width and isWidthResponsive. Discoverability suffers.

This comment was marked as outdated.

@PavelVanecek PavelVanecek left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay the "after" variant looks much better. Let's have that as a new breaking change in 3.x @ckifer?

@saurabhraj123 thank you for the PR. Would you mind to fix the conflicts? Then we can have a look at what the CI build looks like and what is the visual diff.

Comment thread src/cartesian/CartesianAxis.tsx Outdated
Comment thread src/cartesian/CartesianAxis.tsx Outdated
Comment thread src/util/YAxisUtils.tsx Outdated
@saurabhraj123

Copy link
Copy Markdown
Contributor Author

Before looking into code, is it possible to have the API as width="auto"? If we add a new prop then we have to define what happens when people pass in both width and isWidthResponsive. Discoverability suffers.

You're right. The width="auto" property makes more sense. I will use that.

@saurabhraj123

Copy link
Copy Markdown
Contributor Author

Can you add some unit tests

I will work on it @ckifer.

@PavelVanecek

Copy link
Copy Markdown
Collaborator

Run npm run test-build-output -- --update to get new bundle file snapshots, that will fix the build

@PavelVanecek

Copy link
Copy Markdown
Collaborator

Also, the YAxis label can be defined two different ways, 1. with label prop or 2. with <YAxis><Label /> child component, do your changes work with both?

@saurabhraj123
saurabhraj123 marked this pull request as draft May 30, 2025 15:27
@saurabhraj123
saurabhraj123 marked this pull request as ready for review May 30, 2025 15:28
@saurabhraj123

Copy link
Copy Markdown
Contributor Author

Run npm run test-build-output -- --update to get new bundle file snapshots, that will fix the build

The command runs successfully in local but produces no change. Do I need to do something else?

@ckifer

ckifer commented May 30, 2025

Copy link
Copy Markdown
Member

If it's not working you can also add to the snapshots manually if you look at the failing build

Comment thread src/cartesian/CartesianAxis.tsx Outdated
Comment thread src/util/YAxisUtils.tsx Outdated
Comment thread src/component/Text.tsx
@PavelVanecek

PavelVanecek commented May 31, 2025

Copy link
Copy Markdown
Collaborator

Run npm run test-build-output -- --update to get new bundle file snapshots, that will fix the build

The command runs successfully in local but produces no change. Do I need to do something else?

Ah sorry I forgot. First npm run build that will generate the bundles, then npm run test-build-output -- --update that will update the bundle snapshot. Then you can run npm run build again to verify that it worked, commit and push.

@codecov

codecov Bot commented Jun 2, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 97.20670% with 5 lines in your changes missing coverage. Please review.

Project coverage is 95.63%. Comparing base (c0a9192) to head (2fb6a50).
Report is 7 commits behind head on 3.x.

Files with missing lines Patch % Lines
src/component/Text.tsx 96.05% 3 Missing ⚠️
src/util/YAxisUtils.tsx 92.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              3.x    #5880      +/-   ##
==========================================
+ Coverage   95.61%   95.63%   +0.01%     
==========================================
  Files         187      188       +1     
  Lines       18975    19064      +89     
  Branches     3805     3823      +18     
==========================================
+ Hits        18143    18231      +88     
- Misses        826      827       +1     
  Partials        6        6              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Label width calculation will be handled in another PR
Comment thread src/util/YAxisUtils.tsx Outdated
Comment thread src/util/YAxisUtils.tsx Outdated
@PavelVanecek
PavelVanecek requested a review from Copilot June 4, 2025 10:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds dynamic sizing support for the Y-axis by allowing width="auto", measuring tick and label dimensions at runtime, and updating the axis width in state.

  • Introduce getCalculatedYAxisWidth utility and tests for responsive sizing
  • Extend state slice, selectors, and constants to handle a new auto width option
  • Update YAxis, CartesianAxis, Label, and Text to measure elements via refs and dispatch width updates

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/cartesian/YAxis.spec.tsx Add tests for fixed and dynamically calculated Y-axis width
src/util/YAxisUtils.tsx New utility to measure tick/label widths for responsive layout
src/util/Constants.ts Define DEFAULT_Y_AXIS_WIDTH constant
src/state/selectors/selectChartOffset.ts Fallback to default width when axis width is non-numeric
src/state/selectors/axisSelectors.ts Use constant default for both implicit and selected Y-axis widths
src/state/cartesianAxisSlice.ts Extend Y-axis settings to accept auto and add update action
src/component/Text.tsx Convert Text to forwardRef to support measuring rendered text
src/component/Label.tsx Pass labelRef through to Text for measurement
src/cartesian/YAxis.tsx Hook into layout effect to calculate and dispatch dynamic width
src/cartesian/CartesianAxis.tsx Track tick nodes via ref to measure their sizes
Comments suppressed due to low confidence (2)

test/cartesian/YAxis.spec.tsx:2160

  • The test covers tick-based width calculation via getCalculatedYAxisWidth but does not cover scenarios with axis labels. Consider adding a test that provides a labelRef and verifies label width and gap are accounted for in the calculated width.
it('should render y-axis with dynamically calculated width', async () => {

src/cartesian/YAxis.tsx:36

  • PR summary mentions a prop 'isWidthResponsive' but the code uses width='auto' for dynamic sizing. Update the documentation or prop name to avoid confusion and ensure alignment between feature description and implementation.
interface YAxisProps extends BaseAxisProps {

Comment thread src/util/YAxisUtils.tsx Outdated
Comment thread src/cartesian/CartesianAxis.tsx
Comment thread src/cartesian/YAxis.tsx Outdated
@saurabhraj123
saurabhraj123 marked this pull request as draft June 4, 2025 11:08
@saurabhraj123
saurabhraj123 marked this pull request as ready for review June 4, 2025 11:08
@saurabhraj123

Copy link
Copy Markdown
Contributor Author

@saurabhraj123 the build failures are unrelated to your changes. I have fixed that on 3.x branch. May I please ask you to merge or rebase?

My branch is already up to date with 3.x @PavelVanecek. Ran build commands as well, no changes are reflected.

@ckifer

ckifer commented Jun 4, 2025

Copy link
Copy Markdown
Member

Looks like the vitest downgrade hasn't been merged into your branch. Make sure to do a fresh npm install

@ckifer
ckifer requested a review from PavelVanecek June 4, 2025 16:48
@ckifer
ckifer merged commit 92916eb into recharts:3.x Jun 5, 2025
@PavelVanecek

Copy link
Copy Markdown
Collaborator

Would you like to add the new property to the storybook and docs too, to make it easier to find for other devs?

image image

@PavelVanecek

Copy link
Copy Markdown
Collaborator

No visual diff in the storybook: https://www.chromatic.com/build?appId=63da8268a0da9970db6992aa&number=2358

@saurabhraj123

Copy link
Copy Markdown
Contributor Author

Would you like to add the new property to the storybook and docs too, to make it easier to find for other devs?

I will @PavelVanecek. Also, I will create a follow up PR to add support for the labels.

@PavelVanecek

Copy link
Copy Markdown
Collaborator

Thanks!

ckifer pushed a commit that referenced this pull request Jun 6, 2025
<!--- Provide a general summary of your changes in the Title above -->

## Description
Adding `width='auto'` support in storybook. Refer to this: #5880 

**Implementation summary:**
Changed control type to `text` for YAxis. Then inside
`YAxis.stories.tsx`, wrote a function to convert entered text to number
or 'auto' and passed it to YAxis.

<!--- Describe your changes in detail -->

## Related Issue
#5880 

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an
issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps
to reproduce -->
<!--- Please link to the issue here: -->

## How Has This Been Tested?
By entering different values in the input field for width.

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->

## Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [x] I have added a storybook story or extended an existing story to
show my changes
@hc-12

hc-12 commented Jun 17, 2025

Copy link
Copy Markdown

Hi, i need this feature. Has this been released in v3 beta?

@ckifer

ckifer commented Jun 17, 2025

Copy link
Copy Markdown
Member

Not yet but looking at releasing 3.0 shortly

@ckifer

ckifer commented Jun 18, 2025

Copy link
Copy Markdown
Member

released beta.2 for the time being

Comment thread src/component/Label.tsx
}

return <Label key="label-implicit" content={label} viewBox={viewBox} />;
return <Label key="label-implicit" content={label} {...commonProps} />;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when label is an HTML or SVG element label gets passed to content and then content is cloned with props. props includes labelRef which isn't a valid prop in the DOM

ckifer pushed a commit that referenced this pull request Jun 25, 2025
<!--- Provide a general summary of your changes in the Title above -->

## Description
`labelRef` was being passed to a DOM node. It is not a valid node prop
and was causing warning.

## Related Issue
#6004 
#5880 
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an
issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps
to reproduce -->
<!--- Please link to the issue here: -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [ ] I have added a storybook story or extended an existing story to
show my changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants