4

场景

在移动端通过 H5 的 canvas 标签绘制图表的时候,不经过任何处理的图表相比较其他元素看起来会有些模糊。

先看下面一组高分屏下的圆,上面是普通 div 元素“绘制”的圆,下面是通过 canvas 绘制的圆。可以看出,下面的圆相比较是模糊的。

在这里插入图片描述

为什么会这样?

一台普通屏幕上的像素(逻辑像素),可以当做是正常的像素(css中设置的像素),当画一个100px的元素,他就是一个100px的元素。

但是,在出现了一些高分辨率的屏幕之后,就发生了一些变化。随之也出现了一个属性 devicePixelRatio ,它允许我们去查询设备屏幕的像素比。高分屏下(假设devicePixelRatio为3),在css设置的100px(逻辑像素),实际渲染的是300px的物理像素

而不管是否为高分屏, canvas 中的单位 1 (逻辑像素),就是 1 物理像素,所以在高分屏下,canvas 绘制的图片看起来就模糊了(可以想象成,一张清晰度正常的普通图片为了布满整个背景被强行放大 n 倍,所以看起来模糊了)。

如何处理?

这个涉及到 canvas 标签的一些特性。即 canvas 元素的大小(宽高)会影响 canvas 画布的内容

举个栗子:

画一个半径为 50 的圆,画布默认宽高为 300 * 150 ,不设置 canvas 元素宽高的情况下是一个圆;如果设置 canvas 元素的宽高都为 150, 那么画布 x 轴方向的内容会被压缩,为原来的 1/2 倍。

在这里插入图片描述在这里插入图片描述

那么,利用这个特性。

思路: 高分屏下(假设devicePixelRatio为 3,逻辑像素为 100px),将 canvas 画布大小 [乘以 3] 转换成实际像素(物理像素)大小,然后通过css设置 canvas 元素的大小 为逻辑像素大小 [100px]。缩放后,画布内容就是高清的了。但是这个时候画布内容是缩小的,这个时候可以使用 canvas 的 scale() 去进行放大 3 倍就可以了。

注释:canvas 的 scale() 的方法在 放大/缩小 canvas 时,不会改变内容素质,可以理解为清晰度不会变。

实现解读

参考图片:一张普通的图片,为了占满背景,被强行放大,导致有点模糊。为了显示更清晰,那么就设置更小的宽高。但是为了占满背景,就又进行一次不会改变图片素质的等比放大。

代码实现

// 仅练习
class DprCanvas {
  constructor(id) {
    const canvas = document.getElementById(id)
    const ctx = canvas.getContext('2d')
    const dpr = window.devicePixelRatio
    const logicalWidth = canvas.width
    const logicalHeight = canvas.height

    canvas.width = logicalWidth * dpr
    canvas.height = logicalHeight * dpr
    canvas.style.width = logicalWidth + 'px'
    canvas.style.height = logicalHeight + 'px'

    ctx.scale(dpr, dpr)
    this.draw(ctx)
  }
  draw(ctx) {
    ctx.beginPath()
    ctx.fillStyle = 'darkcyan'
    ctx.arc(50, 50, 50, 0, Math.PI * 2)
    ctx.fill()
  }
}

效果

在这里插入图片描述


艾欢欢
410 声望20 粉丝