News

Work with canvas across high-density displays

Ingamana’s Luciano Borromei explains how device PixelRatio helps you draw more responsively

canvas608

Device pixel density

First we need to get the pixel density the browser is working at. Luckily there is a DOM property containing that exact value: window.devicePixelRatio. Unfortunately, Internet Explorer 10 for Mobile doesn’t report this value, so a little extra code is required. The JavaScript snippet below allows you to get the value in a way supported by all major up-to-date browsers:

001 var devicePixelRatio = window.devicePixelRatio || (window.screen.availWidth / document.documentElement.clientWidth);

Canvas element

FlatGuitars applied devicePixelRatio in this way for the ‘Spinal Tap’ flavoured preloader element.  However here we’ll create a basic <canvas> element within the HTML and set its size via CSS. In this example we’re going to use 100px for simplicity, but you can use any dimensions you wish:

001 HTML:
002     
003 <canvas id=”graphics”></canvas>
004
005 CSS:
006
007 #graphics
008 {
009     width: 100px;
010     height: 100px;
011 }

Work with physical pixels

In order to be able to use the device’s actual pixels, we need to give our <canvas> the appropriate resolution. We achieve this by recalculating the element’s width and height attributes, overriding the base CSS. To get the number of physical pixels the element is taking, we multiply the element’s dimensions by devicePixelRatio. For example, if the pixel ratio is 2, the width and height attributes for the <canvas> element would then become 200px:

001 var canvasElement = document.
getElementById(“graphics”);
002 canvasElement.setAttribute(“width”, canvasElement.offsetWidth *
devicePixelRatio);    
003 canvasElement.setAttribute(“height”, canvasElement.offsetHeight *
devicePixelRatio);
004

Draw to resolution

It’s important to keep in mind that you need to make all dimensions proportional to the device pixel density. For example, if you were going to draw a circle with a 40px radius on a device with a pixel ratio value of 2, the radius should be 80px instead. The following code is an example of how to draw a circle for any pixel density, continuing our script:

001 var context = canvasElement.
getContext(“2d”);
002 context.translate(canvasElement.
offsetWidth / 2 * devicePixelRatio,
canvasElement.offsetHeight / 2 *
devicePixelRatio);
003 context.fillStyle = “blue”;
004 context.beginPath();
005 context.arc(0, 0, 40 *
devicePixelRatio, 0, Math.PI * 2, true);
006 context.closePath();
007 context.fill();

Bigger zoom values

In order to test your <canvas> graphics without multiple devices of varying pixel densities, you can use a desktop browser to simulate them. After all, a browser running on a high-density display is little more than a browser rendering with a bigger zoom value. So, by changing the zoom value, you will get different pixel density values. Just remember to refresh your page in order to redraw your graphics!

TECHNIQUE

Split-screen backgrounds

Section element
FlatGuitars breaks the page into full-width <section> regions for each guitar. Each section is then styled to have 100% dimensions as well as its own flat background colour. Inside we place a element styled to contain our pattern.

001 HTML:
002 <body>
003 <section>
004 <span class=”dotoverlay”></
span>
005 …
006 </section>
007
008 CSS:
009 section {
010 position: relative;
011 overflow: hidden;
012 width: 100%;
013 height: 100%;
014 z-index:1;
015 }
016

Span pattern
The pattern is a 10 x 10px transparent PNG with a dotted pattern we set as our element’s repeating background. Crucially, be sure to take note of the fact that the width set to 50%, which will fill half the screen while the height remains maximised.

Split background
In the CSS code, the z-index attributes are set purposefully so that any subsequent elements you place inside the <section> will then appear above the pattern. Without this you will find that the dotted background appears above anything on that half of the page, which you don’t want.

×