I want to use a canvas thats max 1000px x 1000px. But if the screen is smaller, or the window becomes smaller to automatically adjust the width/height based on that while maintaining original aspect ratio. example: If width=500px then canvas = 500x500, not 500x1000. if height = 100, then canvas = 100x100. I dont mind using javascript, css, html to do this. thank you.
-
There is a very comprehensive answer to a similar question here >>> [Maintain the aspect ratio of a div with CSS](https://stackoverflow.com/questions/1495407/maintain-the-aspect-ratio-of-a-div-with-css) _ It explains in detail how aspect ratios are calculated etc. Although your question is specific to the ` – inputforcolor Jan 05 '20 at 23:11
-
thanks for your comment. even in the example given, it only adjusts based on width, not height. I have seen this done, i just have no idea how. you can see for yourself. https://colonist.io/ click 'Play Now', inspect element, then change the width/height. see how the size changes dynamically and maintains aspect ratio? that is what i am looking for. thanks – Jan 05 '20 at 23:26
-
Just "wanting" to do something is not enough to post on SO, so: what have you actually tried in order to achieve this so far? Where is your code that shows you tapping into the window's current width and height, and listening for resize events? – Mike 'Pomax' Kamermans Jan 06 '20 at 00:02
1 Answers
Scale to fit with fixed aspect ratio.
You can use CanvasRenderingContext2D.setTransform to scale and position the transform to fit and center content.
You will need a reference resolution which defines the original coordinate scale 1
and the aspect. Eg...
const refRes = {width: 1000, height: 1000};
Scale to fit
Then you can calculate the scale and origin to fit and center content to a given sized canvas. This is done by using the minimum scaled dimension to scale the content. Eg...
// Get the scale to fit content to the canvas
const scale = Math.min(canvas.width / refRes.width, canvas.height / refRes.height);
// set the origin so that the scaled content is centered on the canvas
const origin = {
x: (canvas.width - refRes.width * scale) / 2,
y: (canvas.height - refRes.height * scale) / 2
};
// Set the transform to scale and center on canvas
ctx.setTransform(scale, 0, 0, scale, origin.x, origin.y);
// Then render your content using the original coordinates.
ctx.fillRect(0, 0, 1000, 1000); // will fit any sized canvas
As this maintains the aspect there may be unused pixels left and right or above and below depending on the canvas aspect.
Scale to fill
You can scale to fill, which will crop the content but ensures that all pixels are use. Just use the maximum scaled dimension. Eg...
// Use max res to scale to fill
const scale = Math.max(canvas.width / refRes.width, canvas.height / refRes.height);
Demo
Demo shows content scaled to fit a canvas that has its size changed randomly. The content is rendered in the original coordinate systems and the 2D transform is used to scale to fit and center.
requestAnimationFrame(mainLoop);
const ctx = canvas.getContext("2d");
const size = 1000;
Math.TAU = Math.PI * 2;
Math.randI = (m, M) => Math.random() * (M - m) + m | 0; // for unsigned int32
Math.nearZero = val => Math.abs(val) < 1e-3;
const refRes = {width: size, height: size};
renderContent();
// State for canvas size changes
var xRes = canvas.width, yRes = canvas.height;
var xResC = xRes, yResC = yRes; // current resolution
var xResD = 0, yResD = 0; // resolution delta change
const rate = 0.2; // rate of canvas size change
// WARNING there is no bounds checking for canvas size.
// If rate < 0 || rate > 0.5 you MUST check that canvas size
// is safe before setting its width and height
function scaleToFit() {
const scale = Math.min(canvas.width / refRes.width, canvas.height / refRes.height);
ctx.setTransform(
scale, 0, 0, scale,
(canvas.width - refRes.width * scale) / 2,
(canvas.height - refRes.height * scale) / 2
);
}
function mainLoop() {
xResC += (xResD = (xResD += (xRes - xResC) * rate) * rate);
yResC += (yResD = (yResD += (yRes - yResC) * rate) * rate);
const w = xResC | 0;
const h = yResC | 0;
if (w !== canvas.width || h !== canvas.height) {
canvas.width = w;
canvas.height = h;
renderContent();
}
if(Math.nearZero(xResD) && Math.nearZero(yResD)) {
xRes = Math.randI(30, 300);
yRes = Math.randI(30, 200);
}
requestAnimationFrame(mainLoop);
}
function renderContent() {
scaleToFit();
ctx.fillStyle = "#Faa";
ctx.fillRect(0,0,size,size);
ctx.fillStyle = "#8aF";
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 4, 0, Math.TAU);
ctx.fill();
ctx.fillStyle = "#FF8";
ctx.fillRect(
(size - size * Math.SQRT1_2) / 2, (size - size * Math.SQRT1_2) / 2,
size * Math.SQRT1_2, size * Math.SQRT1_2
);
ctx.lineWidth = 10;
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 4, 0, Math.TAU);
ctx.rect(
(size - size * Math.SQRT1_2) / 2, (size - size * Math.SQRT1_2) / 2,
size * Math.SQRT1_2, size * Math.SQRT1_2
);
ctx.stroke();
}
canvas {
border: 1px solid black;
}
<canvas id="canvas"></canvas>

- 51,134
- 11
- 73
- 136