REGL rendering in a React component

575 Views Asked by At

I have the following code where I'm attempting to render a 3d seen (using REGL) into a React component App. It seems to render finely at first. But what I notice is that if I adjust the size of the browser window, the div the component renders grows in height. So any window adjust meant translates directly into a growth in height until the div is taller than the window. I'm trying to understand how REGL and REACT can work together and so I'm not sure what to attribute this behavior to. It could be a misunderstanding of either on my part.

import React, {
  Component
} from 'react';
import regl from 'regl';

class App extends Component {
  constructor() {
    super()
    this.state = {
      reglTest: "Test REGL",
    };
  }
  componentDidMount() {
    const rootDiv = document.getElementById('reglTest');
    console.log(rootDiv);

    var reglObj = regl({
      container: rootDiv,
    })

    reglObj.frame(({
      tick
    }) => {
      reglObj.clear({
        color: [(tick % 100 * 0.01), 0, 0, 1],
        depth: 1,
      });

      reglObj({
        frag: `
  void main() {
    gl_FragColor = vec4(1, 0, 0, 1);
  }`,
        vert: `
  attribute vec2 position;
  void main() {
    gl_Position = vec4(position, 0, 1);
  }`,
        attributes: {
          position: [
            [(tick % 100 * 0.01), -1],
            [-1, 0],
            [1, 1]
          ]
        },
        count: 3
      })()
    });

  }
  render() {
    return ( <div id = "reglTest" > {this.state.reglTest} < /div> );
  }
}

export default App;

EDIT:

I was able to trace the bug down to a resize function in the REGL file.

 function resize () {
    var w = window.innerWidth;
    var h = window.innerHeight;
    if (element !== document.body) {
      var bounds = element.getBoundingClientRect();
      w = bounds.right - bounds.left;
      h = bounds.bottom - bounds.top;
    }
    canvas.width = pixelRatio * w;
    canvas.height = pixelRatio * h;
    extend(canvas.style, {
      width: w + 'px',
      height: h + 'px'
    });
  }

It winds up computing h as some high value (say 1000+ after adjusting the browser window for a little bit), while the window.innerHeight remains at say 320.

1

There are 1 best solutions below

0
On

I was puzzled by the same problem and it turns out that the example code, that I can see you also are using, is wrong.

The problem is with the "Test REGL" string (from state). When it is put into the same div as the canvas, the getBoundingClientRect() call return the height of the canvas element plus the height of the text string.

This height is then passed to the canvas that grows as a result.

Because canvas must fill its parent div completely, it is important to set the canvas to display: "block"

Solution:

  • The div containing the canvas, must ONLY contain the canvas.

And

  • The canvas element must be styled as: display: "block"

So what you need to do: Clear the container div from everything other than the canvas element.

e.g. remove this: {this.state.reglTest} from the render function, so it looks like this:

render() {
  return ( <div id = "reglTest" >  < /div> );
}

and in componentDidMount function, after regl() is called.

componentDidMount() {
  var reglObj = regl({
    container: rootDiv,
  })

add this to set canvas to display block.

const canvas = document.querySelector("#reglTest > canvas:first-of-type");
canvas.setAttribute("style", "display:block;");

so it looks like this

componentDidMount() {
...
  var reglObj = regl({
    container: rootDiv,
  })
const canvas = document.querySelector("#reglTest > canvas:first-of-type");
canvas.setAttribute("style", "display:block;");
...