Skip to content
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

[charts] Support long text #10928

Open
alexfauquette opened this issue Nov 7, 2023 · 6 comments
Open

[charts] Support long text #10928

alexfauquette opened this issue Nov 7, 2023 · 6 comments
Assignees
Labels
component: charts This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature

Comments

@alexfauquette
Copy link
Member

alexfauquette commented Nov 7, 2023

Long text can quickly become an issue in legend and in axis tick labels. For the legend, it push the legend onto the chart, and for the label, they overflow the SVG area

image
image

Solution from other libraries

Ideas

Outside of this scop, the way to format values and labels should be documented and exhaustive.
From the series/axis definition, I should be able to render whatever I want for the tooltip, the legend and the axis. For now the value formater are common to all the components

Search keywords: charts, legend, labels, overflow

@alexfauquette alexfauquette added enhancement This is not a bug, nor a new feature component: charts This is the name of the generic UI component, not the React module! labels Nov 7, 2023
@michaelpward
Copy link

michaelpward commented Nov 8, 2023

@alexfauquette Thank you! 🙂

It may be informative for you to create versions of these charts with, for example, 25 items in the legend to see how they render. It will not be good.

There are at least 2 cases to consider:

  • long strings in tickLabels/legend
  • large number of items in the legend

Below is a partial screenshot of a dashboard in production in our app (a marketing automation platform).

  • The chart on the left shows the "Marketing Channels" that drove growth in the marketing database across the selected date range.
  • The chart on the right aggregates that same data to make clearer which channels are driving the most growth for this customer. As you can see, there are maybe ~30 labels on that chart.

These charts use Chart.js. Chart.js shrinks the "plot area" (I don't know what to call it, the area where the actual chart is) if the legend is large. It gives the legend the space it needs first, then plots the chart in the remaining space. As a developer, there is nothing I need to do. It just works.

If I have to calculate or find the size of the legend so I can set the size of the plot area... I'll just use Chart.js because it does it for me.

That said there is a shortcoming with Chart.js. If the number of items in the legend is very large (let's say 60 or more), the plot area is so small that the chart is useless.

This is a real use case. Set a 12 month date range on that dashboard (which our customers absolutely want to do) and the chart becomes worthless because there are so many marketing channels in a long date range (unless I render it in a much larger container).

A great solution would be a legend that can "overflow":

  • the legend takes up whatever space it needs
  • the plot area is sized automatically to use the remaining space
  • the plot area accepts a minHeight (or minWidth). If the legend is so large it would shrink the plot area to be smaller than the minHeight, the legend "pops up" on mouseover. Or similar.
    What matters is that:
  • the plot area remains visually useful/informative
  • the legend is visible unless it's too large. Then the legend is "available" by mouseover or similar

Thanks for listening 🙂

image

@alexfauquette
Copy link
Member Author

Duplicate wit good insights: #12157

@alexfauquette
Copy link
Member Author

The satori project that map HTML to SVG has its full codebase for text here: https://github.com/vercel/satori/tree/main/src/text

They have a font engine that loads fonts and allows to get the bounding box of text elements.

string can be splited by word or graphen using the segment helper which relies on the Intl.Segmenter to support multiple locales

Then it's a question of mesuring each world, and adapt their placement according to some CSS rules.

@bernardobelchior
Copy link
Member

bernardobelchior commented Feb 11, 2025

@alexfauquette another approach I thought of (other than the one at #16536) is measuring the SVG text.

From my investigations measuring SVG text is the slowest of all options (measuring text in canvas and HTML), but I was assuming that we were creating a new text element inside a new svg element and calling getBBox(). However, due to server-side rendering, we're already rendering all labels. As such, we have already incurred the cost of creating the elements, so the performance of calling getBBox() might be better.

One downside, however, is that if the styles of labels change after client hydration, we would need to re-render all labels to measure them, which might not be very performant.

I'll leave this option here in case it sparks some other ideas, but I don't think it has much future.

@alexfauquette
Copy link
Member Author

@michaelpward It took time but the legend issue got solved in the v8 🎉
The chosen solution has been to extract the legend from SVG to HTML such that it can now scale with its content.

You can already have a look at it in https://next.mui.com/x/react-charts/legend/

@bernardobelchior
Copy link
Member

I'm working on overflowing labels next. Current state:

Image

Image

From this, I see two options:

  1. Hide labels that overflow
  2. Clip labels (w/ ellipsis) that overflow

I'm more inclined to the first option because usually labels are numbers, so using an ellipsis/clipping them doesn't provide much value. E.g., if I have "123456" and I clip it to "12...", the magnitude of the number is lost and it would be better to format it as 120k, for example.

Additionally, hiding is likely more performant as it doesn't requiring finding the largest text that fits the available space.

@alexfauquette @JCQuintas would you agree or do you see any better option/any disadvantages with my proposal?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: charts This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature
Projects
None yet
Development

No branches or pull requests

3 participants