React + Three.js画布在缩小浏览器窗口时无法正确调整大小

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

我正在使用react和three.js在浏览器中显示一些3D模型。只要three.js组件是页面上唯一具有可见内容的元素,一切都可以正常工作。 three.js画布将调整大小,就好了。您可以将其包装在其他容器中,但仍然可以正常工作。当另一个元素或组件作为同级添加时,问题就开始了。

我想有一个带有固定宽度边栏的视口。我使用的是flexbox行容器,该容器包装在侧边栏组件(设置了最小宽度的简单div)和响应性three.js组件中。

将窗口的大小调整得更大可以很好地工作,画布会适当地填充浏览器窗口。但是,当将窗口调整为较小的尺寸时,画布无法根据静态宽度侧栏剩余的可用空间正确地重新计算其大小,从而导致画布无法完全适合浏览器并引入滚动条。

画布确实会缩小一些,但不足以使其完全保留在浏览器窗口中。如果某个组件位于three.js组件之上或之下,则在垂直方向上会出现相同的问题。如果在浏览器窗口较小的情况下重新编译应用程序,则刷新后的视图将适当调整画布的大小。

按照StackOverflow上许多答案的建议,Three.js反应代码看起来像这样:

export class Viewport extends React.Component {

  componentDidMount() {

    const width = this.mount.clientWidth;
    const height = this.mount.clientHeight;
    window.addEventListener("resize", this.handleWindowResize);

    // setup scene
    this.scene = new THREE.Scene();

    //setup camera
    this.camera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 );
    this.camera.position.set( 0, 5, 10 );

    // setup rendering
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
    this.renderer.setClearColor('#666666');
    this.renderer.setSize(width, height, false);
    this.mount.appendChild(this.renderer.domElement);

    // setup geo
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshBasicMaterial({ color: '#433F81' });
    this.cube = new THREE.Mesh(geometry, material);
    this.scene.add(this.cube);
    ...

  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.handleWindowResize);
    this.mount.removeChild(this.renderer.domElement);
  }

  handleWindowResize = () => {
    const width = this.mount.clientWidth;
    const height = this.mount.clientHeight;

    this.camera.aspect = width / height;
    this.camera.updateProjectionMatrix();

    this.renderer.setSize(width, height, false);
  };

  render() {
    return (
      <div className="viewport" style={{display: 'flex', width: "100%", height: "100%"}} ref={(mount) => { this.mount = mount }} />
    );
  }
}

样式是简单的CSS Flexbox,将元素设置为全宽和全高(100%),并且边栏具有设置的最小宽度。

.flex-row-container {
  display: flex;
  flex-flow: row;
  height: 100%;
  width: 100%;
}

.sidebar {
  display: block;
  min-width: 250px;
  background-color: var(--color-mid-gray);
  margin: 3px 4px 3px 4px;
  box-sizing: border-box;
  border: 1px solid var(--color-mid-gray);
  outline: 3px solid var(--color-mid-gray);
}

我想念什么?

reactjs three.js autoresize
2个回答
0
投票

使用element.clientWidth可能会得到不正确的值。您是否尝试过使用element.getBoundingClientRect()代替?

element.getBoundingClientRect()

0
投票

所以评论后,我想我可以按照您的意愿来做。

基本上,我删除了视口上的const rect = this.mount.getBoundingClientRect(); const width = rect.width; const height = rect.height; 设置,因为它是display:flex元素的子元素(flex-row-container div),它不需要它,但需要display:flex来设置它的显示方式在flexbox内(我在CSS而不是JSX中做了)。然后,问题就变成了视口div将扩展,但不会收缩(因为它包含画布),因此添加flex:1 1 auto可以解决此问题。进行了这些更改之后,overflow:hidden将获得所需的结果,然后可以将其用于设置三个画布大小。

请参见this.mount.clientWidth。我在示例中添加了渲染和动画,因此可以轻松看到结果。

希望这会有所帮助。

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