Kanwy o wysokiej rozdzielczości

Wprowadzenie

Ekrany HiDPI są świetne, ponieważ sprawiają, że wszystko wygląda płynniej i czysto. Stwarzają też nowe wyzwania dla programistów. W tym artykule przyjrzymy się unikalnym wyzwaniom związanym z rysowaniem obrazów w obszarze roboczym w kontekście ekranów HiDPI.

Właściwość devicePixelRatio

Zacznijmy od początku. Zanim pojawiły się ekrany HiDPI, piksel był pikselem (o ile pominiemy powiększanie i skalowanie), i tylko tyle. Nie trzeba było niczego zmieniać. Jeśli ustawisz coś o szerokości 100 pikseli, to wystarczy. Po pewnym czasie na ekranie pojawiło się kilka pierwszych telefonów HiDPI z nieco zagadkową właściwością PixelRatio w obiekcie window, z których można korzystać w zapytaniach o multimedia. Ta właściwość pozwoliła nam zrozumieć, jak stosunek wartości pikseli (które nazywamy wartością logiczną piksela) w CSS przekłada się na rzeczywistą liczbę pikseli, których urządzenie używa podczas renderowania. W przypadku iPhone'a 4S z parametrem devicePixelRatio równym 2, zobaczysz, że wartość logiczna 100 pikseli odpowiada wartości urządzenia wynoszącej 200 pikseli.

To ciekawe, ale co to oznacza dla nas, deweloperów? W pierwszych dniach zauważyliśmy, że te urządzenia zwiększają rozmiar naszych obrazów. Tworzyliśmy obrazy o logicznej szerokości pikseli naszych elementów, a po ich narysowaniu były one skalowane przez devicePixelRatio, przez co stawały się niewyraźne.

Obraz jest powiększony i rozmyty z powodu parametru PixelRatio na urządzeniu
Ilustracja 1. Obraz powiększony i rozmyty ze względu na devicePixelRatio

Dotychczasowym rozwiązaniem tego problemu było tworzenie obrazów powiększonych o wartość devicePixelRatio, a potem zmniejszanie ich za pomocą CSS o tę samą wartość. To samo dotyczy canvasa.

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