如何解决fabricjs中的canvas层级生成错乱?

有一个使用了fabricjs(版本:5.3.0)写的弹框组件,大致为:

import { Modal } from "antd";
import { fabric } from "fabric";

const Test: React.FC<any> = ({ a, b, c }) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const [canvas, setCanvas] = useState<fabric.Canvas>();

  useEffect(() => {
    initCanvas();
  }, [a, b]);

  const initCanvas = () => {
    let imgUrl = a.img.Url;
    let imgName = a.img.name;
    let img = new Image();
    img.src = imgUrl;

    // 设置背景图片
    img.onload = () => {
      let c = new fabric.Canvas(canvasRef.current, {
        width: img.width,
        height: img.height,
      });
      c.setBackgroundImage(
        imgUrl,
        c.requestRenderAll.bind(c),
        {
          scaleX: 1,
          scaleY: 1,
          name: imgName,
          left: 150,
          top: 150,
        }
      );
      setCanvas(c);
    }
  };

  ......

  const onOk = () => {
        ...
  }

  const onModalCancel = () => {
        ...
  }

  return (
    <Modal
      open={open}
      onOk={onOk}
      onCancel={onModalCancel}
      forceRender={true}
      destroyOnClose={true}
    >
      <div>
        <canvas id="canvas" ref={canvasRef} />
      </div>
    </Modal>
  )
};
export default Test;

正常情况下应该是canvas-container下有一个lower-canvas和一个upper-canvas,
1682500565168.png

但是现在总是出现生成了多层嵌套的canvas,外层嵌套的canvas会丢失lower-canvas,导致数据正确但是绘制总是出问题,无法选中绘制图形或者总是只显示第一次的数据,感觉canvas第一次初始化后,之后都没有正确初始化
1682500710610.png

请问这个问题该怎么解决呢?

阅读 2.4k
1 个回答

这个问题可能是因为在每次重新初始化画布时候,没有清除之前的画布实例。要解决这个问题,可以在 initCanvas 函数中检查 canvas 状态,如果已经存在一个画布实例,就先销毁它,然后再创建一个新的画布实例。

修改一下initCanvas 函数:



const initCanvas = () => {
  // 如果已存在画布实例,先销毁它
  if (canvas) {
    canvas.dispose();
  }

  let imgUrl = a.img.Url;
  let imgName = a.img.name;
  let img = new Image();
  img.src = imgUrl;

  // 设置背景图片
  img.onload = () => {
    let c = new fabric.Canvas(canvasRef.current, {
      width: img.width,
      height: img.height,
    });
    c.setBackgroundImage(
      imgUrl,
      c.requestRenderAll.bind(c),
      {
        scaleX: 1,
        scaleY: 1,
        name: imgName,
        left: 150,
        top: 150,
      }
    );
    setCanvas(c);
  }
};
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏