Chart.js should trigger at most one forced reflow (ideally zero) upon initialization.
Current behavior
When the <canvas> has no width and height attributes, Chart.js currently causes multiple forced reflows upon initialization, probably due to interspersed reading and writing of DOM and CSS properties. This causes major slowdowns when there are many charts on a page.
Here's a devtools screenshot, showing the reflows as purple "Layout" bars:
In Chrome devtools's Performance tab, press the ⟳ reload icon
Open the Frame section
In the flame graph, zoom in on the main function call to see the re-layouts
Possible solution
Chart.js could perhaps batch all DOM/CSS reads and writes, so that we first do all the reads, then all the writes (see the section Avoid layout thrashing). This should bring the number of reflows down to one.
For use cases where a single page has many charts, this will still slow down page load, because every chart causes a reflow, for O(n) reflows in total.
To accommodate this use case, I'd suggest it might be worthwhile for Chart.js provide a mechanism to run the "read" phase (where we determine the size using getComputedStyle) separately from the "write" phase (where we set DOM/CSS attributes and draw the chart). That way, as a developer, I can batch-run the read phase on all my charts, and then batch-run the write phase on all of them, bringing the number of reflows back down to one.
This mechanism doesn't need to be super obvious to access. I think as long as it's documented on the Performance documentation page in a section like "Avoiding reflows when you have many charts", most people who need it will find it. The Performance page was the thing I checked first when I tried to solve this.
My current workaround is passing canvas.transferControlToOffscreen() instead of canvas to Chart.js, which causes all DOM/CSS writes to be ignored. This does mean that I have to do the sizing logic manually in my own code.
Expected behavior
Chart.js should trigger at most one forced reflow (ideally zero) upon initialization.
Current behavior
When the
<canvas>
has nowidth
andheight
attributes, Chart.js currently causes multiple forced reflows upon initialization, probably due to interspersed reading and writing of DOM and CSS properties. This causes major slowdowns when there are many charts on a page.Here's a devtools screenshot, showing the reflows as purple "Layout" bars:
Reproducible sample
https://codepen.io/joliss/pen/XWwvrJL
Optional extra steps/info to reproduce
main
function call to see the re-layoutsPossible solution
Chart.js could perhaps batch all DOM/CSS reads and writes, so that we first do all the reads, then all the writes (see the section Avoid layout thrashing). This should bring the number of reflows down to one.
For use cases where a single page has many charts, this will still slow down page load, because every chart causes a reflow, for O(n) reflows in total.
To accommodate this use case, I'd suggest it might be worthwhile for Chart.js provide a mechanism to run the "read" phase (where we determine the size using
getComputedStyle
) separately from the "write" phase (where we set DOM/CSS attributes and draw the chart). That way, as a developer, I can batch-run the read phase on all my charts, and then batch-run the write phase on all of them, bringing the number of reflows back down to one.This mechanism doesn't need to be super obvious to access. I think as long as it's documented on the Performance documentation page in a section like "Avoiding reflows when you have many charts", most people who need it will find it. The Performance page was the thing I checked first when I tried to solve this.
My current workaround is passing
canvas.transferControlToOffscreen()
instead ofcanvas
to Chart.js, which causes all DOM/CSS writes to be ignored. This does mean that I have to do the sizing logic manually in my own code.Context
No response
chart.js version
v4.4.3
Browser name and version
Chrome 126.0.6478.127
Link to your project
No response