20

I am trying to use p5 (https://p5js.org/) in a react application and the performance of some sketches is really bad (same in development as after building the app). I'm using create-react-app for the project scaffold, without any changes to the build setup.

The sketches run around 50-60fps when running them directly in the browser, but when loaded into react they drops to about 1-2fps.

I am connecting the sketches with react like this:

// React Component to interface the sketches
class P5Wrapper extends React.Component {

  componentDidMount() {
    const { sketch, ...rest } = this.props;
    this.canvas = new p5(sketch(rest), this.wrapper);
  }

  componentWillReceiveProps(newProps) {
    const { sketch, ...rest } = newProps;

    if (this.props.sketch !== newProps.sketch) {
      this.canvas.remove();
      this.canvas = new p5(newProps.sketch(rest), this.wrapper);
    }

    if (typeof this.canvas.onNewProps === "function") {
      this.canvas.onNewProps(newProps);
    }
  }

  componentWillUnmount() {
    this.canvas.remove();
  }

  render() {
    return <div ref={(wrapper) => this.wrapper = wrapper} />;
  }
}

// you can watch the sketch in action here (https://p5js.org/examples/simulate-game-of-life.html)
const gameOfLife = (props) => (p) => {
  let w;
  let columns;
  let rows;
  let board;
  let next;

  p.setup = () => {
    p.createCanvas(1024, 768);
    p.background(255);
    p.noStroke();
    w = 20;

    columns = p.floor(p.width / w);
    rows = p.floor(p.height / w);

    board = new Array(columns);
    for (let i = 0; i < columns; i++) {
      board[i] = new Array(rows);
    }

    next = new Array(columns);
    for (let i = 0; i < columns; i++) {
      next[i] = new Array(rows);
    }
    init();
  };

  p.draw = () => {
    generate();
    for (let i = 0; i < columns; i++) {
      for (let j = 0; j < rows; j++) {
        if ((board[i][j] === 1)) p.fill(0);
        else p.fill(255);
        p.rect(i * w, j * w, w - 1, w - 1);
      }
    }
  };

  p.mousePressed = () => {
    init();
  };

  const init = () => {
    for (let i = 0; i < columns; i++) {
      for (let j = 0; j < rows; j++) {
        if (i === 0 || j === 0 || i === columns - 1 || j === rows - 1) board[i][j] = 0;
        else board[i][j] = p.floor(p.random(2));
        next[i][j] = 0;
      }
    }
  };

  const generate = () => {
    for (let x = 1; x < columns - 1; x++) {
      for (let y = 1; y < rows - 1; y++) {
        let neighbors = 0;
        for (let i = -1; i <= 1; i++) {
          for (let j = -1; j <= 1; j++) {
            neighbors += board[x + i][y + j];
          }
        }
        neighbors -= board[x][y];
        if ((board[x][y] === 1) && (neighbors < 2)) next[x][y] = 0;
        else if ((board[x][y] === 1) && (neighbors > 3)) next[x][y] = 0;
        else if ((board[x][y] === 0) && (neighbors === 3)) next[x][y] = 1;
        else next[x][y] = board[x][y];
      }
    }
    const temp = board;
    board = next;
    next = temp;
  };
};

// render the wrapper and the sketch
ReactDOM.render(<P5Wrapper sketch={gameOfLife} />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js"></script>
<div id="root"/>

What could be causing the slowdown?

Rikku
  • 428
  • 6
  • 14
au.re
  • 393
  • 1
  • 8
  • 1
    I edited the code so it runs. Since I didn't see any slowdown I changed size to 1024*768 to be closer to full-screen. – Rikku Feb 10 '18 at 20:17
  • 3
    Your code doesn't utilize React at all for running the game of life simulation. You just make a canvas. – Andy Ray Feb 10 '18 at 22:31
  • 2
    This is not due to your code or the fault of the libraries themselves, but rather your browser. When I ran your code snippet in my browser it ran smoothly. I even checked the frames per second and was achieving a solid 100+ fps. Try debugging it with another browser. –  Jan 19 '19 at 23:28
  • 1
    Jargon note: "p5" is actually the nickname for Processing, the java-based language. The p5.js project and library is referred to as p5js to make it explicit it's the JS one, not the Java one. – Mike 'Pomax' Kamermans Jan 20 '19 at 04:58
  • 2
    Also, you might get better results if you tell React that it should not try to manage that canvas element, by using the `shouldComponentUpdate` function, set to return `false`. – Mike 'Pomax' Kamermans Jan 20 '19 at 05:02
  • 1
    @au.re did you end up finding solution to this? – SpaceBear Mar 21 '19 at 02:57
  • 1
    Have you tried looking at the app using production build of React? `npm run build` then, go into the `build` folder, start up a local static server, then look at the built site. I found that `canvas` rendering performance is very slow in development build of React and there's nothing I could do to improve it. The only solution was to look at it using the production build of React then my framerate is back to 60fps. – Chunky Bacon Jul 19 '19 at 15:49
  • 1
    Coming back to this question almost two years later it still seems to be a problem on Firefox. The slowdown happens also after building the app. I've tried to update all dependencies, and it's still the same. The snippet above runs at ~60fps full screen, but built through `create-react-app` only at 5-6fps (firefox). It does work without issues on chrome. – au.re Jul 25 '19 at 09:15
  • 1
    You might wanna try using `react-p5-wrapper` as described in [this answer](https://stackoverflow.com/a/54901163/9957187). I use it in my React project and it works very well. – samzmann Nov 25 '19 at 15:26

1 Answers1

3

This seems to be caused due to low memory availability of RAM, it will runs smoothly when there sufficient memory available. But when there is less memory P5.js is running at low frame rate.

Brief explanation I believe while we run react applications with node, surely it could hold a huge amount of RAM. Especially when we run react with node using 4GB or less RAM configuration, we could end up P5.js or any graphic content running in very low Frames per seconds.

uplift the RAM or run in another machine

Low memory availability in RAM

Nandha Frost
  • 116
  • 1
  • 14