Canvas mit hoher DPI

Paul Lewis

Einführung

HiDPI-Bildschirme sind toll, weil alles flüssiger und klarer aussieht. Sie stellen Entwickler aber auch vor neue Herausforderungen. In diesem Artikel sehen wir uns die besonderen Herausforderungen beim Zeichnen von Bildern im Canvas im Kontext von HiDPI-Bildschirmen an.

Das Attribut „devicePixelRatio“

Beginnen wir am Anfang. Bevor es HiDPI-Bildschirme gab, war ein Pixel ein Pixel (wenn wir Zoomen und Skalieren für einen Moment ignorieren) und das war es auch schon. Sie mussten nichts ändern. Wenn Sie etwas auf 100 Pixel Breite festgelegt haben, war das alles. Dann kamen die ersten HiDPI-Mobilgeräte mit der etwas rätselhaften „devicePixelRatio“-Property im Fensterobjekt auf den Markt, die in Medienabfragen verwendet werden konnte. Mit dieser Eigenschaft konnten wir das Verhältnis zwischen Pixelwerten (die wir als logischen Pixelwert bezeichnen) in beispielsweise CSS und der tatsächlichen Anzahl von Pixeln ermitteln, die das Gerät beim Rendern verwendet. Bei einem iPhone 4S mit einem devicePixelRatio von 2 entspricht ein logischer Wert von 100 px einem Gerätewert von 200 px.

Das ist interessant, aber was bedeutet das für uns Entwickler? In der Anfangszeit ist uns allen aufgefallen, dass unsere Bilder von diesen Geräten hochskaliert wurden. Wir haben Bilder mit der logischen Pixelbreite unserer Elemente erstellt. Beim Zeichnen wurden sie dann durch „devicePixelRatio“ hochskaliert und waren unscharf.

Ein Bild, das aufgrund des devicePixelRatio hochskaliert und unscharf dargestellt wird
Abbildung 1: Ein Bild, das aufgrund des devicePixelRatio hochskaliert und unscharf dargestellt wird

Die De-facto-Lösung hierfür bestand darin, Bilder zu erstellen, die um den devicePixelRatio-Wert vergrößert wurden, und sie dann mit CSS um denselben Betrag zu verkleinern. Das gilt auch für Canvas.

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();