GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix: Recalculate bounding boxes after fonts load by camdecoster · Pull Request #8094 · plotly/plotly.js

Conversation

@camdecoster

@camdecoster camdecoster commented Sep 30, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Description

Recalculate bounding boxes after fonts load to ensure they are sized properly.

Closes #8089.

Changes

  • Track which fonts aren't loaded yet and redraw when they settle
  • Clean up tracking token during purge
  • Add tests
  • Update internal type
  • Add utility for parsing font families

Screenshots

Before After
image image

Testing

  • Be on main
  • Open plotly devtools and paste the following into the browser devtools console:
    // A new family and URL on every run, so the plot always draws before the font arrives
    const family = `JetBrainsMono${Date.now()}`;
    const face = new FontFace(
        family,
        `url(https://cdn.jsdelivr.net/npm/@fontsource/[email protected]/files/jetbrains-mono-latin-400-normal.woff2?v=${Math.random()})`
    );
    document.fonts.add(face);
    
    const gd = Tabs.fresh();
    Plotly.newPlot(
        gd,
        [
            { type: 'bar', x: ['NO', 'DE', 'CA'], y: [30, 12, 10], name: 'Gold: a test of sizes' },
            { type: 'bar', x: ['NO', 'DE', 'CA'], y: [8, 10, 5], name: 'Silver: a second test of sizes' }
        ],
        {
            font: { family, size: 13 },
            legend: { borderwidth: 1, x: 0.02, y: 0.98 },
            width: 500,
            height: 300,
            annotations: [
                {
                    x: 1.02, y: 0, xref: 'paper', yref: 'paper', xanchor: 'left', yanchor: 'bottom',
                    text: 'Source: official list', textangle: -90, showarrow: false,
                    bgcolor: 'rgba(0,0,0,0.15)', borderwidth: 1
                }
            ]
        }
    );
  • Note that the text boxes have the incorrect sizes
  • Switch to this branch
  • Run the snippet again
  • Note that the text boxes have the correct sizes

Notes

  • The first draw is synchronous, so plots with no specified fonts shouldn't see any change with this update
  • Plots with fonts specified that are drawn before the fonts load will be redrawn after those fonts load
    • The redraw costs about as much as the first draw
    • It happens once per font load
    • Here are some performance numbers from Chrome running locally:
      Plots First draw Redraws after the font loads
      1 small bar chart 18 ms 21 ms
      20 small bar charts (3 runs) 112-139 ms 94-185 ms
      1 plot with a 50,000-point SVG scatter 596 ms 593 ms
      20 plots with a 5,000-point SVG scatter each 1.6 s 1.3 s
    • The redraws run synchronously in one task.
  • Plots with fonts specified that are drawn after the fonts load will be drawn once with the correct sizes
  • Purged plots don't get redrawn
  • The redraw fires plotly_beforeplot and plotly_afterplot again
  • To skip the extra draw, wait for the font before the first draw:
    await document.fonts.load('12px "Open Sans"');
    await Plotly.newPlot(gd, data, layout);
  • document.fonts.ready does not work for this, because ready does not start the load of a font that no text uses yet
  • A WebKit bug prevents use of the loadingdone event on the document fonts
  • This fix does not cover text drawn on a canvas, such as scattergl text and gl3d labels. A plot redraws only when an SVG element in the plot uses the loaded family.
  • This fix is related to Axis labels and tick labels in 3D plots do not use fonts loaded from remote server #7413, but it doesn't actually fix that issue. gl-axes3d caches each label mesh by font family for the life of the page, so gl3d labels keep the fallback font after the redraw.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
camdecoster added 6 commits September 30, 2026 07:28
@camdecoster
fix: Recalculate bboxes after fonts load
37330b9
@camdecoster
Add tests
351fe89
@camdecoster
Update internal GraphDiv type
dd658b1
@camdecoster
Add draftlog
aa44890
@camdecoster
Use promises for tracking font loading because of Safari limitations
b2aa6c2
@camdecoster
Be more general in font check
c281d99
@camdecoster
camdecoster marked this pull request as ready for review September 30, 2026 23:17
alexcjohnson
alexcjohnson reviewed Oct 1, 2026
View reviewed changes
Comment thread src/types/core/graph-div.internal.d.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

alexcjohnson
alexcjohnson reviewed Oct 1, 2026
View reviewed changes
Comment thread src/plot_api/plot_api.js
*/
async function redrawAfterFontLoads(gd, unloadedFaces) {
// The draw started these loads, or they finished during the draw
const faces = unloadedFaces.filter((face) => ['loaded', 'loading'].includes(face.status));

@alexcjohnson alexcjohnson Oct 1, 2026

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

So the other options apparently are unloaded and error (or possibly failed, MDN is inconsistent about this). Makes sense to ignore errors at this point, as there's nothing more to wait for. Can we be confident that every relevant font will have been transitioned from unloaded to loading synchronously? I guess we have to assume this, as looking at an existing site I see various fonts staying indefinitely in the unloaded state, presumably because it was declared but never used on the page.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@camdecoster camdecoster Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I think we can be confident in this. That's why my testing showed. If real world use tells a different story, we can tweak the check (or force the fonts to load ourselves).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
alexcjohnson
alexcjohnson approved these changes Oct 1, 2026
View reviewed changes
@camdecoster
camdecoster merged commit 67cc7fa into main Oct 2, 2026
88 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@camdecoster
camdecoster deleted the cam/8089/replot-after-font-load branch October 2, 2026 12:00
@camdecoster camdecoster mentioned this pull request Oct 2, 2026
[BUG]: Text first drawn outside a full redraw keeps fallback font sizes after its web font loads #8099
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@alexcjohnson alexcjohnson alexcjohnson approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

[BUG]: Text extents are not recomputed after web font loading

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@camdecoster @alexcjohnson
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.