0%

canvas适配高清屏

最近又写了个canvas,发现绘制的界面文字有点糊,因为我使用的是4k的外接屏幕,所以是以前开发的时候没感觉,现在有感觉了。。。

canvas 模糊

原因

为啥模糊呢?我们可以把canvas渲染出的东西其实就是绘制的一张图片,不是矢量图,是位图。高dpi显示设备意味着每平方英寸有更多的像素。比如2k屏,浏览器就会以2个像素点来渲染一个像素。该canvas在Retina(视网膜)屏幕上相当于占据了2倍的空间,相当于图片被放大了一倍,因此绘制出来的文字会变得模糊。

解决思路

在canvas的context中存在一个backingStorePixelRatio的属性,但是目前来看已经废弃了,所以也没必要去了解了。

我们可以使用window.devicePixelRatio来查询设备的dpi。这个方法返回当前显示设备的物理像素分辨率与css像素分辨率之比。也可以理解为一个css像素的大小与一个物理像素的大小的比率。简单来说,它告诉浏览器应该使用多少屏幕实际像素来绘制单个css像素。

ps:当用户拖动浏览器到别的屏幕时,可以使用window.matchMedia()来检查devicePixelRatio的值是否发生改变。

具体可以查看MDN window.devicePixelRatio

因此,我们的方案是,获得设备的dpi(像素比),然后将canvas放大到该设备像素比来绘制,然后用css压缩到原来大小,即可显示高清图像。

开干!

准备一个id为canvas的dom:

1
<canvas id="canvas" width="800" height="200"></canvas>

获取context

1
2
3
4
const canvasEl = document.getElementById('canvas')
const context = canvasEl.getContext('2d')
// 存储canvas的真实大小
var canvasWidth, canvasHeight;

获取dpi的函数,如果window.devicePixelRatio获取失败就返回1:

1
2
3
function getDpi() {
return window.devicePixelRatio || 1;
}

设置canvas大小的方法:

1
2
3
4
5
6
7
8
9
function setCanvasWidth(canvasEl, ratio) {
canvasHeight = canvasEl.height;
canvasWidth = canvasEl.width;
canvasEl.style.width = canvasEl.width + 'px';
canvasEl.style.height = canvasEl.height + 'px';

canvasEl.width = canvasEl.width * ratio;
canvasEl.height = canvasEl.height * ratio;
}

这里使用了全局变量保存了原始的canvas的大小,这是为了在绘制的时候需要计算canvas大小的时候方便一点。

绘制:

1
2
3
4
5
6
7
8
9
function draw(canvasEl, content) {
context.clearRect(0, 0, canvasEl.width, canvasEl.height)
context.fillStyle = '#999'
context.fillRect(0, 0, canvasEl.width, canvasEl.height)
// 放置文字
context.fillStyle = '#fff'
context.font = "24px Arial";
context.fillText('很好,很精神', 20, 100)
}

最后开始调用这些方法:

1
2
3
4
var ratio = getDpi()
setCanvasWidth(ratio)
context.scale(ratio, ratio)
draw(canvasEl, context)

需要注意的是,我们最后使用context.scale(ratio, ratio)来对canvas进行了缩放。才最终实现了我们的目的。

最后看下结果:
canvas 高清屏


很有精神

码字辛苦,打赏个咖啡☕️可好?💘