Several Methods of Drawing Network Font by canvas

Keywords: Javascript network Google github

Recently, when drawing with canvas, we encountered a headache problem: when canvas rendered network fonts, it did not work, so we started a solution search test, and encountered many pits in the middle. So we wrote this article to summarize. If you encounter the same problem when using canvas, we hope to have a certain degree for you. Now let's see what solutions are available.

Server-side transformation

What does server-side conversion mean? To transfer the content and fonts directly to the server, the server provides an interface for text to picture, converts fonts to pictures, and then draws pictures directly in canvas, which can ensure that there will be no problem in drawing network fonts and no compatibility problems, but doing so also means the server. There will be more work, and if the text content can be edited and modified by the user, it means that every time the user operates, he requests an interface, and then redraw the picture. This will lead to increased network overhead. If you don't want the involvement of the server, then look at the following solutions

webfontloader

webfontloader is a component library developed by Google and Typekit. It provides a set of standard event monitoring fonts. Although it has not been updated for a long time, it is effective to monitor font loading. Here is a specific example of how to use it:

var WebFont = require('webfontloader')
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
var link = document.createElement('link')
link.rel = 'stylesheet'
link.type = 'text/css'
link.href = 'http://fonts.googleapis.com/css?family=Vast+Shadow'
document.getElementsByTagName('head')[0].appendChild(link)
WebFont.load({
  custom: {
    families: ['Vast Shadow']
  },
  active: function () {
    ctx.font = '50px "Vast Shadow"'
    ctx.textBaseline = 'top'
    ctx.fillText('123', 20, 10)
  }
})

First, webfont loader is introduced through require, and a script tag is dynamically inserted into the font of google. Then the load method of webfont loader is called to configure and listen. When the font is loaded, the active hook is triggered and the corresponding font content is drawn. webfont loader provides a complete event system hook. The child calls to the developer:


If you want to know more about the use of webfont loader, you can go to github Look at the learning. If you think it's a bit worthwhile to introduce a js Library in order to draw web fonts, it doesn't matter. Next, accept the method of not using the library.

document.fonts.load

If you search for canvas loaded web fonts on Google, you can definitely find the following scenario:

var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
var link = document.createElement('link')
link.rel = 'stylesheet'
link.type = 'text/css'
link.href = 'http://fonts.googleapis.com/css?family=Vast+Shadow'
document.getElementsByTagName('head')[0].appendChild(link)
var image = document.createElement('img')
image.src = link.href
image.onerror = () => {
  ctx.font = '50px "Vast Shadow"'
  ctx.textBaseline = 'top'
  ctx.fillText('123', 20, 10)
}

There is a problem with this scheme. When the image onerror event triggers, it can not guarantee that the font has been loaded. It can only guarantee that the css file has been loaded. Therefore, it will not take effect on the first visit:

But when you refresh the browser again, the font takes effect:

What is the reason for this? Let's take a look at the network request to refresh the browser:

You can see that the font behind is cached, so the font can be drawn, but if you check Daisable cache debugged by chrome and disable the cache, no matter how refreshed, the font will not be drawn.

Is there a solution? The answer is yes, use the Font Load API to load, to see the specific code:

var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
var link = document.createElement('link')
link.rel = 'stylesheet'
link.type = 'text/css'
link.href = 'http://fonts.googleapis.com/css?family=Vast+Shadow'
document.getElementsByTagName('head')[0].appendChild(link)
var image = document.createElement('img')
image.src = link.href
image.onerror = () => {
  document.fonts.load('50px Vast Shadow', '123').then(() => {
    ctx.font = '50px "Vast Shadow"'
    ctx.textBaseline = 'top'
    ctx.fillText('123', 20, 10)
  })
}

First use image onerror event trick css file loading, then call document.fonts.load to see if the font is loaded, so that you can accurately monitor the font loading, but this api has compatibility problems, see the specific table:

To learn more about this api, you can go to mdn See

Contrast Drawing

What does contrast drawing mean? It is to set up a font that does not exist, and then set the font we need to compare, to see the specific code:

var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
var link = document.createElement('link')
link.rel = 'stylesheet'
link.type = 'text/css'
link.href = 'http://fonts.googleapis.com/css?family=Vast+Shadow'
document.getElementsByTagName('head')[0].appendChild(link)
ctx.font = '50px UNKNOW'
ctx.textBaseline = 'top'
ctx.fillText('123', 20, 10)
var dataDefault = ctx.getImageData(20, 10, 50, 50).data
ctx.clearRect(20, 10, 100, 100)
var detect = () => {
  ctx.font = '50px "Vast Shadow"'
  ctx.textBaseline = 'top'
  ctx.fillText('123', 20, 10)
  var dataNow = ctx.getImageData(20, 10, 50, 50).data
  if ([].slice.call(dataNow).join('') === [].slice.call(dataDefault).join('')) {
    ctx.clearRect(20, 10, 100, 100)
    requestAnimationFrame(detect)
  }
}
detect()

Firstly, set a font that is not available, draw it, then get the rendering data of the corresponding area, then clear the rendering area, then set the font we need, get the rendering data of the corresponding area, and then compare it in real time. When the rendering data is the same, the rendering is the default font of the system. The font we need is not rendered, then we execute the request Animation Frame and detect detection method, until the rendering data is different, it means that the font we need has been rendered.

summary

This article introduces several common methods of drawing network fonts by canvas. Each method has its own advantages and disadvantages. I hope it will be helpful to you. When used, it is selected according to the specific situation.
If there are mistakes or inaccuracies, you are welcome to criticize and correct, if you like, you are welcome to praise.

Posted by lmaster on Sun, 25 Aug 2019 07:13:49 -0700