Fabric.js 旧 canvas 的残余仍然存在

Fabric.js remnants of old canvas remain

我想把一个canvas的内容显示为另一个canvas的背景,然后在上面画一堆矩形。我需要动态改变:

如果我从头开始这个过程是最简单的。我用一个简单的按钮从头开始模仿。然而,在重绘我的 canvas 之后,fabric.js 的先前信息在稍微拖动 canvas 的项目后仍然存在。这意味着旧的 canvas 没有被正确清除。我试过 .clear().depose(),但无济于事。

如果描述含糊不清,这里有一张图片:

还有一个可重现的小例子:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Hello</title>
</head>

<body>
  <canvas id="finalcanvas"></canvas>
  <canvas id="backgroundcanvas" width="200" height="100"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.min.js" type="text/javascript"></script>
  <script>
    function load_plane_onto_active_canvas() {
      var c = document.getElementById('backgroundcanvas');
      var ctx = c.getContext("2d");
      var bg = c.toDataURL("image/png");

      var canvas = new fabric.Canvas('finalcanvas', {
        width: 333,
        height: 333
      });

      canvas.setBackgroundImage(bg, canvas.renderAll.bind(canvas));

      canvas.on("mouse:over", function(e) {
        console.log(e.target)
      });

      // add 100 rectangles
      for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++) {
          rect = new fabric.Rect({
            width: 10,
            height: 10,
            left: j * 15,
            top: i * 15,
            fill: 'green',
          })
          canvas.add(rect);
        }
      }
    }

    window.onload = function() {
      // fill the background canvas with red
      (function() {
        var canvas = document.getElementById("backgroundcanvas");
        var ctx = canvas.getContext("2d");
        ctx.fillStyle = "#FF0000";
        ctx.fillRect(0, 0, 150, 75);
      }())

      load_plane_onto_active_canvas()
    }
  </script>
  <button onclick="load_plane_onto_active_canvas()">click me</button>

</body>

</html>

希望有人能帮帮我!

请注意,您正在 load_plane_onto_active_canvas() 函数中创建 fabric.Canvasnew 实例。因此,当您单击按钮时,现有的 canvases 保持不变,并且您实际上是在新创建的 canvas 上调用 clear()。 DOM 在这一点上变得混乱,有几个嵌套的 canvases 在彼此内部 - 你可以看一下 DOM 检查员看看。

您可以做的是只创建一次 canvas 实例,然后稍后在您的其他函数中使用对它的引用。

const finalCanvas = new fabric.Canvas("finalcanvas", {
  width: 333,
  height: 333
});
// finalCanvas now exists in the global (window) scope

function load_plane_onto_active_canvas() {
  var c = document.getElementById("backgroundcanvas");
  var ctx = c.getContext("2d");
  var bg = c.toDataURL("image/png");
  
  finalCanvas.clear();

  finalCanvas.setBackgroundImage(bg, finalCanvas.renderAll.bind(finalCanvas));

  finalCanvas.on("mouse:over", function (e) {
    // console.log(e.target);
  });

  // add 100 rectangles
  for (i = 0; i < 10; i++) {
    for (j = 0; j < 10; j++) {
      rect = new fabric.Rect({
        width: 10,
        height: 10,
        left: j * 15,
        top: i * 15,
        fill: "green"
      });
      finalCanvas.add(rect);
    }
  }
}

window.onload = function () {
  // fill the background canvas with red
  (function () {
    var canvas = document.getElementById("backgroundcanvas");
    var ctx = canvas.getContext("2d");
    ctx.fillStyle = "#FF0000";
    ctx.fillRect(0, 0, 150, 75);
  })();

  load_plane_onto_active_canvas();
};
document.querySelector("#b1").onclick = () => load_plane_onto_active_canvas();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.js"></script>
<canvas id="finalcanvas"></canvas>
<canvas id="backgroundcanvas" width="200" height="100"></canvas>
<button id="b1">start from scratch</button>