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

Posted

技术标签:

【中文标题】Fabricjs - 在一个文档中渲染多个画布【英文标题】:Fabricjs - Rendering multiple canvases in one document 【发布时间】:2021-01-17 05:29:45 【问题描述】:

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

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

想法

    向端点发送获取请求,该端点返回包含的 json 数据 图片网址。 将该数据转换为 javascript 数组。 根据上面的长度动态创建fabric js画布 数组。 使用它们的 url 将画布背景设置为图像。 (即每个画布将具有从 url 获取的不同背景)

问题

只有最后一个画布有背景图片。

代码

<!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] 
           
          
          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

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

期望的结果将有 10 个不同背景的画布,对应于图像 url。

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

【问题讨论】:

【参考方案1】:

为您创建只需复制代码,然后在本地使用您自己的图像以获得输出 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>

谢谢

【讨论】:

嗨,我在调用 toDataUrl 时收到“可能无法导出受污染的画布”。另外,我真的很想知道为什么我的代码一开始就不起作用。更新帖子。 在本地工作时不要使用远程图像,在上面的示例中有远程 URL,只需将它们下载到文件夹中,然后放入单个文件夹并在 localhost 服务器中运行。它会起作用的。 这对你有帮助吗?【参考方案2】:

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

代码

//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 
        
        
        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 画布。 (显然即使有承诺,结构代码也没有按正确的顺序运行。这可能是由于语法错误。自定义触发器解决了这个问题。)

results

-每个图像作为背景单独出现在其自己的 fabric.js 画布中。 - 每个画布都是独立的。

【讨论】:

以上是关于Fabricjs - 在一个文档中渲染多个画布的主要内容,如果未能解决你的问题,请参考以下文章

是否可以同时在 FabricJS 画布上独立拖放多个对象?

Fabricjs:显示横幅的预览

从画布中删除图像-fabricjs(javascript)

FabricJS:始终在画布上居中对象

在 FabricJS 画布上拖放和删除对象

如何清除画布属性和事件并将其添加回fabricjs?