Lienzo con valores altos de DPI

Introducción

Las pantallas HiDPI son fabulosas, ya que hacen que todo se vea más fluido y claro. Sin embargo, también presentan un nuevo conjunto de desafíos para los desarrolladores. En este artículo, analizaremos los desafíos únicos de dibujar imágenes en el lienzo en el contexto de las pantallas HiDPI.

La propiedad devicePixelRatio

Empecemos por el principio. Antes de que necesitábamos pantallas HiDPI, un píxel era un píxel (si ignoramos el zoom y el escalamiento por un momento), y eso era todo, no se necesitaba cambiar nada. Si configuraste un elemento para que tenga 100 px de ancho, eso era todo. Luego, los primeros teléfonos celulares HiDPI comenzaron a aparecer con la propiedad devicePixelRatio, un tanto enigmática, en el objeto window, que ahora está disponible para su uso en consultas de medios. Esta propiedad nos permitió comprender la proporción de cómo los valores de píxeles (que llamamos valor lógico de píxeles) en, por ejemplo, CSS se traduciría a la cantidad real de píxeles que usaría el dispositivo en el momento de la renderización. En el caso de un iPhone 4S, que tiene un devicePixelRatio de 2, verás que un valor lógico de 100 px equivale a un valor de dispositivo de 200 px.

Es interesante, pero ¿qué significa para nosotros, los desarrolladores? Al principio, todos comenzamos a notar que estos dispositivos mejoraron nuestras imágenes. Estábamos creando imágenes con el ancho de píxeles lógico de nuestros elementos y, cuando se dibujaran, se aumentarían con devicePixelRatio y serían borrosas.

Una imagen que se aumenta y se desenfoca debido a la clasePixelRatio del dispositivo
Figura 1: Una imagen cuya escala se amplía y se desenfoca debido a devicePixelRatio

La solución de facto para esto ha sido crear imágenes ampliadas por devicePixelRatio y, luego, usar CSS para reducirla en la misma cantidad, y lo mismo ocurre con el lienzo.

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