user2490157
user2490157

Reputation:

Scale canvas width and height to be as large as possible but maintain aspect ratio (JS)

If I have a canvas element that is a certain width and height, e.g.

<canvas id="display" width="900" height="650" tabindex=0></canvas>

and I want to scale up the width and height of the canvas to as large as possible while being contained within the viewport without changing the aspect ratio or increasing the overall area for objects to be displayed within the canvas.

This means that if a window is width 2200 and height 1300, both the display width and height of the canvas will be doubled (and no larger because otherwise the height could not be contained) and the canvas will have the new dimensions 1800 and 1300.

However, I am scaling up the CSS display height of the canvas element, not the canvas itself, which means that objects inside the canvas should also have their dimensions increased.

canvas {
  width: ...
  height: ...
}

It would be even better if the canvas can rescale itself when the window is resized, perhaps with an event listener.

Is there any way to do this in JS?

Upvotes: 0

Views: 2846

Answers (2)

user2490157
user2490157

Reputation:

Ended up finding my own solution, if there is a more elegant one available then please inform me.

// get maximum possible size for canvas while maintining aspect ratio
function resizeEventHandler(){
  var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
  var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
  if(w/canvas.width > h/canvas.height){
    canvas.style.width = "calc("+canvas.width+" / "+canvas.height+" * 100vh)";
    canvas.style.height = "calc(100vh)";
  } else {
    canvas.style.width = "calc(100vw)";
    canvas.style.height = "calc("+canvas.height+" / "+canvas.width+" * 100vw)";
  }
}
resizeEventHandler();
window.addEventListener("resize", resizeEventHandler);

Upvotes: 0

Blindman67
Blindman67

Reputation: 54128

Scale to fit

You have to define the aspect. This can be done by just defining a default size.

const defWidth = 1920;
const defHeight = 1080;

Then you can listen to the window resize event and resize the canvas to fit.

function resizeEventHandler(){
    // get the max size that fits both width and height by finding the min scale
    var canvasScale = Math.min(innerWidth / defWidth, innerHeight / defHeight);
    // or for max size that fills
    // canvasScale = Math.max(innerWidth / defWidth, innerHeight / defHeight);

    // now set canvas size and resolution to the new scale
    canvas.style.width = (canvas.width = Math.floor(defWidth * canvasScale)) + "px";
    canvas.style.height = (canvas.height = Math.floor(defHeight * canvasScale)) + "px";
}

Because the canvas resolution must be an integer the aspect may be out by a pixel. But there is nothing that can be done about that.

Upvotes: 1

Related Questions