如何保持子canvas元素的宽高比为1:1?

问题描述 投票:0回答:1

我已经在 Github 上准备了 一个简单的测试网页(使用 main.css 文件)来解决我的问题:

animated screenshot

在垂直 Flexbox 布局中,我尝试使用 ResizeObserver 来观看具有 flex-grow:1 的父 div 元素,然后在其子画布元素上保持 1:1 的宽高比。

我尝试保持画布宽高比的原因是在我的真实应用程序中,PixiJS 画布嵌入在 ReactJS 应用程序中,如果我只是缩放画布元素以填充 div 父级,则 PixiJS 内容会被拉伸:

screenshot

不幸的是,

parent
div 元素将
hint
div 元素推离屏幕底部 -

我认为,我的代码中缺少一些小东西,请建议修复:

const parentElement = document.getElementById("parent");
const childElement = document.getElementById("child");

const resizeObserver = new ResizeObserver((entries) => {
  for (let entry of entries) {
    const { width, height } = entry.contentRect;
    const minDimension = Math.min(width, height);
    console.log(
      `parent: ${width} x ${height} -> child: ${minDimension} x ${minDimension}`
    );
    childElement.style.width = `${minDimension}px`;
    childElement.style.height = `${minDimension}px`;
  }
});

resizeObserver.observe(parentElement);
html,
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.flexRoot {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: stretch;
  width: 100%;
  height: 100vh;
}

/* the parent holds: status, canvas, hint */
.parent {
  border: 4px solid red;
  flex-grow: 1;
}

canvas {
  width: 1020px;
  height: 1020px;
  background-color: yellow;
  border: 4px green dotted;
  box-sizing: border-box;
}

.hint,
.status {
  background: lightblue;
  font-style: italic;
  text-align: center;
  flex-grow: 0;
}
<div class="flexRoot">
  <div class="status">Game #1 Score1:Score2</div>
  <div class="parent" id="parent">
    <canvas id="child"></canvas>
  </div>
  <div class="hint">A game hint to do this and that...</div>
</div>

javascript css flexbox html5-canvas resize-observer
1个回答
0
投票

为了确保

.parent
的大小由
.flexRoot
而不是
#child
确定,它不应允许溢出:

.parent {
  overflow: hidden;
}

可选: 使用

flex
将画布居中。

const parentElement = document.getElementById("parent");
const childElement = document.getElementById("child");

const resizeObserver = new ResizeObserver((entries) => {
  for (let entry of entries) {
    const {
      width,
      height
    } = entry.contentRect;
    const minDimension = Math.min(width, height);
    console.log(
      `parent: ${width} x ${height} -> child: ${minDimension} x ${minDimension}`
    );
    childElement.style.width = `${minDimension}px`;
    childElement.style.height = `${minDimension}px`;
  }
});

resizeObserver.observe(parentElement);
html,
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.flexRoot {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: stretch;
  width: 100%;
  height: 100vh;
}


/* the parent holds: status, canvas, hint */

.parent {
  border: 4px solid red;
  flex-grow: 1;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

canvas {
  width: 1020px;
  height: 1020px;
  background-color: yellow;
  border: 4px green dotted;
  box-sizing: border-box;
}

.hint,
.status {
  background: lightblue;
  font-style: italic;
  text-align: center;
  flex-grow: 0;
}
<div class="flexRoot">
  <div class="status">Game #1 Score1:Score2</div>
  <div class="parent" id="parent">
    <canvas id="child"></canvas>
  </div>
  <div class="hint">A game hint to do this and that...</div>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.