SeregPie / THREE.TextTexture

A texture with the drawn text.
MIT License
72 stars 9 forks source link

Trying to use custom font on startup, often shows the browser's default font #15

Open derolf opened 2 years ago

derolf commented 2 years ago

I am loading the Roboto font in index.html:

<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet" />

Then trying to use it in a TextSprite:

 const instance = new TextSprite({
    alignment: "left",
    color: "#24ff00",
    fontFamily: "Roboto",
    fontSize: 1,
    text: text,
  });

Sometimes, the TextSprite renders the browser's default font instead of Roboto. Any idea to safely wait for Roboto?

Filyus commented 2 years ago

document.fonts.load (used in THREE.TextTexture): https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/load https://stackoverflow.com/a/32292880

Libs to wait for font loading: https://github.com/bramstein/fontfaceobserver and https://fontfaceobserver.com/ (6 KB) https://github.com/typekit/webfontloader (old, 13 KB)

Libs to get font metrics: https://github.com/foliojs/fontkit https://github.com/opentypejs/opentype.js and https://opentype.js.org/ (170 KB) https://github.com/Pomax/lib-font (not so popular, 80 KB) https://github.com/rsms/fontkit (with WASM) https://github.com/soulwire/FontMetrics (old, 2 KB)

Metrics explanation: https://freetype.org/freetype2/docs/glyphs/glyphs-3.html https://soulwire.github.io/FontMetrics/

TextMetrics: https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics https://stackoverflow.com/a/67698040

Another way: https://threejs.org/docs/#examples/en/loaders/FontLoader https://github.com/gero3/facetype.js

Filyus commented 2 years ago

Possible solution from https://stackoverflow.com/a/64192936:

export async function waitForFontLoad(
    font: string,
    timeout = 1000,
    interval = 10
) {
    return new Promise((resolve, reject) => {
        // repeatedly poll check
        const poller = setInterval(async () => {
            try {
                await document.fonts.load(font);
            } catch (err) {
                reject(err);
            }
            if (document.fonts.check(font)) {
                clearInterval(poller);
                resolve(true);
            }
        }, interval);
        setTimeout(() => clearInterval(poller), timeout);
    });
}
Filyus commented 2 years ago

Recommendation to use document.fonts.onloadingdone instead.