高 DPI 畫布

Paul Lewis

簡介

HiDPI 螢幕很棒,能讓畫面看起來更流暢、更清晰。但也為開發人員帶來了新的挑戰。本文將探討在 HiDPI 螢幕上繪圖時,在畫布上繪圖的獨特挑戰。

devicePixelRatio 屬性

讓我們先從一開始。在我們推出高解析度螢幕之前,像素就是像素 (如果我們略過縮放和調整大小),您不必進行任何變更。如果您將某個項目的寬度設為 100 像素,那麼就只有這個寬度。接著,前幾部 HiDPI 手機手上就開始彈出視窗物件上的 PixelRatio 屬性,以供媒體查詢使用。這個屬性讓我們能夠瞭解像素值 (我們稱為邏輯像素值) 的比例,比方說:CSS 會轉譯成裝置實際使用像素的「實際」像素數量。以 iPhone 4S 為例,其 devicePixelRatio 為 2,因此 100 px 的邏輯值等同於 200 px 的裝置值。

這很有趣,但對開發人員來說有何意義?我們一開始就發現,這些裝置會將圖片調大。我們以元素的邏輯像素寬度建立圖片,當圖片繪製時,會根據 devicePixelRatio 向上調整,因此會變得模糊。

圖片因 devicePixelRatio 而向上調整並模糊處理
圖 1 - 圖片因裝置 PixelRatio 而變大並模糊

實際上解決這個問題的方法,就是建立以 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();