Kanwy o wysokiej rozdzielczości

Wstęp

Ekrany HiDPI są piękne, dzięki czemu wszystko wygląda płynniej i czystszy. Stanowią one jednak również nowe wyzwania dla deweloperó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 wprowadziliśmy ekrany HiDPI, piksel był tylko pikselem (jeśli pominiemy nieco powiększanie i skalowanie), więc nie trzeba było niczego zmieniać. Jeśli ustawisz szerokość 100 pikseli, nic się nie stanie. Następnie pojawiło się kilka pierwszych telefonów komórkowych HiDPI z nieco tajemniczą właściwością devicePixelRatio w obiekcie window, którą można wykorzystać w zapytaniach o multimedia. Dzięki tej właściwości mogliśmy zrozumieć współczynnik tego, jak wartości pikseli (które nazywamy wartością logiczną piksela) – na przykład – CSS zostaną przełożone na rzeczywistą liczbę pikseli, których urządzenie użyje do renderowania. W przypadku iPhone'a 4S, którego parametr devicePixelRatio wynosi 2, wartość logiczna 100 pikseli odpowiada wartości 200 pikseli.

To ciekawe, ale co to oznacza dla nas, deweloperów? Na początku wszyscy zaczęli zauważać, że te urządzenia ulepszają obrazy. Tworzyliśmy obrazy o logicznej szerokości pikseli, a po rozciągnięciu ich rozmiar był skalowany za pomocą urządzeniaPixelRatio, przez co byłyby rozmyte.

Obraz jest ulepszany i zamazany z powodu PixelRatio
Rysunek 1. Obraz jest skalowany i zamazany z powodu urządzeniaPixelRatio

Faktyczne rozwiązanie polegało na utworzeniu obrazów przeskalowanych w górę o wartość parametru devicePixelRatio, a następnie za pomocą CSS do przeskalowania ich w dół o tę samą ilość – to samo dotyczy obiektów 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();