呃,首先呢~
敝人小弟在下我今天仔细的思考了一下,决定这次还是再来一篇『中场休息
』科普文,等到明天再来继续磁力/引力
的部分
其实是因为刚好工作应接不暇来不及写新的案例 = = (嘘
这次的中场休息系列
,我们要来探讨的是要怎麽样在Canvas
上面绘制文字
。
讲到这边大概有很多人会觉得超级莫名其妙
:
阿不就是用ctx.fillText就解决了吗? 还要讨论什麽?
不要急嘛。
通常初次使用fillText,正常人应该会很直观的就这样写:
function text(ctx,textSource){
ctx.font = '50px serif';
ctx.fillStyle="black";
ctx.fillText(textSource,0,0);
}
(()=>{
const ctx = document.querySelector('canvas').getContext('2d') ;
text(ctx,'TEST')
})()
接着打开浏览器,然後就发现萤幕上面什麽都没出现 ~
为什麽?看起来该做的都做了啊,怎麽什麽都没长出来?
其实第一个原因就在於ctx.fillText
的第2 、 3个参数,这个x = 0, y = 0的基准点,其实预设并不是从该行文字
的左上角
作为顶点起算,而是从左下角
起算。
有些人接着说,『那这样是不是我随意地给Y
一个足够大的数值,就可以了?』
OK~那就改成这样
function text(ctx,textSource){
ctx.font = '50px serif';
ctx.fillStyle="black";
ctx.fillText(textSource,0,50);
}
(()=>{
const ctx = document.querySelector('canvas').getContext('2d') ;
text(ctx,'TEST')
})()
文字这样就出来了~!这样就可以打完收工了吗?! YAH! 今天真是EASY!
『错误。』
这边很明显的问题
就是50
这个数字是我们随便乱给的,实际上你并不知道Y应该要给多少才能够完整
且刚好
的把文字show出来。
那麽应该怎麽做呢?
请使用ctx.textBaseline
这个属性,ctx.textBaseline
是用来决定要把文字哪一处作为垂直渲染基准线
的property
,而当我们把ctx.textBaseline
设定在top
的时候,文字就会以上缘作为垂直渲染基准线
,这样就可以看到我们绘制的文字了~。
延伸阅读: MDN 上的 ctx.textBaseline: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline
而既然我们提到了垂直渲染基准线
,那肯定就也有水平渲染基准线
的设置方式~
那就是ctx.textAlign
,这个的用法其实就跟css
差不多~
延伸阅读: MDN 上的 ctx.textAlign: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
那今天就到这边了吗 ~ 好像也不怎麽难嘛哈哈~
『错误。』
眼比较尖的人可能会注意到~我们用fillText写出来的字,好像跟一般html打出来的文字比起来:
就是有那麽一点糊糊的
到这边可能就有些人开始翻文件找是不是有什麽反锯齿
啦~提升解析度
的property
~但是在找了一阵子之後才发现根本不如所想,接下来可能就开始怀疑是不是硬体效能
问题。
咦?你说我怎麽知道你心里在想什麽? 那当然是因为小弟我第一次用fillText时就是撞死在这面墙上 :P
不知道大家还记不记得我们在这个系列文
初期的时候有提到过:『一张宽度100px, 高度100px的canvas,它实际上就是100*100 = 10000个像素的集合体』。
记得啊。然後呢?
其实,浏览器画面本身也可以看作是一个比较大号的Canvas
,但不同的点之一
就在於它的像素密度
可能比一般的Canvas
还要高。
为什麽说『可能』呢,原因其实就是我们刚刚提到的硬体差异
。
一般来说,如果使用者的电脑萤幕是Retina
萤幕,或是其他类型的高解析度
显示器,他的萤幕像素密度会是一般显示器,或是Canvas
的2倍
以上。
这就意味着在同样100x100
范围中绘制的文字,高解析度显示器
的浏览器画面实际上是显示了至少20000
个像素,这就导致用DOM
渲染的文字,画质远比用Canvas
渲染的文字来的清晰。
但是这个状况当然也有解决办法,那就是强制对Canvas进行压缩处理。
还记得我们之前有提到过用css的方式去扩大Canvas的尺寸会导致像素密度变低吗? 这边我们就是要逆转这个现象,首先把Canvas
的width/height属性都提高N
倍,然後再用css
去把style的width/height再缩减N
倍。
这麽一来,像素的密度就直接被提高N
倍了,而且Canvas
的长宽还不变。
接着可能有人会问:
有没有办法求得N实际上应该要给多少才够呢,给太大也不好吧?
这时候就该Window.devicePixelRatio
这个property
登场啦~
延伸阅读: MDN上的Window.devicePixelRatio: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
Window.devicePixelRatio
这个property
就是可以用来侦测当前的显示器像素密度值,例如,Macbook Pro
的Retina
萤幕的这个值会是2
,而其他种类的显示器也有不同的值。
妥善的运用Window.devicePixelRatio
,我们就可以在Canvas
上画出跟Dom
渲染文字具有同等水平解析度的文字~
到这边为止,我们已经学到怎麽用Canvas去画一行清晰的文字
,但是实际上我们今天的内容~
『还没有结束。』
我们今天的目标是「用Canvas精准的写出一个『字』」,但是我们从刚刚到现在,其实都还是在一张固定大小的Canvas
上绘制文字。
试想今天如果有一个需求:『如果我需要用Canvas
去画一个字,而画好字的canvas
,他的长宽尺寸
要完全贴合这个画出来的字,要怎麽办?』
碰到像这样的状况,就代表着我们需要获取『字』的『高度』/『宽度』等数据。
这时候可能就会有人怀疑:
有可能取得这些东西吗? 我在用DOM渲染文字的时候从没听说过有这种数据可以取得
基本上,api
其实都是应需求而生的,而在canvas
的世界中,想要去获取当下所渲染出来的一个文字的高度/宽度,当然也是合情合理~
这边要登场的就是ctx.measureText()
这个api
延伸阅读: MDN上的ctx.measureText: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/measureText
这个api
的用法就在於可以传入一个字串
,然後他就会根据当前ctx的font
属性设置的字体大小等参数,来回传一个TextMetrics
物件。
什麽是TextMetrics
物件? 这是一种包含了ctx
环境下渲染某字串
的各项视觉数值
的一个物件,除了基本的长宽
,还能透过部分数值计算出很多人在菜鸟时期可能都想要计算过的文字实际高度
(就是文字实际具有颜色的部分所占的高度,不是行高, 也不是X高~!)
延伸阅读: MDN上的TextMetrics物件介绍: https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
透过上述的方法,我们其实就可以利用Canvas
做出近似用DOM
渲染的文字,这样做的好处就是我们还可以对这样的Canvas
文字作进一步加工! 例如填充渐层
、填充素材图样
,甚至可以做出文字变形动画
!(然後再把做好的Canvas转成inline-block当成行内元素塞到其他元素当成段落文字的一部分)
以上就是我们第二篇
的中场休息
系列文,虽然是有点想放一些实作的案例,但是碍於时间问题没有完成(之前是有在公司专案实作过用Canvas做渐层文字的IE11 PolyFill~效果真的不错),总之还是希望大家喜欢这次的科普介绍~
<<: 连续 30 天 玩玩看 ProtoPie - Day 19
工程师太师了: 第16话 杂记: 今天终於是第三十天了, 漫长的三十天, 每天都要努力发文, 有监於...
"The Great Movie Experience" as Myron En...
(图源:Tim Pope's twitter) [系列文目录] 这篇文章会介绍一个VSCodeVi...
阮毋是喜爱虚华,阮只是环境来拖磨; 人客若叫阮,风雨嘛着行,为伊唱出留恋的情歌。 -- 流浪到淡水...
今天的内容将延续 上一篇 文章中 Operation Process 里的 3. ,同时我们会非常...