解决 canvas 绘图在高清屏中的模糊问题

解决 canvas 绘图在高清屏中的模糊问题

为什么模糊

CSS 像素是一个抽象单位(1 px),浏览器根据某种规则将 css 像素转化为屏幕需要的实际像素值。

在高清屏之前,屏幕上显示一个像素点需要 1 x 1 个 css 像素。在高清屏,同样大小的屏幕上要显示一个点,就需要 n x 1 个 css 像素。这里的 n 就是设备像素比 devicePixelRatio >= 2.

也就是说,同样大小的区域,高清屏需要更多的 css 像素:css 像素不够,则会放大内容——变得模糊;css 像素足够,则会缩小内容——变得清晰。放大、缩小的比例由 devicePixelRatio 决定。

比如说 iPhone 4s,它的 devicePixelRatio 为 2,假设屏幕上有块区域大小为 100px x 100px,上面有张 100px x 100px大小的图片,那么这张图片会被放大 2 倍后再渲染到这块区域,所以看起来就模糊了。

canvas 绘图在高清屏中模糊

canvas 属于位图,绘制在它上面的文字、图片、线条也属于位图,经放大后就失真、显得模糊了。要解决这个问题,我们就需要 canvas 拥有更多的 css 像素,即让 canvas 足够大。多大才够呢?太大会不会浪费资源/性能?我们需要因地制宜,根据 devicePixelRatio 来决定画布的大小。

function setupCanvas(canvas) {
  var dpr = window.devicePixelRatio || 1
  var rect = canvas.getBoundingClientRect()

  canvas.width = rect.width * dpr
  canvas.height = rect.height * dpr

  var ctx = canvas.getContext('2d')
  ctx.scale(dpr, dpr)

  return ctx
}

// 现在我们只需要根据 UI 设计图绘制需要的内容
// 由于使用了 setupCanvas,绘制的内容在各种高清屏中表现清晰、一致
var ctx = setupCanvas(document.querySelector('.my-canvas'));
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();

在 setupCanvas 函数中,我们根据屏幕的 devicePixelRatio 对 canvas 画布本身进行放大,然后使用 ctx.scale() 放大 canvas 单位,这样在 ctx 上下文绘制的内容就会被放大,使得最后生成的图片清晰的显示在对应的屏幕上。

实际上,我们还要兼顾不同大小、不同分辨率的屏幕。一般设计师会给我们宽度为 375px 的设计图,这需要我们根据屏幕大小进行缩放:

function setupCanvas(canvas) {
  const UI_WIDTH = 375
  const DOC_WIDTH = document.documentElement.clientWidth
  const DPR = window.devicePixelRatio || 1
  let scale = (DPR * DOC_WIDTH / UI_WIDTH).toFIxed(2)
  //let rect = canvas.getBoundingClientRect()

  canvas.width = canvas.width * scale
  canvas.height = canvas.height * scale

  let ctx = canvas.getContext('2d')
  ctx.scale(scale, scale)

  return ctx
}

术语

device pixel

设备像素(又称物理像素、屏幕像素)是显示屏的最小物理单元,是我们在屏幕上能看到的最小点。

device-independent pixel

设备无关像素(又称密度无关像素,DIP)是一个抽象单位,表示计算机中的一个虚拟点,由系统转为一个设备像素点。

devicePixelRatio

设备像素比,它的值等于设备像素/设备无关像素,devicePixelRatio = DP/DIP

css pixel

css 像素是浏览器使用的抽象单位,属于设备无关像素(DIP)。我们看到的内容,是浏览器将 css 像素转化为设备像素后的结果。

矢量图

矢量图是根据几何特性来绘制图形,矢量可以是一个点或一条线,矢量图只能靠软件生成,文件占用内在空间较小,因为这种类型的图像文件包含独立的分离图像,可以自由无限制的重新组合。它的特点是放大后图像不会失真。

位图

位图图像(bitmap),亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。当放大位图时,图像就失真、模糊了。

引用

posted @ 2018-12-25 15:02  Liaofy  阅读(6535)  评论(0编辑  收藏  举报