javascript 强制画布使用Flex列中的可用空间

taor4pac  于 2023-05-12  发布在  Java
关注(0)|答案(4)|浏览(172)

我有一个全尺寸的页面,包含一个顶部工具栏,下面是一个包含2列的容器:

  • 右栏
  • 包含画布的左列(在该列中水平和垂直居中),该画布具有自己的坐标系(通常为4000 x 3000),并应保持此纵横比。这个画布上有一个“+”按钮。(在我的真实的代码中,有几个画布用于多个图层和多个按钮,但在这里并不重要)

在这里,它几乎可以工作,但是我不能让画布占据左列中的全部可用空间。
使用我尝试的所有方法(max-width: 100%max-height: 100%),当我们在浏览器中放大/缩小时(70% 80%... 150%),或者它失败了,因为所使用的方法阻止了按钮停留在画布的顶部,在它的右角。

TL;DR:如何让这个画布占据左列的所有可用空间,保持其纵横比,保持分层按钮,而不会溢出?

注:我正在寻找一个CSS解决方案,JS是不是定位,但只有绘图。

ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#FF0000"; ctx.fillRect(0, 0, 1000, 1000);
ctx.fillStyle = "#00FF00"; ctx.fillRect(1000, 1000, 1000, 1000);
ctx.fillStyle = "#0000FF"; ctx.fillRect(2000, 2000, 1000, 1000);
ctx.fillStyle = "#000000"; ctx.fillRect(3000, 0, 1000, 1000);
* {
  padding: 0;
  margin: 0;
}

.page {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.toolbar {
  background-color: yellow;
  flex: 0 0 5em;
}

.container {
  background-color: orange;
  flex: 1 0 0;
  display: flex;
}

.left {
  background-color: magenta;
  flex: 1 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.right {
  background-color: salmon;
  flex: 0 0 10em;
}

.canvas-wrapper {
  background-color: grey;
  display: flex;
  position: relative;
}

canvas {
  height: 100px;
  background-color: white;
}

.button {
  background-color: yellow;
  position: absolute;
  top: 0;
  right: 0;
  width: 1em;
  height: 1em;
}
<div class="page">
  <div class="toolbar">
    TOOLBAR OF HEIGHT 5 EM
  </div>
  <div class="container">
    <div class="left">
      <div class="canvas-wrapper">
        <canvas width="4000" height="3000"></canvas>
        <div class="button">+</div>
      </div>
    </div>
    <div class="right">
      RIGHT OF WIDTH 10 EM
    </div>
  </div>
</div>

PS:你必须在“全页”中打开片段才能看到浏览器放大/缩小功能(CTRL +,CTRL -)。

rqdpfwrv

rqdpfwrv1#

您需要更改一些对齐方式,如width s、height s、flex-grow s,并添加一个HTML Package 器(即<div class="canvas-wrapper-inner">)。
请参见下面的片段。

ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 1000, 1000);
ctx.fillStyle = "#00FF00";
ctx.fillRect(1000, 1000, 1000, 1000);
ctx.fillStyle = "#0000FF";
ctx.fillRect(2000, 2000, 1000, 1000);
ctx.fillStyle = "#000000";
ctx.fillRect(3000, 0, 1000, 1000);
* {
  padding: 0;
  margin: 0;
}

.page {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.toolbar {
  background-color: yellow;
  flex: 0 0 5em;
}

.container {
  background-color: orange;
  flex: 1 0 0;
  display: flex;
}

.left {
  background-color: magenta;
  flex: 1 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.right {
  background-color: salmon;
  flex: 0 0 10em;
}

.canvas-wrapper {
  background-color: grey;
  display: flex;
  position: relative;
  flex-grow: 1; /* Added */
  align-self: stretch; /* Added */
  align-items: center; /* Added */
  justify-content: center; /* Added */
}

canvas {
  width: 100%; /* Added */
  flex-grow: 1; /* Added */
  object-fit: contain; /* Added */
  max-height: calc(100vh - 5em); /* Added */
}

.button {
  background-color: yellow;
  position: absolute;
  top: 0;
  right: 0;
  width: 1em;
  height: 1em;
}

/* Added */
.canvas-wrapper-inner {
  position: relative;
}
<div class="page">
  <div class="toolbar">
    TOOLBAR OF HEIGHT 5 EM
  </div>
  <div class="container">
    <div class="left">
      <div class="canvas-wrapper">
        <div class="canvas-wrapper-inner">
          <canvas width="4000" height="3000"></canvas>
          <div class="button">+</div>
        </div>
      </div>
    </div>
    <div class="right">
      RIGHT OF WIDTH 10 EM
    </div>
  </div>
</div>
qij5mzcb

qij5mzcb2#

有一个方便的单位大小称为cqmin,它是内联或块大小的最小值。将容器 Package 器设置为size类型的容器,以便内容响应块和内联尺寸,然后将画布的宽度设置为100cqmin。使用aspect-ratio来保持,呃,长宽比。参见下面的示例。我也放了一个代码页here

ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#FF0000"; ctx.fillRect(0, 0, 1000, 1000);
ctx.fillStyle = "#00FF00"; ctx.fillRect(1000, 1000, 1000, 1000);
ctx.fillStyle = "#0000FF"; ctx.fillRect(2000, 2000, 1000, 1000);
ctx.fillStyle = "#000000"; ctx.fillRect(3000, 0, 1000, 1000);
* {
  padding: 0;
  margin: 0;
}

.page {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.toolbar {
  background-color: yellow;
  flex: 0 0 5em;
}

.container {
  background-color: orange;
  flex: 1 0 0;
  display: flex;
}

.left {
  container-type: size;
  background-color: magenta;
  flex: 1 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.right {
  background-color: salmon;
  flex: 0 0 10em;
}

.canvas-wrapper {
  position: relative;
  width: 100cqmin;
}

.button {
  background-color: yellow;
  position: absolute;
  top: 0;
  right: 0;
  width: 1em;
  height: 1em;
}

canvas {
  width: 100%;
  aspect-ratio: 4/3;
  background-color: white;
}
<div class="page">
  <div class="toolbar">
    TOOLBAR OF HEIGHT 5 EM
  </div>
  <div class="container">
    <div class="left">
      <div class="canvas-wrapper">
        <canvas width="4000" height="3000"></canvas>
        <div class="button">+</div>
      </div>
    </div>
    <div class="right">
      RIGHT OF WIDTH 10 EM
    </div>
  </div>
</div>
vpfxa7rd

vpfxa7rd3#

下面是一个基于RokBenko的答案的答案,它似乎可以工作,没有二级 Package 器和二级flex:

ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 1000, 1000);
ctx.fillStyle = "#00FF00";
ctx.fillRect(1000, 1000, 1000, 1000);
ctx.fillStyle = "#0000FF";
ctx.fillRect(2000, 2000, 1000, 1000);
ctx.fillStyle = "#000000";
ctx.fillRect(3000, 0, 1000, 1000);
* {
  padding: 0;
  margin: 0;
}

.page {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.toolbar {
  background-color: yellow;
  flex: 0 0 5em;
}

.container {
  background-color: orange;
  flex: 1 0 0;
  display: flex;
}

.left {
  background-color: magenta;
  flex: 1 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.right {
  background-color: salmon;
  flex: 0 0 10em;
}

.canvas-wrapper {
  background-color: #aaa;
  position: relative;
}

canvas {
  background-color: white;
  width: 100%;
  max-height: calc(100vh - 5em);
}

.button {
  background-color: yellow;
  position: absolute;
  top: 0;
  right: 0;
  width: 1em;
  height: 1em;
}
<div class="page">
  <div class="toolbar">
    TOOLBAR OF HEIGHT 5 EM
  </div>
  <div class="container">
    <div class="left">
      <div class="canvas-wrapper">
        <canvas width="4000" height="3000"></canvas>
        <div class="button">+</div>
      </div>
    </div>
    <div class="right">
      RIGHT OF WIDTH 10 EM
    </div>
  </div>
</div>
rqmkfv5c

rqmkfv5c4#

这是基于my other answer on the related question。这个想法是:

  • 使用Flexbox创建固定+流体布局
  • 将画布放置在流体部分内
  • 使用相对+绝对定位来缩放和居中画布元素
ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 1000, 1000);
ctx.fillStyle = "#00FF00";
ctx.fillRect(1000, 1000, 1000, 1000);
ctx.fillStyle = "#0000FF";
ctx.fillRect(2000, 2000, 1000, 1000);
ctx.fillStyle = "#000000";
ctx.fillRect(3000, 0, 1000, 1000);
body {
  margin: 0;
}

.page {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.toolbar {
  background-color: yellow;
  flex: 0 0 5em;
}

.container {
  background-color: orange;
  flex: 1 1 auto;
  /* make it the wrapper for two column layout */
  display: flex;
  flex-direction: row;
}

.left {
  background-color: magenta;
  flex: 1 1 auto;
  /* make it the wrapper for canvas */
  position: relative;
}

.right {
  background-color: salmon;
  flex: 0 0 10em;
  align-self: center;
}

canvas {
  background-color: gray;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}
<div class="page">
  <div class="toolbar">
    TOOLBAR OF HEIGHT 5 EM
  </div>
  <div class="container">
    <div class="left">
      <canvas width="4000" height="3000"></canvas>
    </div>
    <div class="right">
      RIGHT OF WIDTH 10 EM
    </div>
  </div>
</div>

为了处理+按钮,我建议使用一个类似的解决方案,将画布和按钮 Package 在一个 Package 器元素中,该 Package 器元素被强制用作内联替换元素:

ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 1000, 1000);
ctx.fillStyle = "#00FF00";
ctx.fillRect(1000, 1000, 1000, 1000);
ctx.fillStyle = "#0000FF";
ctx.fillRect(2000, 2000, 1000, 1000);
ctx.fillStyle = "#000000";
ctx.fillRect(3000, 0, 1000, 1000);
body {
  margin: 0;
}

.page {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.toolbar {
  background-color: yellow;
  flex: 0 0 5em;
}

.container {
  background-color: orange;
  flex: 1 1 auto;
  /* make it the wrapper for two column layout */
  display: flex;
  flex-direction: row;
}

.left {
  background-color: magenta;
  flex: 1 1 auto;
  /* make it the wrapper for canvas */
  position: relative;
}

.right {
  background-color: salmon;
  flex: 0 0 10em;
  align-self: center;
}

.canvas-wrapper {
  background-color: gray;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  max-width: 100%;
  max-height: 100%;
}

canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.button {
  background-color: yellow;
  position: absolute;
  top: 0;
  right: 0;
  width: 1em;
}
<div class="page">
  <div class="toolbar">
    TOOLBAR OF HEIGHT 5 EM
  </div>
  <div class="container">
    <div class="left">
      <div class="canvas-wrapper" style="aspect-ratio: 4000 / 3000;">
        <canvas width="4000" height="3000"></canvas>
        <div class="button">+</div>
      </div>
    </div>
    <div class="right">
      RIGHT OF WIDTH 10 EM
    </div>
  </div>
</div>

相关问题