简体   繁体   中英

Fabric.js - Text with free rectangular bounding box like Google slides

I am making drawing editor using Fabric.js. One of the requirements is to create flexible text box component (like Goole Slides or Power Point) whose bounding box can be adjusted without compromising text size and other text controls like scale, reposition... Currently, what fabric.js provides with fabric.Text is not sufficient for this task. So I am using fabric.Group but I am stack on selection issue. I cannot select sub-objects of group. How can I go about this issue. Any information is welcome

This is I want to achieve:

在此处输入图片说明

This is what I have now with raw fabric.Text object

在此处输入图片说明

This is what I have achieved with fabric.Group

在此处输入图片说明

Here is my class which is intended for Textbox

class Text extends fabric.Group {
  constructor(options) {
    super([], Object.assign(options));
    this.class = 'textbox';

    this.init();
  }

  init() {
    const left = this.left;
    const top = this.top;
    const width = this.width || 100;
    const height = this.height || 40;

    this.rect = new fabric.Rect({
      left,
      top,
      width,
      height,
      fill: 'rgba(0,0,0,0)',
      stroke: this.stroke,
      type: 'rect',
      originX: 'left',
      originY: 'top',
      strokeWidth: this.strokeWidth
    });

    this.text = new fabric.IText(this.text, {
      left: left + 20,
      top: top + 12,
      fontSize: this.fontSize,
      fontFamily: this.fontFamily,
      fontColor: this.fontColor,
      selectable: true
    });
    this.text.setCoords();

    this.text.setControlsVisibility({
      br: false, // middle top disable
      bl: false, // midle bottom
      tl: false, // middle left
      tr: false, // I think you get it,
      mb: false,
      ml: false,
      mt: false,
      mr: false,
      mtr: false
    });

    this.addWithUpdate(this.rect);
    this.addWithUpdate(this.text);
  }

  toObject() {
    const obj = super.toObject();
    return Object.assign(obj, {
      class: this.class
    });
  }
}

export default Text;

You can Use Fabric's TextBox If you want flexible width and height. But I think You also need border around text, For that Grouping is good Option but You have to adjust Width and Height of Rect based on Your Text. For that You need to override onKeyDown method of Textbox and add your own method for changing width and height of Rect. Of course you can also call that function on text:changed event. I did the same , I can't share full code but here's the hint

this.LimitedTextbox = fabric.util.createClass(fabric.IText, {
       //you can ignore it , here i setting fixed width to Itext
        initDimensions: function() {
            this.isEditing && this.initDelayedCursor();
            this.clearContextTop();
            if (this.__skipDimension) {
                return;
            }
            this._splitText();
            this._clearCache();
            if (this.path) {
            this.width = this.path.width;
            this.height = this.path.height;
            }
            else {
                let width = this.calcTextWidth();
                if(width>this.maxWidth){
                    this.width = width;
                }else{
                    this.width = this.maxWidth;
                }
                this.height = this.calcTextHeight();    
            }
            if (this.textAlign.indexOf('justify') !== -1) {
            this.enlargeSpaces();
            }
            this.saveState({ propertySet: '_dimensionAffectingProps' });
        },
        onKeyDown:function(e){
            //Can be Ignored , I wanted my textbox to have limited lines only
            if ((e.keyCode == 13 && this._textLines.length>=this.maxLines) || 
            (e.keyCode == 9 || e.keyCode == 27)) {
                this.exitEditing();
                self.lastSelected = undefined;
            }else{
                this.callSuper('onKeyDown',e);
                let maxLine = Math.max(...this.__lineWidths); 
                //This is What you need , A function to change border width.
                self.changeBorderWidth(this.toObject().groupId, this, { iWidth: this.width, iHeight: this.height,maxLine:maxLine,id:this.toObject().id },false,this.toObject().customType==='stamp_input');
                if(this.dynamicMinWidth>this.maxWidth){
                    this.width = this.dynamicMinWidth;
                }
            }
                
            
        },
    });

Edit: To add border to IText or Textbox https://stackoverflow.com/a/67055302/11036872

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM