Search code examples
javascriptfabricjs

Click on an fabricjs element is not recognized


I am trying to build a simple editor using fabricjs.

I did the following:

<!DOCTYPE html>
<html lang="en">

<head>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
  <style>
    html,
    body {
      height: 100%;
      width: 100%;
      padding: 0;
      margin: 0;
    }
    
    body {
      touch-action: none;
      background-image: linear-gradient(to bottom left, rgb(214, 240, 201) 10%, rgba(255, 231, 191, 1) 80%);
      -webkit-user-select: none;
      -moz-user-select: -moz-none;
      -ms-user-select: none;
      user-select: none;
    }
    
    .input-group {
      padding: 4px;
    }
    
    .canvas-container {
      margin: 0 auto;
      width: 100%;
      overflow: hidden;
      background: url(./transparent.png);
      background-size: 15px 15px;
      box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
    }
    
    .actived {
      background: #fff9a8;
    }
    
    .list-group {
      line-height: 35px;
    }
    
    .svg-icon {
      width: 1em;
      height: 1em;
    }
    
    .svg-icon path,
    .svg-icon polygon,
    .svg-icon rect {
      fill: #4691f6;
    }
    
    .svg-icon circle {
      stroke: #4691f6;
      stroke-width: 1;
    }
    
    .fl {
      float: left;
    }
    
    .fr {
      float: right;
    }
    
    .input-group-text {
      background-color: #f4f4f4;
    }
    
    .list-group-item {
      padding: 2px 10px;
      ;
      cursor: pointer;
    }
    
    .list-group {
      border-radius: 0;
      text-align: left;
    }
  </style>
</head>

<body>
  <div class="container-fluid h-100">
    <div class="row h-100">
      <div class="col-sm-3 border-end text-center h-100 overflow-scroll bg-light py-3">
        <hr>
        <div class="form-floating w-100 mb-3 tour5">
          <h6 class="mb-3">Add Element</h6>
          <button class="btn btn-outline-primary" onclick="addText();" data-toggle="tooltip" data-placement="top" title="" data-bs-original-title="Add Text" aria-label="Add Text"><i
                            class="fa fa-font"></i></button>
          <button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick="  canvas.add(new fabric.Circle({ name: genNextName(), originX:'center', originY:'center',  radius: 30, fill: '#000', top: 100, left: 100 }));" data-bs-original-title="Add Circle"
            aria-label="Add Circle"><i
                            class="fa fa-circle"></i></button>
          <button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick="  canvas.add(new fabric.Triangle({  name: genNextName(),  originX:'center', originY:'center', height:100, width:100, fill: '#000', top: 100, left: 100 }));"
            data-bs-original-title="Add Triangle">
                        <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="triangle" role="img"
                            xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class=""
                            style="height: 16px;top: 9px;">
                            <path fill="currentColor"
                                d="M329.6 24c-18.4-32-64.7-32-83.2 0L6.5 440c-18.4 31.9 4.6 72 41.6 72H528c36.9 0 60-40 41.6-72l-240-416z"
                                class=""></path>
                        </svg>
                    </button>
        </div>
        <hr>
      </div>
      <div class="col-sm-6 my-auto py-4 overflow-hidden">
        <div class="canvas-container" style="width: 329px; height: 329px; position: relative; user-select: none;"><canvas id="c" class="lower-canvas" width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: none; user-select: none;"></canvas><canvas class="upper-canvas " width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: manipulation; user-select: none; cursor: default;"></canvas>
        </div>
      </div>
      <div class="col-sm-3 border-start py-3 h-100 overflow-scroll bg-light text-center">
        <form class="form-inline pt-4" id="f" onsubmit="return false;" style="display: none;">
          <div class="form-floating w-100 mb-4" style="">
            <textarea type="text" class="form-control form-control-sm" name="text" oninput="canvas.getActiveObject().set({'text':this.value}); canvas.renderAll();" onmouseover="this.style.height = (this.scrollHeight)+'px';" rows="10" autocomplete="off"></textarea>
            <label for="floatingInput" class="lable-sm">Text</label>
          </div>
          <div class="input-group input-group-sm mb-3 w-100 tour13">
            <span class="input-group-text" id="inputGroup-sizing-sm">MaxHeight to Fit Text</span>
            <input type="number" class="form-control" name="maxHeight" onkeyup="hide_mh_box(); show_mh_box();" onblur="hide_mh_box();" onfocus="show_mh_box();" autocomplete="off">
          </div>
        </form>
      </div>
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
  <script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
  <script src="https://unpkg.com/[email protected]/dist/fabric.min.js"></script>
  <script src="https://rawcdn.githack.com/lyzerk/fabric-history/8c223cbdc8305307b4a8f8710f97da54d9146ffa/src/index.js"></script>
  <script src="https://rawgit.com/fabricjs/fabric.js/master/lib/centering_guidelines.js"></script>
  <script src="https://rawgit.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>

  <script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>

  <script>
    var canvas;
    var apiUrl;
    var startedLoadingFamilies = false;
    var to;
    var scale;

    fabric.Text.prototype.set({
      _getNonTransformedDimensions() {
        return new fabric.Point(this.width, this.height).scalarAdd(this.padding);
      },
      _calculateCurrentDimensions() {
        return fabric.util.transformPoint(this._getTransformedDimensions(), this.getViewportTransform(), true);
      }
    });

    function fitCanvas(w, h) {
      var scaleW = (document.querySelectorAll(".col-sm-6")[0].offsetWidth - 100) / w;
      var scaleH = (document.querySelectorAll("body")[0].offsetHeight - 100) / h;
      scale = Math.min(scaleH, scaleW);

      if (scale > 1) {
        scale = 1;
      }


      canvas.setZoom(scale);
      canvas.setWidth(w * scale);
      canvas.setHeight(h * scale);

      initAligningGuidelines(canvas);
      initCenteringGuidelines(canvas);

      canvas.renderAll();
      console.log("finished!!");

    }

    (function() {
      canvas = new fabric.Canvas('c', {
        allowTouchScrolling: true
      });
      WebFont.load({
        google: {
          families: ["Inter:200"]
        },
        active: function() {
          canvas.loadFromJSON({
            "height": "500",
            "width": "500",
            "edit": "yes",
            "objects": [],
            "backgroundImage": {
              "crossOrigin": "anonymous"
            }
          }, function() {
            fitCanvas(500, 500);
          })
        }
      });

      canvas.on('before:render', function(opt) {
        canvas.getObjects().map(function(o, i) {
          if (o.type.toLowerCase() == "textbox") {
            var maxH = (o.maxHeight) ? (o.maxHeight) : (canvas.height);
            o.set({
              'maxHeight': maxH
            });
            if (o.fontSize > 0 && (maxH > o.fontSize)) {
              while (o.height > maxH) {
                o.set({
                  'fontSize': o.fontSize - 1
                });
              }
            }
          }

          if (o.circleFrame) {
            o.set({
              clipPath: new fabric.Circle({
                radius: o.width / 2,
                originX: 'center',
                originY: 'center'
              })
            });

          }

          if ((o.rx || o.ry) && o.type == "image") {

            let rx = (o.rx || 0);
            let ry = (o.ry || 0);

            o.set({
              clipPath: new fabric.Rect({
                rx: rx,
                ry: ry,
                height: o.height,
                width: o.width,
                originX: 'center',
                originY: 'center'
              })
            });

          }
        });
      });

    })();
  </script>
  <script>
    fabric.Object.prototype.objectCaching = false;

    function changeDim() {
      fitCanvas($("#widthC").val(), $("#heightC").val());
    }

    function setCanvasBI(src, o = "1") {
      if (!src) {
        src = $("#canvasBI").val();
      }
      if (src.length == 0) {
        src = new fabric.Image('');
      }
      canvas.setBackgroundImage(src, canvas.renderAll.bind(canvas), {
        opacity: o
      });
    }

    (function() {

      $(document).on("mouseenter", "[data-label]", function() {
        $("#font-search").val($(this).data("label"));
        loadFont($(this).data("label"));
      });

      fabric.Canvas.prototype.getItemByAttr = function(attr, name) {
        var object = null,
          objects = this.getObjects();
        for (var i = 0, len = this.size(); i < len; i++) {
          if (objects[i][attr] && objects[i][attr] == name) {
            object = objects[i];
            break;
          }
        }
        return object;
      };

      $("form#f").hide();

      var activeObject;

      $("#f input, #f select").on("input", function() {
        if (["height", "width", "top", "left", "strokeWidth", "charSpacing"].includes(this.name)) {
          canvas.getActiveObject().set(this.name, parseFloat(this.value)).setCoords();
        } else {
          canvas.getActiveObject().set(this.name, this.value).setCoords();
        }
        canvas.renderAll();
      });

      canvas.preserveObjectStacking = true;

      fabric.Object.prototype.toObject = (function(toObject) {
        return function() {
          return fabric.util.object.extend(toObject.call(this), {
            name: this.name,
            text: this.text
          });
        };
      })(fabric.Object.prototype.toObject);

      canvas.on('object:scaling', function(e) {
        if (e.target.toObject().type != "image" && e.target.toObject().type != "circle") {
          e.target.set({
            width: e.target.width * e.target.scaleX,
            height: e.target.height * e.target.scaleY,
            scaleX: 1,
            scaleY: 1
          })
        }
      });

      canvas.on('object:modified', function(opt) {
        document.body.style.cursor = 'progress';
      });

      canvas.on("after:render", function() {

        canvas.includeDefaultValues = false;
        canvas.toObject().objects.forEach(function(layer, id) {

          if (typeof layer.name !== 'undefined') {
            canvas.getItemByAttr(`name`, layer.name).set({
              "name": String.fromCharCode(65 + id).toLowerCase()
            })
            var actived = '';
            if (canvas.getActiveObject()) {
              actived = (canvas.getActiveObject().name == layer.name) ? " actived" : "";
            }
          }
        });
        document.body.style.cursor = 'default'
      });

      canvas.on("selection:created", function(obj) {
        if ("image" == obj.target.type) {
          canvas.getActiveObject().setControlsVisibility({
            mb: false,
            ml: false,
            mt: false,
            mr: false
          });
        }
        $("form#f input[type!='hidden'], #f select").parent().hide();
        $("form#f").hide();
        canvas.renderAll();
        showForm();
      });

      canvas.on("selection:updated", function(obj) {
        if ("image" == obj.target.type) {
          canvas.getActiveObject().setControlsVisibility({
            mb: false,
            ml: false,
            mt: false,
            mr: false
          });
        }
        canvas.renderAll();
        $("form#f").hide();
        $("form#f input[type!='hidden'] , #f select, #f textarea").parent().hide();
        showForm();
      });

      canvas.on("selection:cleared", function() {
        canvas.renderAll();
        $("form#f").hide();
        $("form#f input[type!='hidden'], #f select, #f textarea").parent().hide();
      });

      canvas.hoverCursor = 'default';
      canvas.on('mouse:over', function(e) {
        if (e.target) {
          e.target._renderControls(canvas.contextTop, {
            hasControls: false
          })
        }
      });

      canvas.on('mouse:out', function(e) {
        canvas.clearContext(canvas.contextTop);
      });
      canvas.on('mouse:down', function(e) {
        canvas.clearContext(canvas.contextTop);
      });

      function showForm() {

        $("form#f").show();
        activeObject = canvas.getActiveObject();
        var v;
        for (i in activeObject) {
          v = activeObject[i];

          if (typeof v != "undefined") {
            $("textarea[name='" + i + "']").val(v).parent().show();
            $("input[name='" + i + "']").val(v).parent().show();
            $("select[name='" + i + "']").val(v).parent().show();
          }
        }
      }

      addText = function() {
        var text = new fabric.Textbox("Edit this Text", {
          name: genNextName(),
          left: canvas.getWidth() / canvas.getZoom() / 2,
          top: canvas.getHeight() / canvas.getZoom() / 2,
          width: (canvas.getWidth() / canvas.getZoom()) / 2,
          fill: "#000000",
          originX: "center",
          originY: "center",
          fontFamily: "Inter",
          fontWeight: 400,
          fontSize: 60,
          padding: 20
        });
        text.setControlsVisibility({
          mt: false,
          mb: false,
          ml: true,
          mr: true,
          tl: true,
          tr: true,
          bl: true,
          br: true
        });

        canvas.add(text);
        canvas.setActiveObject(text);
        canvas.renderAll();
      };

    })();

    function hide_mh_box() {
      canvas.remove(canvas.getItemByAttr("isBB", true));
    }

    function show_mh_box() {
      var h = parseInt($("[name=maxHeight]").val());
      var n = new fabric.Rect({
        top: canvas.getActiveObject().get('top'),
        left: canvas.getActiveObject().get('left'),
        width: canvas.getActiveObject().get('width'),
        height: h,
        originX: canvas.getActiveObject().get('originX'),
        originY: canvas.getActiveObject().get('originY'),
        angle: canvas.getActiveObject().get('angle'),
        opacity: 1,
        strokeWidth: 2,
        stroke: "#FF00FF",
        fill: "rgba(0,0,0,0)",
        evented: !1,
        isBB: true
      });
      canvas.add(n);
      canvas.renderAll();
    }

    var visited = [];
  </script>

  <script>
    function genNextName() {
      canvas.renderAll();
      var total = canvas.getObjects().length;
      return String.fromCharCode(65 + total).toLowerCase()
    }
  </script>
</body>

</html>

When I click on an element f.ex. the triangle it is added to the canvas. When I click on the added triangle a menu on the right should go up. However, the element does not get selected.

enter image description here

Any suggestions what I am doing wrong?

I appreciate your replies!


Solution

  • you have second canvas element next to your canvas, it prevents from clicking on first canvas element, removing this second canvas solves this issue

    <canvas class="upper-canvas " width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: manipulation; user-select: none; cursor: default;"></canvas>
    

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" />
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
      <style>
        html,
        body {
          height: 100%;
          width: 100%;
          padding: 0;
          margin: 0;
        }
        
        body {
          touch-action: none;
          background-image: linear-gradient(to bottom left, rgb(214, 240, 201) 10%, rgba(255, 231, 191, 1) 80%);
          -webkit-user-select: none;
          -moz-user-select: -moz-none;
          -ms-user-select: none;
          user-select: none;
        }
        
        .input-group {
          padding: 4px;
        }
        
        .canvas-container {
          margin: 0 auto;
          width: 100%;
          overflow: hidden;
          background: url(./transparent.png);
          background-size: 15px 15px;
          box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
        }
        
        .actived {
          background: #fff9a8;
        }
        
        .list-group {
          line-height: 35px;
        }
        
        .svg-icon {
          width: 1em;
          height: 1em;
        }
        
        .svg-icon path,
        .svg-icon polygon,
        .svg-icon rect {
          fill: #4691f6;
        }
        
        .svg-icon circle {
          stroke: #4691f6;
          stroke-width: 1;
        }
        
        .fl {
          float: left;
        }
        
        .fr {
          float: right;
        }
        
        .input-group-text {
          background-color: #f4f4f4;
        }
        
        .list-group-item {
          padding: 2px 10px;
          ;
          cursor: pointer;
        }
        
        .list-group {
          border-radius: 0;
          text-align: left;
        }
      </style>
    </head>
    
    <body>
      <div class="container-fluid h-100">
        <div class="row h-100">
          <div class="col-sm-3 border-end text-center h-100 overflow-scroll bg-light py-3">
            <hr>
            <div class="form-floating w-100 mb-3 tour5">
              <h6 class="mb-3">Add Element</h6>
              <button class="btn btn-outline-primary" onclick="addText();" data-toggle="tooltip" data-placement="top" title="" data-bs-original-title="Add Text" aria-label="Add Text"><i
                                class="fa fa-font"></i></button>
              <button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick="  canvas.add(new fabric.Circle({ name: genNextName(), originX:'center', originY:'center',  radius: 30, fill: '#000', top: 100, left: 100 }));" data-bs-original-title="Add Circle"
                aria-label="Add Circle"><i
                                class="fa fa-circle"></i></button>
              <button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick="  canvas.add(new fabric.Triangle({  name: genNextName(),  originX:'center', originY:'center', height:100, width:100, fill: '#000', top: 100, left: 100 }));"
                data-bs-original-title="Add Triangle">
                            <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="triangle" role="img"
                                xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class=""
                                style="height: 16px;top: 9px;">
                                <path fill="currentColor"
                                    d="M329.6 24c-18.4-32-64.7-32-83.2 0L6.5 440c-18.4 31.9 4.6 72 41.6 72H528c36.9 0 60-40 41.6-72l-240-416z"
                                    class=""></path>
                            </svg>
                        </button>
            </div>
            <hr>
          </div>
          <div class="col-sm-6 my-auto py-4 overflow-hidden">
            <div class="canvas-container" style="width: 329px; height: 329px; position: relative; user-select: none;"><canvas id="c" class="lower-canvas" width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: none; user-select: none;"></canvas>
            </div>
          </div>
          <div class="col-sm-3 border-start py-3 h-100 overflow-scroll bg-light text-center">
            <form class="form-inline pt-4" id="f" onsubmit="return false;" style="display: none;">
              <div class="form-floating w-100 mb-4" style="">
                <textarea type="text" class="form-control form-control-sm" name="text" oninput="canvas.getActiveObject().set({'text':this.value}); canvas.renderAll();" onmouseover="this.style.height = (this.scrollHeight)+'px';" rows="10" autocomplete="off"></textarea>
                <label for="floatingInput" class="lable-sm">Text</label>
              </div>
              <div class="input-group input-group-sm mb-3 w-100 tour13">
                <span class="input-group-text" id="inputGroup-sizing-sm">MaxHeight to Fit Text</span>
                <input type="number" class="form-control" name="maxHeight" onkeyup="hide_mh_box(); show_mh_box();" onblur="hide_mh_box();" onfocus="show_mh_box();" autocomplete="off">
              </div>
            </form>
          </div>
        </div>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
      <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
      <script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
      <script src="https://unpkg.com/[email protected]/dist/fabric.min.js"></script>
      <script src="https://rawcdn.githack.com/lyzerk/fabric-history/8c223cbdc8305307b4a8f8710f97da54d9146ffa/src/index.js"></script>
      <script src="https://rawgit.com/fabricjs/fabric.js/master/lib/centering_guidelines.js"></script>
      <script src="https://rawgit.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
    
      <script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>
    
      <script>
        var canvas;
        var apiUrl;
        var startedLoadingFamilies = false;
        var to;
        var scale;
    
        fabric.Text.prototype.set({
          _getNonTransformedDimensions() {
            return new fabric.Point(this.width, this.height).scalarAdd(this.padding);
          },
          _calculateCurrentDimensions() {
            return fabric.util.transformPoint(this._getTransformedDimensions(), this.getViewportTransform(), true);
          }
        });
    
        function fitCanvas(w, h) {
          var scaleW = (document.querySelectorAll(".col-sm-6")[0].offsetWidth - 100) / w;
          var scaleH = (document.querySelectorAll("body")[0].offsetHeight - 100) / h;
          scale = Math.min(scaleH, scaleW);
    
          if (scale > 1) {
            scale = 1;
          }
    
    
          canvas.setZoom(scale);
          canvas.setWidth(w * scale);
          canvas.setHeight(h * scale);
    
          initAligningGuidelines(canvas);
          initCenteringGuidelines(canvas);
    
          canvas.renderAll();
          console.log("finished!!");
    
        }
    
        (function() {
          canvas = new fabric.Canvas('c', {
            allowTouchScrolling: true
          });
          WebFont.load({
            google: {
              families: ["Inter:200"]
            },
            active: function() {
              canvas.loadFromJSON({
                "height": "500",
                "width": "500",
                "edit": "yes",
                "objects": [],
                "backgroundImage": {
                  "crossOrigin": "anonymous"
                }
              }, function() {
                fitCanvas(500, 500);
              })
            }
          });
    
          canvas.on('before:render', function(opt) {
            canvas.getObjects().map(function(o, i) {
              if (o.type.toLowerCase() == "textbox") {
                var maxH = (o.maxHeight) ? (o.maxHeight) : (canvas.height);
                o.set({
                  'maxHeight': maxH
                });
                if (o.fontSize > 0 && (maxH > o.fontSize)) {
                  while (o.height > maxH) {
                    o.set({
                      'fontSize': o.fontSize - 1
                    });
                  }
                }
              }
    
              if (o.circleFrame) {
                o.set({
                  clipPath: new fabric.Circle({
                    radius: o.width / 2,
                    originX: 'center',
                    originY: 'center'
                  })
                });
    
              }
    
              if ((o.rx || o.ry) && o.type == "image") {
    
                let rx = (o.rx || 0);
                let ry = (o.ry || 0);
    
                o.set({
                  clipPath: new fabric.Rect({
                    rx: rx,
                    ry: ry,
                    height: o.height,
                    width: o.width,
                    originX: 'center',
                    originY: 'center'
                  })
                });
    
              }
            });
          });
    
        })();
      </script>
      <script>
        fabric.Object.prototype.objectCaching = false;
    
        function changeDim() {
          fitCanvas($("#widthC").val(), $("#heightC").val());
        }
    
        function setCanvasBI(src, o = "1") {
          if (!src) {
            src = $("#canvasBI").val();
          }
          if (src.length == 0) {
            src = new fabric.Image('');
          }
          canvas.setBackgroundImage(src, canvas.renderAll.bind(canvas), {
            opacity: o
          });
        }
    
        (function() {
    
          $(document).on("mouseenter", "[data-label]", function() {
            $("#font-search").val($(this).data("label"));
            loadFont($(this).data("label"));
          });
    
          fabric.Canvas.prototype.getItemByAttr = function(attr, name) {
            var object = null,
              objects = this.getObjects();
            for (var i = 0, len = this.size(); i < len; i++) {
              if (objects[i][attr] && objects[i][attr] == name) {
                object = objects[i];
                break;
              }
            }
            return object;
          };
    
          $("form#f").hide();
    
          var activeObject;
    
          $("#f input, #f select").on("input", function() {
            if (["height", "width", "top", "left", "strokeWidth", "charSpacing"].includes(this.name)) {
              canvas.getActiveObject().set(this.name, parseFloat(this.value)).setCoords();
            } else {
              canvas.getActiveObject().set(this.name, this.value).setCoords();
            }
            canvas.renderAll();
          });
    
          canvas.preserveObjectStacking = true;
    
          fabric.Object.prototype.toObject = (function(toObject) {
            return function() {
              return fabric.util.object.extend(toObject.call(this), {
                name: this.name,
                text: this.text
              });
            };
          })(fabric.Object.prototype.toObject);
    
          canvas.on('object:scaling', function(e) {
            if (e.target.toObject().type != "image" && e.target.toObject().type != "circle") {
              e.target.set({
                width: e.target.width * e.target.scaleX,
                height: e.target.height * e.target.scaleY,
                scaleX: 1,
                scaleY: 1
              })
            }
          });
    
          canvas.on('object:modified', function(opt) {
            document.body.style.cursor = 'progress';
          });
    
          canvas.on("after:render", function() {
    
            canvas.includeDefaultValues = false;
            canvas.toObject().objects.forEach(function(layer, id) {
    
              if (typeof layer.name !== 'undefined') {
                canvas.getItemByAttr(`name`, layer.name).set({
                  "name": String.fromCharCode(65 + id).toLowerCase()
                })
                var actived = '';
                if (canvas.getActiveObject()) {
                  actived = (canvas.getActiveObject().name == layer.name) ? " actived" : "";
                }
              }
            });
            document.body.style.cursor = 'default'
          });
    
          canvas.on("selection:created", function(obj) {
            if ("image" == obj.target?.type) {
              canvas.getActiveObject().setControlsVisibility({
                mb: false,
                ml: false,
                mt: false,
                mr: false
              });
            }
            $("form#f input[type!='hidden'], #f select").parent().hide();
            $("form#f").hide();
            canvas.renderAll();
            showForm();
          });
    
          canvas.on("selection:updated", function(obj) {
            if ("image" == obj.target?.type) {
              canvas.getActiveObject().setControlsVisibility({
                mb: false,
                ml: false,
                mt: false,
                mr: false
              });
            }
            canvas.renderAll();
            $("form#f").hide();
            $("form#f input[type!='hidden'] , #f select, #f textarea").parent().hide();
            showForm();
          });
    
          canvas.on("selection:cleared", function() {
            canvas.renderAll();
            $("form#f").hide();
            $("form#f input[type!='hidden'], #f select, #f textarea").parent().hide();
          });
    
          canvas.hoverCursor = 'default';
          canvas.on('mouse:over', function(e) {
            if (e.target) {
              e.target._renderControls(canvas.contextTop, {
                hasControls: false
              })
            }
          });
    
          canvas.on('mouse:out', function(e) {
            canvas.clearContext(canvas.contextTop);
          });
          canvas.on('mouse:down', function(e) {
            canvas.clearContext(canvas.contextTop);
          });
    
          function showForm() {
    
            $("form#f").show();
            activeObject = canvas.getActiveObject();
            var v;
            for (i in activeObject) {
              v = activeObject[i];
    
              if (typeof v != "undefined") {
                $("textarea[name='" + i + "']").val(v).parent().show();
                $("input[name='" + i + "']").val(v).parent().show();
                $("select[name='" + i + "']").val(v).parent().show();
              }
            }
          }
    
          addText = function() {
            var text = new fabric.Textbox("Edit this Text", {
              name: genNextName(),
              left: canvas.getWidth() / canvas.getZoom() / 2,
              top: canvas.getHeight() / canvas.getZoom() / 2,
              width: (canvas.getWidth() / canvas.getZoom()) / 2,
              fill: "#000000",
              originX: "center",
              originY: "center",
              fontFamily: "Inter",
              fontWeight: 400,
              fontSize: 60,
              padding: 20
            });
            text.setControlsVisibility({
              mt: false,
              mb: false,
              ml: true,
              mr: true,
              tl: true,
              tr: true,
              bl: true,
              br: true
            });
    
            canvas.add(text);
            canvas.setActiveObject(text);
            canvas.renderAll();
          };
    
        })();
    
        function hide_mh_box() {
          canvas.remove(canvas.getItemByAttr("isBB", true));
        }
    
        function show_mh_box() {
          var h = parseInt($("[name=maxHeight]").val());
          var n = new fabric.Rect({
            top: canvas.getActiveObject().get('top'),
            left: canvas.getActiveObject().get('left'),
            width: canvas.getActiveObject().get('width'),
            height: h,
            originX: canvas.getActiveObject().get('originX'),
            originY: canvas.getActiveObject().get('originY'),
            angle: canvas.getActiveObject().get('angle'),
            opacity: 1,
            strokeWidth: 2,
            stroke: "#FF00FF",
            fill: "rgba(0,0,0,0)",
            evented: !1,
            isBB: true
          });
          canvas.add(n);
          canvas.renderAll();
        }
    
        var visited = [];
      </script>
    
      <script>
        function genNextName() {
          canvas.renderAll();
          var total = canvas.getObjects().length;
          return String.fromCharCode(65 + total).toLowerCase()
        }
      </script>
    </body>
    
    </html>