Search code examples
javascriptcanvassizing

Sizing a canvas (in javascript) via 'style' gives bad results?


I want to generate my canvas in javascript. Sizing it via 'style' doesn't work. (Option 'a' in my code) Why?

But the way to do it is with canvas.width and .height (Option 'b'). The default size is Option 'c'.

<html>
  <head>
    <meta charset="utf-8">
    <style>
canvas { outline:1px dotted black; } 
    </style>
  </head>
  <body>
    <script>
  "use strict";
  let option = prompt('a, b, or c','a');
  let canvas = document.createElement('canvas');
  canvas.setAttribute('id','canvas');
  switch(option) {
  case 'a': // setting size with style - NG
    canvas.setAttribute('style','width:500px; height:500px;');
    break;
  case 'b': // setting size with .width/.height - OK
    canvas.width = 500;
    canvas.height = 500;
    break;
  case 'c':
  default: // default size
    option = 'c';
  }
  document.body.appendChild(canvas);
  let ctx = canvas.getContext("2d")
  ctx.font = '20px Ariel';
  ctx.fillText('Option: '+option,10,20);
  ctx.arc(250,250,200, 0, 6.2832);
  ctx.stroke();
    </script>
  </body>
</html>

Solution

  • You have to do both 'a' and 'b' at the same time for the image to not be distorted -- and you also have to look at the weird thing called the "device-pixel-ratio-to-backing-store-pixel-ratio" magic numbers so it is scaled appropriately and not blurry.

    The canvas default size is not square, so if you set it square by 'a' only or 'b' only, it still will be rectangular by the other option and so the image will be smashed.

    Here's a snippet of some of my old code that does this:

    const ctx = canvas.getContext("2d");
    const dpr = window.devicePixelRatio || 1;
    const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
    const ratio = dpr / bsr;
    
    canvas.width = targetWidth * ratio;
    canvas.height = targetHeight * ratio;
    canvas.style.width = targetWidth;
    canvas.style.height = targetHeight;
    

    I got this code from another SO answer many years ago but I can't remember from where.

    hope this helps.