devicePixelRatio

Sharp Rendering with devicePixelRatio

window.devicePixelRatio counts device pixels per CSS pixel: 2 on most laptops, 3 on many phones, and it changes as the user zooms. A bitmap the size of its CSS box is upscaled and goes soft; allocate that many times more pixels and scale the context to keep drawing in CSS pixels.

hidpi(): a bitmap sized for the screen, drawn in CSS pixelsHTMLLive
<canvas id="soft" width="290" height="44" style="width:290px; height:44px"></canvas>
<canvas id="sharp" style="width:290px; height:44px"></canvas>
<script>
  function hidpi(c, r = devicePixelRatio) {       // kept in demos/ch02/hidpi.js
    c.width = c.clientWidth * r;  c.height = c.clientHeight * r;
    const ctx = c.getContext('2d');  ctx.scale(r, r);  return ctx;
  }
  for (const ctx of [soft.getContext('2d'), hidpi(sharp)]) {
    ctx.fillStyle = '#5b3f99';  ctx.fillRect(4, 4, 26, 36);
    ctx.font = '14px Georgia';  ctx.fillText('Patterns of the Deep Web', 38, 20);
    ctx.font = '11px sans-serif';  ctx.fillText(`bitmap ${ctx.canvas.width}px wide`, 38, 36);
  }
</script>
Browser output of Listing 2.3
Browser output of 3

At the capture's ratio of 2 the left canvas has a quarter of the pixels it needs. Later listings load hidpi.js; re-run it when a ResizeObserver or a matchMedia() query for the ratio reports a change.