Home > Mobile >  Two layered canvas scaled to automatically fill flex column space
Two layered canvas scaled to automatically fill flex column space

Time:01-18

I'd like two left canvas (layered on top of each other), to fit the left column (100% width minus the right column's 300px width).

It should work even if the canvas' height and width change dynamically, see here after 1 second and 3 seconds, when the canvas width changes from 500 to 1500 pixels wide.

var c1 = document.getElementById("canvas1"), ctx1 = c1.getContext("2d");
var c2 = document.getElementById("canvas2"), ctx2 = c2.getContext("2d");
setTimeout(() => {
    ctx1.canvas.width = 500;
    ctx1.canvas.height = 300; 
    ctx1.rect(0, 0, 500, 300);
    ctx1.fill();
    ctx2.canvas.width = 500;
    ctx2.canvas.height = 300; 
    ctx2.rect(50, 50, 100, 100);
    ctx2.fillStyle = "green";
    ctx2.fill();
}, 1000);
setTimeout(() => {
    ctx1.canvas.width = 1500;
    ctx1.canvas.height = 500; 
    ctx1.rect(0, 0, 1500, 500);
    ctx1.fill();
    ctx2.canvas.width = 1500;
    ctx2.canvas.height = 500; 
    ctx2.rect(100, 100, 100, 100);
    ctx2.fillStyle = "red";
    ctx2.fill();
}, 3000);
.container { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background-color: yellow; }
.column { border: 1px solid black; }
.canvas-wrapper { margin: 1rem; flex: 1; }
#canvas2 { position: absolute; top: 0; left: 0; }
.right-column { width: 300px; }
<div >
    <div >
        <canvas id="canvas1"></canvas>
        <canvas id="canvas2"></canvas>
    </div>
    <div >
        Hello world
    </div>
</div>

Here is how it should look like, in both cases it should be rescaled to fit the left column.
In the second case (with the red square), the canvas should be scaled down to fit in the left column (for example to a width of ~1000px if the browser viewport width is 1300 px, minus the 300 px for the right column), even if the real canvas width is still 1500 px.

enter image description here

I have tried multiple variations of flexbox, without success.

If possible, I'd like to keep flex and avoid calc(100% - 300px) rules.

TL;DR: How to make two layered canvas of the same size on top of each other (this size can vary) fit automatically a column in a flex layout?

CodePudding user response:

Does changing to grid help?

This snippet has two columns in the grid, the first one taking what's left after the 300px column. The width and height of the canvases is set to maximum of the cell dimensions.

var c1 = document.getElementById("canvas1"),
  ctx1 = c1.getContext("2d");
var c2 = document.getElementById("canvas2"),
  ctx2 = c2.getContext("2d");
setTimeout(() => {
  ctx1.canvas.width = 500;
  ctx1.canvas.height = 300;
  ctx1.rect(0, 0, 500, 300);
  ctx1.fill();
  ctx2.canvas.width = 500;
  ctx2.canvas.height = 300;
  ctx2.rect(50, 50, 100, 100);
  ctx2.fillStyle = "green";
  ctx2.fill();
}, 1000);
setTimeout(() => {
  ctx1.canvas.width = 1500;
  ctx1.canvas.height = 500;
  ctx1.rect(0, 0, 1500, 500);
  ctx1.fill();
  ctx2.canvas.width = 1500;
  ctx2.canvas.height = 500;
  ctx2.rect(100, 100, 100, 100);
  ctx2.fillStyle = "red";
  ctx2.fill();
}, 3000);
.container {
  display: grid;
  grid-template-columns: 1fr 300px;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background-color: yellow;
}

.column {
  border: 1px solid black;
}

.canvas-wrapper {
  margin: 1rem;
  flex: 1;
}

#canvas2 {
  position: absolute;
  top: 0;
  left: 0;
}

canvas {
  max-width: 100%;
  max-height: 100%;
}

.right-column {
  width: 300px;
}
<div >
  <div >
    <canvas id="canvas1"></canvas>
    <canvas id="canvas2"></canvas>
  </div>
  <div >
    Hello world
  </div>
</div>

CodePudding user response:

The trick with FlexBox is to make the left column have a min-width:0, this allows it to shrink, and your 300px right column can then stay the same.

Also you will want to make another div for you canvas-wrapper, so that margins etc work as expected.

Eg.

var c1 = document.getElementById("canvas1"), ctx1 = c1.getContext("2d");
var c2 = document.getElementById("canvas2"), ctx2 = c2.getContext("2d");
setTimeout(() => {
    ctx1.canvas.width = 500;
    ctx1.canvas.height = 300; 
    ctx1.rect(0, 0, 500, 300);
    ctx1.fill();    
    ctx2.canvas.width = 500;
    ctx2.canvas.height = 300; 
    ctx2.rect(50, 50, 100, 100);
    ctx2.fillStyle = "green";
    ctx2.fill();
}, 1000);
setTimeout(() => {
    ctx1.canvas.width = 1500;
    ctx1.canvas.height = 500; 
    ctx1.rect(0, 0, 1500, 500);
    ctx1.fill();
    ctx2.canvas.width = 1500;
    ctx2.canvas.height = 500; 
    ctx2.rect(100, 100, 100, 100);
    ctx2.fillStyle = "red";
    ctx2.fill();
}, 3000);
.container { 
  display: flex; 
  align-items: center; 
  justify-content: center; 
  background-color: yellow; 
}
.column { 
  border: 1px solid black; 
}
.canvas-wrapper { 
  margin: 1rem; 
  flex: 1; 
  position: relative; 
}
#canvas1 {
  width: 100%;
}
#canvas2 { 
  position: absolute; 
  top: 0;
  left: 0;
  width: 100%;
}

.left-column {
  min-width: 0;
}
.right-column {
  width: 300px; 
  min-width: 300px; 
}
<div >
    <div >
        <div >
          <canvas id="canvas1"></canvas>
          <canvas id="canvas2"></canvas>
        </div>
    </div>
    <div >
        Hello world
    </div>
</div>

  • Related