Fabric.js - Grouped iText not editable

前端 未结 5 989
暗喜
暗喜 2021-01-04 13:11

The title says all. When a fabric.ITextis part of a fabric.Group, it no longer reacts like a editable text.

Here is a use-case: http://jsfi

相关标签:
5条回答
  • 2021-01-04 13:25

    I might be too late to answer this, but surely many of you like me searching for this answer shall meet the solution. You can find a perfectly working solution of iText where user can edit the text of iText which is a part of a fabric.group Working solution

    Approach followed here is:

    1. When user double clicks the desired group, we ungroup all the elements
    2. set focus on iText element
    3. Enters the editing mode of iText & select all text so that user can directly start editing..
    4. Once user exits edit mode, the elements are again grouped together.

      // ungroup objects in group
      var items
      var ungroup = function (group) {
          items = group._objects;
          group._restoreObjectsState();
          canvas.remove(group);
          for (var i = 0; i < items.length; i++) {
              canvas.add(items[i]);
          }
          // if you have disabled render on addition
          canvas.renderAll();
      };
      
      // Re-group when text editing finishes
      var dimensionText = new fabric.IText("Dimension Text", {
          fontFamily: 'Comic Sans',
          fontSize: 14,
          stroke: '#000',
          strokeWidth: 1,
          fill: "#000",
          left: 170,
          top: 60
      });
      dimensionText.on('editing:exited', function () {
          var items = [];
          canvas.forEachObject(function (obj) {
              items.push(obj);
              canvas.remove(obj);
          });
          var grp = new fabric.Group(items.reverse(), {});
          canvas.add(grp);
          grp.on('mousedown', fabricDblClick(grp, function (obj) {
              ungroup(grp);
              canvas.setActiveObject(dimensionText);
              dimensionText.enterEditing();
              dimensionText.selectAll();
          }));
      });
      
    0 讨论(0)
  • 2021-01-04 13:26

    I know is too late, but here is a working code for your problem: http://jsfiddle.net/fd4yrxq6/2/

    I just made some little changes using the anwares above:

    ...
    // ungroup objects in group
    var items;
    var ungroup = function (group) {
        items = group._objects;
        group._restoreObjectsState();
        canvas.remove(group);
        canvas.renderAll();
        for (var i = 0; i < items.length; i++) {
            canvas.add(items[i]);
        }
        // if you have disabled render on addition
        canvas.renderAll();
    };
    ...
    dimensionText.on('editing:exited', function () {
            for (var i = 0; i < items.length; i++) {
            canvas.remove(items[i]);
        }
        var grp = new fabric.Group(items, {});
        canvas.add(grp);
        grp.on('mousedown', fabricDblClick(grp, function (obj) {
            ungroup(grp);
            canvas.setActiveObject(dimensionText);
            dimensionText.enterEditing();
            dimensionText.selectAll();
        }));
    });
    ...
    

    var canvas = new fabric.Canvas('canvas');
    canvas.setWidth(300);
    canvas.setHeight(300);
    
    // Double-click event handler
    var fabricDblClick = function (obj, handler) {
        return function () {
            if (obj.clicked) handler(obj);
            else {
                obj.clicked = true;
                setTimeout(function () {
                    obj.clicked = false;
                }, 500);
            }
        };
    };
    
    // ungroup objects in group
    var items;
    var ungroup = function (group) {
        items = group._objects;
        group._restoreObjectsState();
        canvas.remove(group);
        canvas.renderAll();
        for (var i = 0; i < items.length; i++) {
            canvas.add(items[i]);
        }
        // if you have disabled render on addition
        canvas.renderAll();
    };
    
    // Re-group when text editing finishes
    var dimensionText = new fabric.IText("Dimension Text", {
        fontFamily: 'Comic Sans',
        fontSize: 14,
        stroke: '#000',
        strokeWidth: 1,
        fill: "#000",
        left: 170,
        top: 60
    });
    dimensionText.on('editing:exited', function () {
            for (var i = 0; i < items.length; i++) {
            canvas.remove(items[i]);
        }
        var grp = new fabric.Group(items, {});
        canvas.add(grp);
        grp.on('mousedown', fabricDblClick(grp, function (obj) {
            ungroup(grp);
            canvas.setActiveObject(dimensionText);
            dimensionText.enterEditing();
            dimensionText.selectAll();
        }));
    });
    
    function addRuler() {
        var dimension_mark = new fabric.Path('M0,0L0,-5L0,5L0,0L150,0L150,-5L150,5L150,0z');
        dimension_mark.set({
            left: 150,
            top: 70,
            stroke: '#333333',
            strokeWidth: 2,
            scaleY: 1
        });
        var dimension_group = new fabric.Group([dimension_mark, dimensionText], {
            left: 50,
            top: 50
        });
        canvas.add(dimension_group);
        dimension_group.on('mousedown', fabricDblClick(dimension_group, function (obj) {
            ungroup(dimension_group);
            canvas.setActiveObject(dimensionText);
            dimensionText.enterEditing();
            dimensionText.selectAll();
            canvas.renderAll();
        }));
    }
    addRuler();
    
    style = {
            left: 100,
            top: 100,
            width: 20,
            height: 20,
            fill: "green",
            lockRotation: true
        };
        var rectangle = new fabric.Polygon([
            { x: 20, y: 0 },
            { x: 0, y: 20 },
            { x: 20, y: 40 },
            { x: 40, y: 20 },
        ], style);
        canvas.add(rectangle);
    .canvas {
        border: 1px solid Black;
        width: 300px;
        height: 300px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.2.0/fabric.min.js"></script>
    <p id="addObj">Fabric.js - iText editing from Group</p>
    <canvas id="canvas" class="canvas" ></canvas>

    0 讨论(0)
  • 2021-01-04 13:29

    Thanks for the answer, However it doesn't make sure only the items in the group are regrouped, we must change 'canvas.forEachObject' to 'groupItems' as it will try to put back all items in the canvas only those belonged to the group. See the following code

    // ungroup objects in group
    var groupItems = []
    var ungroup = function (group) {
        groupItems = group._objects;
        group._restoreObjectsState();
        canvas.remove(group);
        for (var i = 0; i < groupItems.length; i++) {
            canvas.add(groupItems[i]);
        }
        // if you have disabled render on addition
        canvas.renderAll();
    };
    
    // Re-group when text editing finishes
    var dimensionText = new fabric.IText("Dimension Text", {
        fontFamily: 'Comic Sans',
        fontSize: 14,
        stroke: '#000',
        strokeWidth: 1,
        fill: "#000",
        left: 170,
        top: 60
    });
    dimensionText.on('editing:exited', function () {
        var items = [];
        groupItems.forEach(function (obj) {
            items.push(obj);
            canvas.remove(obj);
        });
        var grp = new fabric.Group(items.reverse(), {});
        canvas.add(grp);
        grp.on('mousedown', fabricDblClick(grp, function (obj) {
            ungroup(grp);
            canvas.setActiveObject(dimensionText);
            dimensionText.enterEditing();
            dimensionText.selectAll();
        }));
    });
    
    0 讨论(0)
  • 2021-01-04 13:36

    If you would like a real visual padding(like the css) for itext, you could add an unselectable Rect just behind the itext. And adjust the Rect position based on all event for itext, e.g, moving, scaling etc.

    self.createITextWithPadding = function (event) {
    
                   var itext = new fabric.IText('Done', {
                       fontSize: 18,
                       padding : tnbConstants.ITEXT.PADDING,
                       fill: '#FFF',
    
                   });
    
                   itext.left = (event.pageX - $("#tnb-panel").position().left)-itext.width/2;
                   itext.top = (event.pageY-$("#tnb-panel").position().top)-itext.height/2;
    
                   var bg = new fabric.Rect({
                        fill: '#32b775',
                       left : itext.left - tnbConstants.ITEXT.PADDING,
                       top :itext.top - tnbConstants.ITEXT.PADDING,
                       rx: 5,
                       ry: 5,
                       width: itext.width + tnbConstants.ITEXT.PADDING*2,
                       height:itext.height + tnbConstants.ITEXT.PADDING*2,
                       selectable : false
                   });
    
                   itext.bgRect = bg;
                   itext.on("moving",self.adjustBackRect);
                   itext.on("scaling",self.adjustBackRect);
    
                   return itext;
               }
    
    self.adjustBackRect = function (e) {//e is event
                   var text = e.target;
                   var bgRect = text.bgRect;
    
                   bgRect.set({
                       left : text.left - text.padding,
                       top : text.top - text.padding,
                       width : text.width * text.scaleX + text.padding * 2,
                       height : text.height * text.scaleY + text.padding * 2 ,
                   });
    
    
                   console.log("text width :" + (text.width * text.scaleX + text.padding*2));
                   console.log("text height :" + (text.height * text.scaleY + text.padding*2));
                   console.log("bg width :" + (bgRect.width ));
                   console.log("bg height :" + (bgRect.height ));
               };
    
    0 讨论(0)
  • 2021-01-04 13:37

    Currently there is no way for IText to handle the events as they are not handed down to it if it's contained in a group. I think this is also the prefered way to handle that as it would confuse the user - what if he starts to edit multiple texts. This might end up in a mess. Maybe you can rework your script a little to workaround this problems.

    0 讨论(0)
提交回复
热议问题