最近在用canvas绘图时遇到了一个令人头痛的问题:canvas绘制网络字体时没效果,遂开始了一番解决方案查找测试,中间也碰到了不少坑,于是写下此篇文章做个总结,如果大家在用canvas时遇到了同样的问题,希望对大家有一定的帮助,接下来就来看看有哪几种解决办法
服务端转换
服务端转换是什么意思呢?直接把内容和需要的字体传递给服务端,服务端提供一个文字转图片的接口,将字体转换成图片,然后在canvas中直接绘制图片,这样就能保证绘制网络字体不会有问题,不会有任何的兼容性问题,但是这样做也就意味着服务端的工作会变多,同时如果文字内容是可以被用户编辑修改的,那就意味着用户每操作一次,都要请求一次接口,然后重新绘制一次图片,这样会导致网络开销增加,如果不想要服务端的介入,那就看看下面的解决方案
webfontloader
webfontloader是一个由Google和Typekit共同开发的组件库,提供了一组标准事件监听字体的加载,虽然已经很长时间没有更新了,但是对字体加载的监听确实有效,下面来看一个具体的例子怎么使用:
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) } })
首先通过require引入webfontloader,并且动态插入一个script标签载入google的字体,然后调用webfontloader的load方法进行配置监听,当字体加载完成后就会触发active钩子,开始绘制对应字体的内容,webfontloader提供了一个完整的事件系统钩子给开发者调用:
如果想要了解webfontloader的更多用法可以前往 github 查看学习,如果你觉得为了绘制网络字体需要引入一个js库有点得不偿失,没关系,接下来向你接受不用库的方法
document.fonts.load
如果你在Google上搜索canvas加载网络字体,你一定能搜到下面这个方案:
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) }
这个方案存在一点问题,当image onerror事件触发的时候,并不能保证字体已经加载完成,只能保证css文件已经加载完成,因此,在第一次访问的时候并不会生效:
但是你再刷新一下浏览器之后字体就生效了:
这是什么原因呢?我们来看一下刷新浏览器的网络请求:
可以看到后面的字体走的是缓存,因此可以字体可以绘制出来,但是如果将chrome调试的Disable cache勾选上,将缓存禁用掉,那么无论怎么刷新,字体都不会绘制出来。
有解决办法吗?答案是有的,使用Font Load API进行加载,来看具体代码:
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) }) }
先用image的onerror事件trick css文件的加载,然后调用document.fonts.load看字体是否加载完成,这样就可以准确监听到字体加载完成,但是这个api存在兼容性问题,来看具体表格:
想要对这个api了解更多,可以前往 mdn 查看
对比绘制
对比绘制是什么意思呢?就是先设置一个没有的字体,然后在设置我们需要的字体进行对比,来看具体代码:
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()
首先设置一个没有的字体,绘制上去,然后拿到对应区域的渲染数据,然后再将渲染区域清除然后,然后再设置我们需要的字体,拿到对应区域的渲染数据,然后实时对比,当渲染数据一样时,表示绘制的都是系统默认字体,我们需要的字体没有渲染出来,然后执行requestAnimationFrame
再执行detect检测方法,直到渲染数据不一样,就表示我们需要的字体已经渲染完成
总结
以上所述是小编给大家介绍的html5 canvas绘制网络字体的常用方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
更新动态
- 群星-时尚慢摇DJ舞曲《发烧车载中文天碟-调情》非卖品[WAV]
- 潘美辰.2008-全新重声大碟(出道20年精选纪念版)【倍特音乐】【WAV+CUE】
- 罗时丰.2002-唱歌的人(2011再生版)【贝特音乐】【WAV+CUE】
- 罗时丰.2003-唱歌的人台语精选+新歌【贝特音乐】【WAV+CUE】
- 999PUNKSTA《情绪数码故障》[Hi-Res][24bit 48kHz][FLAC/分轨][301.83MB]
- HOYO-MiX《原神-珍珠之歌4 游戏音乐》[320K/MP3][289.48MB]
- 陈崎凡《CHEN》[320K/MP3][81.13MB]
- skt都在哪一年夺冠 英雄联盟skt夺冠赛季介绍
- 炉石传说抢先体验乱斗什么时候结束 深暗领域体验乱斗结束时间
- 炉石传说抢先乱斗卡组有什么 深暗领域抢先体验乱斗卡组推荐
- 荣耀手机腕上最佳搭档 荣耀手表5首销开启
- 雷克沙ARES 6000 C28战神之翼 AMD 9800X3D超强搭档
- 咪咕快游感恩同游,超值回馈尽在咪咕咪粉节!
- 陈崎凡《CHEN》[FLAC/分轨][326.32MB]
- 群星《我们的歌第六季 第2期》[320K/MP3][74.05MB]