【问题标题】:React won't draw anything in the canvas in useEffectReact 不会在 useEffect 中的画布中绘制任何内容
【发布时间】:2022-03-24 08:36:18
【问题描述】:

我用 matter.js 构建了一个 react 网站。我正在使用useEffect 钩子将内容渲染到带有matter.js 的画布上(我发现大部分代码here)。但是,当我尝试在画布上绘制任何其他内容时,什么也没有出现。一切与重要.js 相关的工作。

const scene = useRef()
const isDragging = useRef(false)
const engine = useRef(Engine.create())

useEffect(() => {
  const cw = 1100;
  const ch = 700;
  const render = Render.create({
    canvas: scene.current,
    engine: engine.current,
    options: {
      width: cw,
      height: ch,
      wireframes: false,
      background: 'transparent'
    }
  })

  console.log("gravity " + engine.current.gravity.y + "x : " + engine.current.gravity.x)

  let mouse = Mouse.create(render.canvas);
  let mouseConstraint = MouseConstraint.create(engine.current, {
    mouse: mouse,
    constraint: {
      render: {
        visible: false
      }
    }
  })
  render.mouse = mouse;

  World.add(engine.current.world, [
    Bodies.rectangle(cw / 2, 0, cw, 20, {
      isStatic: true,
      density: 1
    }),
    Bodies.rectangle(cw / 2, ch, cw, 20, {
      isStatic: true,
      density: 1
    }),
    Bodies.rectangle(0, ch / 2, 20, ch, {
      isStatic: true,
      density: 1
    }),
    Bodies.rectangle(cw, ch / 2, 20, ch, {
      isStatic: true,
      density: 1
    }),

    mouseConstraint,
  ])

  Runner.run(engine.current)
  Render.run(render)

  Events.on(mouseConstraint, "mousedown", function(event) {
    handleSelections(mouseConstraint.body)
  })
  Events.on(mouseConstraint, "startdrag", function(event) {
    isDragging.current = true
  })
  Events.on(mouseConstraint, "enddrag", function() {
    isDragging.current = false
  })
  Events.on(engine.current, 'afterUpdate', function() {
    countTen.current = countTen.current + 1;

    if (countTen.current == 10) {
      countTen.current = 0;

      if (selectedObjectRef.current != null) {

        setGraphingPos(selectedObjectRef.current.velocity.y * -1);

        setTicks(ticks + 1)
      }
    }
  })

  // ******************* This part doesn't work **************************
  scene.current.getContext('2d').beginPath();
  scene.current.getContext('2d').arc(100, 100, 20, 0, 2 * Math.PI, false);
  scene.current.getContext('2d').fillStyle = 'red';
  scene.current.getContext('2d').fill();
  // **********************************************************************
  return () => {
    Render.stop(render)
    World.clear(engine.current.world)
    Engine.clear(engine.current)
    render.canvas.remove()
    render.canvas = null
    render.context = null
    render.textures = {}
  }
}, [])
<canvas ref={scene} onClick={ handleMouseDown} className='main-canvas'></canvas>

非常感谢任何形式的帮助!

【问题讨论】:

    标签: javascript html reactjs react-hooks matter.js


    【解决方案1】:

    目前,您在MJS wipes per frame 的同一画布上预先绘制了一次。所以,你画了你的圆圈,然后 MJS 在渲染第一帧时立即擦除画布。随着引擎和渲染器继续运行,您永远不会尝试再次绘制。

    我看到了一些解决方案(至少!)。哪个最合适取决于您的具体用例。

    1. afterRender callback for the render object 内每一帧的画布上绘制。这是您现在最简单、最直接的解决方案,我在下面提供了一个示例。
    2. 在您提供给 MJS 的上面添加一个second transparent canvas。这是通过绝对定位完成的。现在,您可以在此叠加层中做任何您想做的事情,而不会受到 MJS 的干扰。
    3. 无头运行 MJS,这为您提供最大的控制,因为 MJS 内置渲染器是 mostly intended for protoyping(它是物理引擎,而不是图形引擎)。一旦你没有头,你可以随时随地渲染任何你想要的东西。在plain DOM and with Reactp5.js 的其他答案中,我有很多无头渲染的演示。

    顺便说一句,这似乎与 React 或 useEffect 没有任何关系;即使你在 vanilla JS 中注入一个普通的画布,也会出现同样的问题。

    另外,请记住,您绘制的任何内容都与 MJS 完全无关,只是它恰好位于同一画布上。不要指望物理会起作用,除非您使用 MJS 知道的身体坐标。

    虽然您没有提供完整的组件,但这里是上述afterRender 方法的最小概念验证:

    const {useEffect, useRef} = React;
    const {Bodies, Engine, Events, Render, Runner, Composite} = Matter;
    
    const Scene = () => {
      const canvasRef = useRef();
    
      useEffect(() => {
        const cw = 200;
        const ch = 200;
        const engine = Engine.create();
        const ctx = canvasRef.current.getContext("2d");
        const render = Render.create({
          canvas: canvasRef.current,
          engine,
          options: {
            width: cw,
            height: ch,
            wireframes: false,
            background: "transparent",
          }
        });
        Events.on(render, "afterRender", () => {
          const x = Math.cos(Date.now() / 300) * 80 + 100;
          const y = Math.sin(Date.now() / 299) * 80 + 100;
          ctx.beginPath();
          ctx.arc(x, y, 20, 0, 2 * Math.PI);
          ctx.fillStyle = "red";
          ctx.fill();
        });
        Composite.add(engine.world, [
          Bodies.rectangle(cw / 2, 0, cw, 20, {
            isStatic: true,
            density: 1,
          }),
          Bodies.rectangle(cw / 2, ch, cw, 20, {
            isStatic: true,
            density: 1,
          }),
          Bodies.rectangle(0, ch / 2, 20, ch, {
            isStatic: true,
            density: 1,
          }),
          Bodies.rectangle(cw, ch / 2, 20, ch, {
            isStatic: true,
            density: 1,
          }),
        ]);
        Runner.run(engine);
        Render.run(render);
    
        return () => {
          Render.stop(render);
          Composite.clear(engine.world);
          Engine.clear(engine);
          render.canvas.remove();
          render.canvas = null;
          render.context = null;
          render.textures = {};
        };
      }, []);
      return <canvas ref={canvasRef}></canvas>;
    };
    
    ReactDOM.render(<Scene />, document.querySelector("#app"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>
    <div id="app"></div>

    【讨论】:

    • 非常感谢老兄!我会尽快测试代码并更新
    • 我现在选择第一个选项。我很确定第二个选项不适用于 MouseConstraint。
    • 第一种方法完美!!!!你为我节省了很多时间,非常感谢!
    • 啊,关于选项 2 的 MouseConstraint 很好。我没有考虑到这一点。可能有一种解决方法,但我会把它留给后代。
    猜你喜欢
    • 2015-08-26
    • 2013-06-15
    • 2016-12-08
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多