1

I use Matter js for physics and canvas for rendering 100 items, after every change in props the app gets slower and slower. At the same time, subsequent downloads with the same props occur instantly, i.e. past images and elements remained and were not deleted, which loads the application. enter image description here

"Top" dropdown menu changes props for bubbles component, code:

const Bubbles = ({ coins }) => {
  var winwidth = window.innerWidth;
  var winheight = window.innerHeight - 80;

  const [physics, setPhysics] = useState({
    frictionAir: 0,
    friction: 0.2,
    frictionStatic: 0.2,
    restitution: 0.1,
    inertia: Infinity,
    density: 0.8,
  });

  useEffect(() => {
    setSize(coins);
    // create an engine
    const engine = Engine.create();
    const world = engine.world;
    // create a renderer
    const render = Render.create({
      element: document.querySelector(".bubbles"),
      engine: engine,
      options: {
        width: winwidth,
        height: winheight,
        showAngleIndicator: false,
        background: "transparent",
        wireframeBackground: "transparent",
        wireframes: false,
        showDebug: false,
      },
    });

    const bubbles = [];

    // create a canvas
    const canvas = document.createElement("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    document.querySelector(".bubbles").appendChild(canvas);
    const ctx = canvas.getContext("2d");

    // create 100 random bubbles
    for (let i = 0; i < coins.length; i++) {
      const x = Math.random() * window.innerWidth;
      const y = Math.random() * window.innerHeight;
      const bubble = Bodies.circle(x, y, coins[i].size / 2, {
        ...physics,
        render: {
          fillStyle: "transparent",
        },
      });
      Composite.add(engine.world, bubble);
      // store the bubble and its content data in an object
      bubbles.push({
        bubble,
        content: {
          radius: coins[i].radius,
          text: `${i + 1}`,
        },
      });
    }

    // update the canvas on each engine update
    Matter.Events.on(engine, "afterUpdate", function () {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      for (let i = 0; i < bubbles.length; i++) {
        const bubble = coins[i];
        const pos = bubbles[i].bubble.position;
        const size = bubble.size;
        const text = bubble.symbol;
        const priceChange = bubble.price_change_percentage_24h.toFixed(1);
        const image = new Image();
        image.src = bubble.image;

        if (priceChange > 0) {
          ctx.fillStyle = "rgba(5, 222, 5, 0.15)";
          ctx.strokeStyle = "rgba(5, 222, 5, 0.6)";
        } else if (priceChange < 0) {
          ctx.fillStyle = "rgba(166, 53, 53, 0.15)";
          ctx.strokeStyle = "rgba(166, 53, 53, 0.8)";
        } else {
          ctx.fillStyle = "rgba(255, 255, 89, 0.069)";
          ctx.strokeStyle = "rgba(187, 231, 11, 0.443)";
        }

        ctx.beginPath();
        ctx.arc(pos.x, pos.y, size / 2, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();

        ctx.drawImage(
          image,
          pos.x - size / 5,
          pos.y - size / 2.5,
          size / 2.5,
          size / 2.5
        );

        ctx.font = `${size / 6}px Acme`;
        ctx.fillStyle = "white";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(text, pos.x, pos.y + size / 6.5);

        ctx.font = `${size / 6.5}px Acme`;
        ctx.fillStyle = "white";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(priceChange + "%", pos.x, pos.y + size / 3);
      }
    });

    // fit the render viewport to the scene
    window.addEventListener("onload", () => {
      Render.lookAt(render, {
        min: { x: 0, y: 0 },
        max: { x: 100000, y: 10000 },
      });
    });
    // run the engine
    Runner.run(engine);

    // run the renderer
    Render.run(render);

    return () => {
      // stop the engine and renderer
      Engine.clear(engine);
      Render.stop(render);
      Runner.stop(engine);
      // remove the canvas from the DOM
      canvas.remove();
    };
  }, [coins]);

  return <></>;
};

export default Bubbles;

after each update of the coins props, I deleted the canvas and stopped the engine, but still the speed worsened

return () => {
  // stop the engine and renderer
  Engine.clear(engine);
  Render.stop(render);
  Runner.stop(engine);
  // remove the canvas from the DOM
  canvas.remove();
};

I want to either stop re-creating the engine and the matter js world, canvas with images. Only without window.location.reload(), because I need to save props like "Top" and "Earth, Trampoline", etc.

RubenSmn
  • 4,091
  • 2
  • 5
  • 24
FakeHuman
  • 21
  • 3
  • Using MJS and React can be tricky. Try adapting [this answer](https://stackoverflow.com/a/71104810/6243352) which should be a bit more in the ballpark--cleaning up the `Events.on` may do the job. Avoid `document.createElement` in favor of refs. Curious to hear how it goes and feel free to post a [self answer](https://stackoverflow.com/help/self-answer) if you do work something out. – ggorlen Feb 04 '23 at 15:30
  • 1
    @ggorlen, oh my god, thanks, i solved the problem. I didn't properly clear the js canvas value and also didn't set events.off when unmounting the component. – FakeHuman Feb 04 '23 at 16:35

1 Answers1

1

I solved the problem. I didn't properly clear the js canvas value and also didn't set events.off when unmounting the component. Here is the solution to my problem

 return () => {
      //set Matter Js events off. drawCanvas - afterUpdate event function
      Events.off(engine, 'afterUpdate', drawCanvas);
      Render.stop(render);
      Composite.clear(engine.world);
      Runner.stop(engine)
      Engine.clear(engine);
      render.canvas.remove();
      render.canvas = null;
      render.context = null;
      // remove the canvas from the DOM
      canvas.remove();
    };
FakeHuman
  • 21
  • 3