Preloading font-face using canvas

The problem

General routine for loading resources in javascript goes like that:

var image = new Image;
image.onload = function() { /* some onReady callback */ };
image.src = "nude-princess-peach.png";

But for WebFonts there is no corresponding object which makes it kind of difficult – especially when you want to write pure canvas app (for example compatible with CocoonJS)

The solution

First of – in chrome – using context.fillText with not-yet-loaded font-face – will execute properly – but with absolutely no visual result. So the basic idea is to set a timer which will be calling a drawing function until something actually appears on canvas. Detect the change. That’s it :)

As for firefox – if the font is not yet loaded it will fall back to default one which is “10px sans-serif” now to detect the change we just need to check if after assignment the font is still “10px sans-serif”.

The implementation

live example

There are many ways to detect that change – I will use cq.trim() but you can easily write any other method from scratch.

So basically – if I call a trim method on an empty image – it will not be trimmed at all – ergo – its dimensions will stay intact.

Code

I like to keep the same routine as in image or audio – so I am going to create object representing a font.

var WebFont = function(fontName) {

  /* create some canvas that will be used to check
     if the font has been loaded */

  var placeholder = cq(64, 64);

  /* setup check timer */

  var timer = setInterval(function() {    

    /* save previous height */

    var previousHeight = placeholder.canvas.height;

    /* try to draw some text */

    placeholder.clear().font("32px " + fontName).fillText("test", 32, 32).trim();

    /* check for changes */

    if((window.mozIndexedDB && placeholder.context.font !== "10px sans-serif") || (!window.mozIndexedDB && placeholder.canvas.height !== previousHeight)) {
    
      /* eventually run ready callback and clear the timer */

      this.onload();
      clearInterval(timer);
    }
    
  }, 500);
}

Usage

example css:

@import url(http://fonts.googleapis.com/css?family=Kavoon);

example js:

var font = new WebFont("Kavoon");
font.onload = function() { alert("Font has been loaded"); }

live example

I am using this method in my WIP simploader.js see example usage here