0

This is my type font:
@font-face {font-family: "myicon";/*...*/}
And the content for my icon in css is:
content: "\e000";
My Js code:
ctx.font = '13.5pt myicon'; ctx.fillText("\ue000",90, 101); //not working

can you explain me where is the problem ? why not print the icon ? (Sorry for my bad english)

zzingo
  • 1

2 Answers2

2

Although you can use script such as the one markE mentions, you can also just paste in a small snippet that waits for the font to load.

The script will test by doing:

  • Create an internal canvas, draw default font to it and store its pixels
  • Try to set the font you want at intervals, draw it and extract its pixels
  • If there is no difference at pixel level, wait more
  • At first pixel difference, we have a new font loaded (presumably)
  • If timed out (here 3 sec) it will call error callback

A live example:

hasFont("Open Sans", function() {
  document.body.innerHTML += " OK<br>Loading font..."

  // unknown font:
  hasFont("xFontoY", function() {
    document.body.innerHTML += " OK"
  }, function() {
    document.body.innerHTML += " Not loaded"
  });
  
}, function() {
  document.body.innerHTML += " Not loaded"
});

function hasFont(fontName, callback, error) {

  var canvas = document.createElement("canvas"),
      ctx = canvas.getContext("2d"),
      w = 60, h = 20,                             // affects accuracy
      delay = 50, maxTests = (1000 / delay) * 3,  // 3 sec @ 50ms intervals
      initial = getPixels("sans-serif");
  
  canvas.width = w; canvas.height = h;

  // test
  (function test() {
    var px = getPixels(fontName), len = px.length, i = 0;
    for(; i < len; i++) {
      if (initial[i] !== px[i]) {callback(fontName);return}
    }
    
    if (--maxTests) setTimeout(test, delay);
    else {if (error) error(fontName)}
  })();
  
  function getPixels(fontName) {
    ctx.clearRect(0, 0, w, h);
    ctx.font = h + "px " + fontName + ", sans-serif";
    ctx.fillText("aWm", 0, h);
    return new Uint32Array(ctx.getImageData(0, 0, w, h).data.buffer);
  }
}
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'), local('OpenSans'), url(https://fonts.gstatic.com/s/opensans/v10/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2) format('woff2'), url(https://fonts.gstatic.com/s/opensans/v10/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
}
canvas {border:1px solid #000}
Loading font...

Feel free to rewrite it to take options, promise etc.

  • Upvote for an Interesting & Very Direct (!) approach. You're literally examining whether the pixels on the text sample have changed. If I could suggest an efficiency: downsize the created canvas to approximately the size of the text...that way you don't have to test 300x150 pixels during each "no-change" test cycle – markE Feb 19 '15 at 16:54
  • @markE thanks!. Oh, check this line: `getImageData(0, 0, 60, 20)`. –  Feb 19 '15 at 19:25
  • Ah, yes...I see you've already got the test area reduced to 60x20. Maybe I need glasses! – markE Feb 19 '15 at 19:39
  • @markE but yes, there are tweaks that can be done here. I made it more as a proof-of-concept in the SO editor. –  Feb 19 '15 at 19:39
  • 1
    @markE I thought you already had glasses!? or maybe it's my memory... :p –  Feb 19 '15 at 19:40
0

External Fonts (like images) are loaded asynchronously.

So you are trying to use the font before it is fully loaded.

There are many scripts to do this. One good one is TypeScript's WebFontLoader:

https://github.com/typekit/webfontloader#events

markE
  • 102,905
  • 11
  • 164
  • 176