这两天帮别人利用canvas做一个简单的文字动画,碰到了一些问题。将自己踩坑和解决的思路记录如下。
关于使用 “canvas + 外部字体” 绘制文字动画,窗体加载时,初绘制的字体是默认字体的问题说明:
这个问题的发生主要是html外部字体的加载机制造成的。如果html文档中没有使用该字体的文字,则外部字体文件不会被加载出来,只有到被使用的时候才会被加载。
1、最简单的解决思路就是在html中加入文字,并设置为该字体。
2、另一个思路就是,既然你没有被加载,那我就在绘制之前先去把你加载出来。这里采用了元素做一个字体的预加载。但这里有个问题,预加载的时候会涉及到“作为本地file”运行和“在IDE开发环境与服务器环境中以"http/https"请求的模式运行”。
<link rel="preload" href="./a.ttf" as="font" type="font/ttf">
第二种情况下需要在预加载参数中设置"crossorigin = anonymous"。
<link rel="preload" href="./a.ttf" as="font" type="font/ttf" crossOrigin = "anonymous"">
但如果直接在html文件的元素中写,那么在本地和在服务器的情况就无法兼顾。 这里我想到的是用js去添加这个元素,根据请求的protocol类型(window.location.protocol属性)来判断。但问题是当整个文件加载完成,也就是window.onload()方法已经执行完必,draw方法已经被调用,这样做是无意义的。
因此,我们需要研究一下浏览器解析html文件的过程,找到一个js里可以操作,并且生命周期在window.onload()之前的方法。经过查阅可知,document.onreadystatechange()事件监听器+document.readystate可满足上述需求。且当document.readystate = “interactive” 时,既可以对Dom对象操作,其生命周期也在window.onload()之前。故在js中添加如下代码。
window.document.onreadystatechange = function () {
console.log("recent ready state: " + document.readyState + " " + this.readyState)
if(window.document.readyState === "interactive"){
let link = document.createElement("link");
link.rel = "preload";
link.href = "./a.ttf";
link.as = "font";
link.type = "font/ttf";
if(window.location.protocol.split(':')[0] === "http" || window.location.protocol.split(':')[0] === "https"){
link.crossOrigin = "anonymous";
}
document.getElementsByTagName("head")[0].insertAdjacentElement("afterbegin", link);
}