高 DPI 画布

Paul Lewis

简介

HiDPI 屏幕非常精美,会让一切看起来更流畅、更清晰。但是,它们也给开发者带来了一系列新挑战。在本文中,我们将探讨在 HiDPI 屏幕环境中在画布中绘制图像的独特挑战。

devicePixelRatio 属性

我们从头开始吧。在我们推出 HiDPI 屏幕之前,一个像素是一个像素(如果我们略微忽略缩放和缩放),您并不需要进行任何更改。如果您将某个对象设置为 100px 宽,就足够了。后来,前几部 HiDPI 移动手机开始弹出,窗口对象上具有略显神秘的 devicePixelRatio 属性,可用于媒体查询。通过该属性,我们可以了解像素值(我们称之为逻辑像素值)的比率,例如 CSS 转换为设备在渲染时会使用的实际像素数。对于 devicePixelRatio 为 2 的 iPhone 4S,您会看到 100px 逻辑值等于 200px 设备值。

这很有趣,但对我们的开发者来说又意味着什么呢?早期,我们都开始注意到图像被这些设备放大。我们以元素的逻辑像素宽度创建图像,当它们绘制出来时,被 devicePixelRatio 放大,从而变得模糊。

图片因 devicePixelRatio 而被放大和模糊处理
图 1 - 图片因 devicePixelRatio 而放大和模糊处理

事实上,此问题的解决方案是创建由 devicePixelRatio 放大的图像,然后使用 CSS 将其缩小相同的幅度,画布也是如此!

function setupCanvas(canvas) {
  // Get the device pixel ratio, falling back to 1.
  var dpr = window.devicePixelRatio || 1;
  // Get the size of the canvas in CSS pixels.
  var rect = canvas.getBoundingClientRect();
  // Give the canvas pixel dimensions of their CSS
  // size * the device pixel ratio.
  canvas.width = rect.width * dpr;
  canvas.height = rect.height * dpr;
  var ctx = canvas.getContext('2d');
  // Scale all drawing operations by the dpr, so you
  // don't have to worry about the difference.
  ctx.scale(dpr, dpr);
  return ctx;
}

// Now this line will be the same size on the page
// but will look sharper on high-DPI devices!
var ctx = setupCanvas(document.querySelector('.my-canvas'));
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();