Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dashboards): Auto-size Big Number widget (#76209)
**Before:** <img width="1194" alt="Screenshot 2024-08-13 at 3 16 05 PM" src="https://github.com/user-attachments/assets/354672f6-6537-44cf-b760-e5f6eeba5185"> **After:** <img width="1198" alt="Screenshot 2024-08-13 at 3 16 17 PM" src="https://github.com/user-attachments/assets/dd66ce6b-6183-4855-be8b-89c900d4589e"> **Bonus:** ![Screenshot 2024-08-14 at 3 53 42 PM](https://github.com/user-attachments/assets/e8a61c28-dec9-403f-8af9-fcf971ac31e2) ## Explanation The "Big Number" widget is a Dashboards feature where a user can make a query like `count()` and get a big honkin' number that shows how many transactions they have. The widget has some fancy CSS to help size it big (but not too big), but CSS alone isn't enough. In many cases, the big number gets truncated! That's not very nice or very useful. This PR changes the approach. Instead of CSS, it adds a new utility component called `AutoSizedText`. This component mimics the height and width of its parent, and then iteratively updates the font size of its contents until they fit nicely inside the parent. e.g., - The parent is 300px by 300x, and contains the text "OH HELLO" - The component splits the difference and renders the text at a font size of 110px ((200px + 20px) / 2). It sets the known bounds to 20px minimum and 200px maximum - The component determines the child is too big because it has bigger dimensions than its parent. It splits the difference between the current and minimum font size, and sets it to 165px ((110px + 200px) / 2). It updates the known bounds to 20px minimum and 200px maximum (since 200px is known to be too big) and renders again - The child is still too big. The component narrows the font size search field again (note: this works kind of like a binary search) by splitting the difference between the current and minimum font size ((165 + 20) / 2) to 92.5. It updates the known bounds to minimum 20px and maximum 165px. - This process continues until the child is either within 5% of the parent dimensions _and_ fits inside the parent _or_ it runs out of calculations (maximum of 5 per component) ## Other Methods Considered 1. SVG. SVGs can auto-scale to a parent, and can contain `<text>` elements. I didn't like this approach because font scaling by percentage is _not at all_ the same as changing the font size. Modern typefaces do a lot of work to look legible at different sizes at the font level, and the only way to respect this is to set the correct font size 2. CSS `transform` has the same problem as SVG scaling 3. Container Queries. This doesn't work because container queries make it easier to set the font size as a proportion of the container, but our case is very complicated. For one thing, we'd need to clamp and scale on both width and height, but the _width_ of the content is fully variable based on which characters are used. There's no known ratio that would work. For another, that approach doesn't work at all for multi-line text? Etc. 4. Canvas. There's a way (I hear) to render text to a canvas and use `measureText` to get the dimensions, but that's fairly complicated ## FAQs I think the most obvious question is what's the performance like. In short, it's not great, but I did what I could. The most important thing is wrapping the updates in `useTransition` which will mark them as lower priority. This will allow other, higher-priority renders (like interactions with other dropdowns) to interrupt the resizing logic. I also limited the iteration count to 5, and debounced the resize listener. This seems to work _well enough_ even with CPU throttling set pretty high. Overall I'm not too worried because resizing is not a common operation, and it's still pretty fast compared to how long a Dashboard resize _already_ takes (a long time). The second is testing. Short of literal snapshots (which I don't think we do anymore) I couldn't come up with anything that felt more worthwhile than manual QA. You tell me, though. Fixes [#75730](#75730) --------- Co-authored-by: Jonas <jonas.badalic@sentry.io>
- Loading branch information