html5 canvas绘制网络字体的常用方法


Posted in HTML / CSS onAugust 26, 2019

最近在用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提供了一个完整的事件系统钩子给开发者调用:

html5 canvas绘制网络字体的常用方法 

如果想要了解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文件已经加载完成,因此,在第一次访问的时候并不会生效:

html5 canvas绘制网络字体的常用方法 

但是你再刷新一下浏览器之后字体就生效了:

html5 canvas绘制网络字体的常用方法 

这是什么原因呢?我们来看一下刷新浏览器的网络请求:

html5 canvas绘制网络字体的常用方法 
 

可以看到后面的字体走的是缓存,因此可以字体可以绘制出来,但是如果将chrome调试的Disable cache勾选上,将缓存禁用掉,那么无论怎么刷新,字体都不会绘制出来。

html5 canvas绘制网络字体的常用方法 

有解决办法吗?答案是有的,使用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存在兼容性问题,来看具体表格:

html5 canvas绘制网络字体的常用方法 

想要对这个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绘制网络字体的常用方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

HTML / CSS 相关文章推荐
CSS3基础(RGBa、text-shadow、box-shadow、border-radius)
Nov 13 HTML / CSS
用CSS3实现背景渐变的方法
Jul 14 HTML / CSS
深入浅析css3 中display box使用方法
Nov 25 HTML / CSS
CSS3实现彩色进度条动画的示例
Oct 29 HTML / CSS
HTML5之消息通知的使用(Web Notification)
Oct 30 HTML / CSS
手对手的教你用canvas画一个简单的海报的方法示例
Dec 10 HTML / CSS
HTML5跳转小程序wx-open-launch-weapp的示例代码
Jul 16 HTML / CSS
Html5 webRTC简单实现视频调用的示例代码
Sep 23 HTML / CSS
HTML5适合的情人节礼物有纪念日期功能
Jan 25 HTML / CSS
奇妙的 CSS shapes(CSS图形)
Apr 05 HTML / CSS
html5表单的required属性使用
Jul 07 HTML / CSS
使用CSS实现一个搜索引擎的原理解析
Sep 25 HTML / CSS
HTML5超炫酷粒子效果的进度条的实现示例
Aug 23 #HTML / CSS
HTML5语义化元素你真的用对了吗
Aug 22 #HTML / CSS
解决HTML5中滚动到底部的事件问题
Aug 22 #HTML / CSS
手摸手教你用canvas实现给图片添加平铺水印的实现
Aug 20 #HTML / CSS
html5 canvas实现给图片添加平铺水印
Aug 20 #HTML / CSS
导出HTML5 Canvas图片并上传服务器功能
Aug 16 #HTML / CSS
HTML5自定义属性的问题分析
Aug 16 #HTML / CSS
You might like
PHP中读取文件的几个方法总结(推荐)
2016/06/03 PHP
ucenter中词语过滤原理分析
2016/07/13 PHP
ThinkPHP5框架实现简单的批量查询功能示例
2018/06/07 PHP
不用MOUSEMOVE也能滑动啊
2007/05/23 Javascript
javascript dom代码应用 简单的相册[firefox only]
2010/06/12 Javascript
上传的js验证(图片/文件的扩展名)
2013/04/25 Javascript
jquery中animate的stop()方法作用实例分析
2015/01/30 Javascript
深入浅出理解javaScript原型链
2015/05/09 Javascript
JavaScript实现身份证验证代码
2016/02/17 Javascript
即将发布的jQuery 3 有哪些新特性
2016/04/14 Javascript
通过bootstrap全面学习less
2016/11/09 Javascript
Vue Spa切换页面时更改标题的实例代码
2017/07/15 Javascript
nodejs微信扫码支付功能实现
2018/02/17 NodeJs
jquery实现的简单轮播图功能【适合新手】
2018/08/17 jQuery
angularjs性能优化的方法
2018/09/05 Javascript
vue中@change兼容问题详解
2019/10/25 Javascript
vue 自定义组件的写法与用法详解
2020/03/04 Javascript
Vue实现input宽度随文字长度自适应操作
2020/07/29 Javascript
js实现幻灯片轮播图
2020/08/14 Javascript
[07:47]DOTA2国际邀请赛采访专栏:探访Valve总部
2013/08/08 DOTA
[09:33]2015国际邀请赛第四日TOP10
2015/08/08 DOTA
Python导入txt数据到mysql的方法
2015/04/08 Python
在python中实现对list求和及求积
2018/11/14 Python
python中update的基本使用方法详解
2019/07/17 Python
django 控制页面跳转的例子
2019/08/06 Python
tensorflow之读取jpg图像长和宽实例
2020/06/18 Python
CSS3实例分享--超炫checkbox复选框和radio单选框
2014/09/01 HTML / CSS
CSS3中的常用选择器使用示例整理
2016/06/13 HTML / CSS
迪斯尼假期(欧洲、中东及非洲):Disney Holidays EMEA
2021/02/15 全球购物
标记环网Toke Ring IEEE802.5
2014/05/26 面试题
人事行政主管岗位职责
2013/12/22 职场文书
服务之星事迹材料
2014/05/03 职场文书
办理收楼委托书范本
2014/10/09 职场文书
生死抉择观后感
2015/06/09 职场文书
2016年寒假学习心得体会
2015/10/09 职场文书
oracle删除超过N天数据脚本的方法
2022/02/28 Oracle