Fabricjs - 在一个文档中渲染多个画布

Fabricjs - Rendering multiple canvases in one document

我在动态创建和设置 canvas 背景时遇到问题。 我希望用户能够用文本和形状注释图像,这就是我这样做的原因。

我想知道为什么这段代码会产生这样的输出

想法

  1. 向 returns json 数据包含的端点发送获取请求 图片 urls.
  2. 将该数据转换为 javascript 数组。
  3. 根据上面的长度动态创建fabric js canvases 数组。
  4. 使用 url 为图像设置 canvas 背景。 (即每个 canvas 的背景都取自 url)

问题

只有最后一个 canvas 有背景图片。

代码

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
      }
    </style>
    <script
      src="https://code.jquery.com/jquery-3.5.1.min.js"
      integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
      crossorigin="anonymous"
    ></script>
  </head>
  <body>
    <script src="fabric.js"></script>
    <!--new start-->
    <script>
      //procedurally load images from a given source
      //endpoint with image links
      var end_point = "http://localhost:8080/endpoint.php";
      var settings = {
        url: "http://localhost:8080/endpoint.php",
        method: "GET",
      };
      //get the images array from end point
      $.ajax(settings).done(function (images_json) {
        var images = JSON.parse(images_json);
        //procedurally create farbric.js canvas for each image element in the html document and set their background as the corresponding image.
        //for each item in the images array, create a fabric.js canvas with its background set as the image itself
        var canvas_array = [];
        for (var i = 0, len = images.length; i < len; i++) {
          //console.log(images[i]);
          //create canvas and then make it a fabric canvas
          document.body.innerHTML += `<canvas 
          id=${[i]} 
          width="1000" 
          height="200"
          style="border-style: solid;">
          </canvas>`;
          //canvases stored in canvas_array
          canvas_array[i] = new fabric.Canvas(`${[i]}`);
          console.log(canvas_array[i]);
          //set canvas background as the image
          canvas_array[i].setBackgroundImage(
            `${images[i]}`,
            canvas_array[i].renderAll.bind(canvas_array[i]),
            {
              backgroundImageOpacity: 1,
              backgroundImageStretch: false,
            }
          );
        }
      });
    </script>
    <!--new end-->
  </body>
</html>

结果

result

注意 该代码生成正确数量的 canvases。但是背景图片似乎不起作用

期望的结果将有 10 canvas 个具有与图像对应的不同背景 url 个。

我是 fabric.js 的新手,这可能是一个愚蠢的错误。

已为您创建,只需复制代码,然后在本地使用您自己的图像即可在输出中获得实际的完整结果div(将生成图像)。

      let CANVAS_LIST = [];
        let imageList = [
            'https://homepages.cae.wisc.edu/~ece533/images/airplane.png',
            'https://homepages.cae.wisc.edu/~ece533/images/arctichare.png',
            'https://homepages.cae.wisc.edu/~ece533/images/baboon.png',
        ]

        imageList.forEach(element => {


            let canvasElement = document.createElement("canvas");
            canvasElement.width = '300';
            canvasElement.height = '300';
            $("#canvas_container").append(canvasElement);
            let canvas = new fabric.Canvas(canvasElement);

            // Adding Example Text here. 
            canvas.add(new fabric.Text('This text is added', {
                fontFamily: 'Delicious_500',
                color: 'red',
                left: 10,
                top: 100
            }));
            // Setting up  Background to dynamic generated Canvas
            canvas.setBackgroundImage(
                `${element}`,
                canvas.renderAll.bind(canvas),
                {
                    backgroundImageOpacity: 1,
                    backgroundImageStretch: false,
                }
            );

            CANVAS_LIST.push(canvas);
        });

        setTimeout(() => {
            generateOutput();
        }, 3000);
        function generateOutput() {
            $("#output").empty();
            CANVAS_LIST.forEach(canvas => {
                let image = $("<img>").attr({
                    width: 200,
                    height: 200,
                    src: canvas.toDataURL()

                });

                image.css({ marginLeft: '20px' });

                $("#output").append(image);
            })
        }
<!DOCTYPE html>
<html>
<head>
    <style>
        body {}
    </style>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"
        integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>

<body>
    <div class="container">
        <div id="canvas_container">
        </div>
        <button onclick="generateOutput()"> Show output</button>
        <div id="output">

        </div>
    </div>
   
</body>
</html>

谢谢

使用远程源是一个严格的要求。我尝试了几种方法,终于成功了。

代码

//c global variable
var n_can_arr = [];
var f_can_arr = [];
var img_arr = [];

//c procedurally load images from a given source
$.ajax({
  url: "http://localhost:8080/endpoint.php",
  type: "GET",
  dataType: "json", //c added data type
  success: function (res) {
    for (var index = 0; index < res.length; index++) {
      //c create canvas
      var setHtml = `<canvas
        id=${index} 
        width="1000"
        height="800"
        style="border-style: solid;">
        </canvas>`;
      document.body.innerHTML += setHtml;
      //c update canvas and image arrays
      n_can_arr.push(index);
      img_arr.push(res[index]);
    }
    //c call image set after the loop is over
    $(document).trigger("images_set");
  },
});

//c on image_set called
$(document).bind("images_set", () => {
  //c for each element of normal canvas array, create a fabric js canvas and set its background
  for (var i = 0; i < n_can_arr.length; i++) {
    create_canvas(i);
  }
  //c for each element of fabric canvas array, apply the extend canvas function
  extend_canvas();
});

function create_canvas(i) {
  //c create fabric js canvases with normal canvas id from canvas arrray
  var canvas = new fabric.Canvas(`${i}`);
  f_can_arr.push(canvas);

  //c set canvas background using image array
  canvas.setBackgroundImage(img_arr[i], canvas.renderAll.bind(canvas), {
    backgroundImageOpacity: 1,
    backgroundImageStretch: false,
  });
}

function extend_canvas() {
  f_can_arr.forEach((canvas) => {
    var origX, origY, isDown, mode_rect, mode_uline, mode_free, pointer;

    //c setting keypress listener
    $(window).on("keypress", (e) => {
      console.log(e.key);
      //c drawing rectangles
      if (e.key == 1) {
        var rect;
        console.log("Box");
        isDown = true;
        mode_free = false;
        mode_uline = false;
        mode_rect = true;

        //c canvas event listners
        canvas.on("mouse:down", function (o) {
          isDown = true;
          if (mode_rect) {
            pointer = canvas.getPointer(o.e);
            origX = pointer.x;
            origY = pointer.y;
            console.log(origX + "," + origY);
            rect = new fabric.Rect({
              left: origX,
              top: origY,
              originX: "left",
              originY: "top",
              width: pointer.x - origX,
              height: pointer.y - origY,
              fill: "red",
              angle: 0,
              fill: "rgba(255,0,0,0.0)",
              stroke: "black",
              strokeWidth: 1,
            });
            canvas.add(rect);
          }
        });

        canvas.on("mouse:move", function (o) {
          if (mode_rect) {
            if (isDown) {
              var pointer = canvas.getPointer(o.e);

              if (origX > pointer.x) {
                rect.set({ left: Math.abs(pointer.x) });
              }
              if (origY > pointer.y) {
                rect.set({ top: Math.abs(pointer.y) });
              }

              rect.set({ width: Math.abs(origX - pointer.x) });
              rect.set({ height: Math.abs(origY - pointer.y) });

              canvas.renderAll();
            }
          }
        });
      }

      //c freehand drawing/Highlighter
      if (e.key == 2) {
        console.log("freehand");
        isDown = true;
        mode_free = true;
        mode_uline = false;
        mode_rect = false;
        canvas.isDrawingMode = 1;
        canvas.freeDrawingBrush.color = "rgba(255,0,0,0.2)";
        canvas.freeDrawingBrush.width = 20;

        //c canvas event listners
        canvas.on("mouse:down", function (o) {
          isDown = true;
          if (mode_free) {
            canvas.renderAll();
          }
        });
      }

      //c line mode
      if (e.key == 3) {
        var line;
        console.log("line");
        isDown = true;
        mode_free = false;
        mode_uline = true;
        mode_rect = false;

        //c canvas event listners
        canvas.on("mouse:down", function (o) {
          isDown = true;
          var pointer = canvas.getPointer(o.e);
          var points = [pointer.x, pointer.y, pointer.x, pointer.y];
          if (mode_uline) {
            line = new fabric.Line(points, {
              strokeWidth: 3,
              fill: "red",
              stroke: "red",
              originX: "center",
              originY: "center",
              targetFindTolerance: true,
            });
            canvas.add(line);
          }
        });
        canvas.on("mouse:move", function (o) {
          if (!isDown) return;
          var pointer = canvas.getPointer(o.e);

          if (mode_uline) {
            line.set({ x2: pointer.x, y2: pointer.y });
            canvas.renderAll();
          }
        });
      }

      //c deleting a selected shape
      if (e.key == 4) {
        var activeObject = canvas.getActiveObject();
        if (activeObject) {
          canvas.remove(activeObject);
        }
      }

      //c cancling freehand drawing mode
      if (e.key == "x") {
        console.log("freehand mode cancled");
        canvas.isDrawingMode = 0;
      }
    });

    //c removing previous event listeners and resetting some global variables
    canvas.on("mouse:up", function (o) {
      isDown = false;
      mode_free = false;
      mode_uline = false;
      mode_rect = false;
      canvas.off("mouse:down");
      canvas.off("mouse:move");
    });
  });
}

function save_canvas() {}

function load_canvas() {}

解决方案

我在 ajax 调用后设置了自定义触发事件。当触发事件被触发时,我才创建 fabricjs canvases。 (显然,即使有承诺,结构代码也不是 运行 正确的顺序。这可能是由于语法错误。自定义触发器解决了这个问题。)

results

-每张图片单独出现在自己的 fabric.js canvas 中作为背景。 -每个canvas都是独立的。