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

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

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

想法

  1. 向端点发送获取请求,该端点返回包含的 json 数据 图片网址。
  2. 将该数据转换为 javascript 数组。
  3. 根据上面的长度动态创建fabric js画布 数组。
  4. 使用它们的 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]} 
          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

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

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

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

【问题讨论】:

    标签: javascript html fabricjs


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

    results

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

    【讨论】:

      猜你喜欢
      • 2020-10-20
      • 1970-01-01
      • 2015-04-06
      • 2017-06-16
      • 1970-01-01
      • 2011-07-28
      • 1970-01-01
      • 2016-08-06
      • 2016-04-03
      相关资源
      最近更新 更多