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

[text] Text measurement problems in browsers #375

Open
sto3psl opened this issue Oct 18, 2018 · 7 comments
Open

[text] Text measurement problems in browsers #375

sto3psl opened this issue Oct 18, 2018 · 7 comments

Comments

@sto3psl
Copy link
Contributor

sto3psl commented Oct 18, 2018

Working a lot with data visualisation and building responsive charts at my company, it came to my attention that in some cases browsers don't measure text correctly and it isn't the fastest thing in general. This got me to start investigating what methods are available to measure text in browsers and compare their speed and accuracy.

I compared these methods:

To make it short:

I didn't try Edge yet or mobile browsers.

I will investigate further and extend my examples. The question is if someone would like to help with that and if it is of interest to you, to improve the reliability and speed of @vx/text and getStringWidth. Currently vx uses getComputedTextLength and from my first investigations I think it could be worth to switch to ctx.measureText. There are also other benefits. For example ctx.measureText doesn't need an element in the DOM (still needs to be created) and it can be done off the main thread with Offscreen Canvas in the future.

Let me know what you think ✌️.

@techniq
Copy link
Collaborator

techniq commented Oct 18, 2018

@sto3psl Awesome analysis! The discrepancies between the measuring types seems relatively low (fractional pixel typically) (I only looked in Chrome and Safari briefly) although I don't know if using a non-SVG based measurement could cause any problems with rendering inconsistencies, but with such a low variance, it's probably worth the speed improvement (especially getting it off the main thread).

I don't have a lot of extra time nowadays, but could try to assist as much as possible.

@loopmode
Copy link

getBoundingClientRect will always cause reflow / layout thrashing, so it's definitely not worth it.
About canvas measuring.. it might become more complicated when you have scaling transforms, e.g when there is a zoom feature for the user.
One would have to traverse up the svg tree and collect all scale transforms, then apply them to the result somehow, right?

@sto3psl
Copy link
Contributor Author

sto3psl commented Oct 19, 2018

That's interesting. I didn't know that transforms affect the measured size of text in SVG since they don't affect getBoundingClientRect. I'm not quite sure though if scaling transforms would cause problems if measuring with canvas. My reasoning is that one usually measures to layout the text like in @vx/text and scaling after that won't change that. I will make a codepen and try with ctx.measureText() and getComputedTextLength().

Thanks for the insights! That's super helpful.

@loopmode
Copy link

Well maybe it was a misunderstanding, but I am currently working on something where the user can basically author a graph, e.g. place nodes and edges, put labels on them, and zoom the whole thing in out via scale transform on a rather-top-level <g> around the actual contents.
getBoundingClientRect gives me the proper rect on-screen, but it's expensive as hell.

@sto3psl
Copy link
Contributor Author

sto3psl commented Oct 19, 2018

I'm not sure if I follow. Could you make a short video of the zoom behaviour? Basic zooming with transform: scale(x) is like zooming an image and doesn't need new text measurements. Not sure what you use getBoundingClientRect for 😅.

@hshoff
Copy link
Member

hshoff commented Oct 19, 2018

Seems like canvas is a bit slower than svg on initial page load vs refresh (maybe this is just my browser?)
speed

I'd be open to making text measurement a runtime strategy where folks could opt-in to different text measurements based on their needs. Tradeoff here is more scope so maintenance/support increases as well as user education ("Which should I use?"). But I think it'd be worth it for vx not to constrain folks to one strategy.

Fun stuff, worth exploring!

@hshoff hshoff changed the title Text measurement problems in browsers [text] Text measurement problems in browsers Oct 20, 2018
@sto3psl
Copy link
Contributor Author

sto3psl commented Oct 25, 2018

Seems like canvas is a bit slower than svg on initial page load vs refresh (maybe this is just my browser?)

@hshoff I added some speed measurement to https://beta.observablehq.com/@sto3psl/text-measurement-in-the-browser. It now displays how fast every line got measured and how long it took to measure all lines. For individual lines the difference isn't that big of a deal but if you start measuring a lot of lines it adds up. Here you can see that ctx.measureText() is much faster than the other options.

Chrome 70

screenshot 2018-10-25 at 14 49 33

Firefox 62

screenshot 2018-10-25 at 14 49 23

I think it would be pretty reasonable to select a sane default and if the user needs a different measurement method we can give them an option in getStringWidth and a prop in @vx/text.

If I have some time later this week I might make some more benchmarks and profile with the chrome dev tools. Than we can also better consider the time used for paint and layout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants