Search code examples
javascriptreactjstypescriptfabricjsreact-tsx

How do I implement the `fromObject` method for customize objects in Fabric JS


I am trying to make a customize object just like in the tutorial http://fabricjs.com/fabric-intro-part-3 (the LabeledRect). The object needs to be cloned, so I would have to implement the fromObject method.

I am using react with typescript and I am not sure how to implement the fromObject method.

  const addLabeledRect = (canv: fabric.Canvas | null) => {
var LabeledRect = fabric.util.createClass(fabric.Rect, {

  type: 'labeledRect',
  initialize: function (options: { label?: any; }) {
    options || (options = {});

    this.callSuper('initialize', options);
    this.set('label', options.label || '');
  },

  toObject: function () {
    return fabric.util.object.extend(this.callSuper('toObject'), {
      label: this.get('label')
    });
  },

  _render: function (ctx: { font: string; fillStyle: string; fillText: (arg0: any, arg1: number, arg2: number) => void; }) {
    this.callSuper('_render', ctx);

    ctx.font = '20px Helvetica';
    ctx.fillStyle = '#333';
    ctx.fillText(this.label, -this.width / 2, -this.height / 2 + 20);
    
  }
  
});
var labeledRect = new LabeledRect({
  width: 100,
  height: 50,
  left: 100,
  top: 100,
  label: '1',
  fill: '#fff'
});
labeledRect.set('data', {
  first_item: 'Hello',
  second_item: 'World',
  next_itme: true
})
canv?.add(labeledRect);}

This code works just fine, the thing is when I want to copy and paste the object it doesn't work correctly. How would I implement thefromObjectmethode so I am able to copy and paste the object?


Solution

  • I did some research and I found a solution, so I figured I would post it, maybe it is helpfull to somone. This post helped me out a lot: Cloning selection of custom objects

    I took me a while, but it turns out you have to assign the property to the fabric library for it to work:

     fabric.LabeledRect = fabric.util.createClass(...)
    

    and for typescript first you have to assign fabric to a variable of type any to bypass the type system and than it will work:

     var Fabric: any = fabric;  
     Fabric.LabeledRect = fabric.util.createClass(...)
    

    so I just had to assign fabric to a variable of type any and assign the property to the fabric library and add the fromObject function. Now I can copy and paste my the labeledRect.

    Here is how I solved it:

    const addLabeledRect = (canv: fabric.Canvas | null) => {
    var Fabric: any = fabric;
    Fabric.LabeledRect = fabric.util.createClass(fabric.Rect, {
    
      type: 'labeledRect',
      
      initialize: function (options: { label?: any; }) {
        options || (options = {});
    
        this.callSuper('initialize', options);
        this.set('label', options.label || '');
      },
    
      toObject: function () {
        return fabric.util.object.extend(this.callSuper('toObject'), {
          label: this.get('label')
        });
      },
    
      _render: function (ctx: { font: string; fillStyle: string; fillText: (arg0: any, arg1: number, arg2: number) => void; }) {
        this.callSuper('_render', ctx);
    
        ctx.font = '20px Helvetica';
        ctx.fillStyle = '#333';
        ctx.fillText(this.label, -this.width / 2, -this.height / 2 + 20);
    
      }
    }
    );
    //added this part
    Fabric.LabeledRect.fromObject = function (object: any, callback: any) {
      var labeledRect = new Fabric.LabeledRect(object);
      callback && callback(labeledRect);
      return labeledRect;
    };
    
    var labeledRect = new Fabric.LabeledRect({
      width: 100,
      height: 50,
      left: 100,
      top: 100,
      label: '1',
      fill: '#fff'
    });
    
    labeledRect.set('data', {
      first_item: 'Hello',
      second_item: 'World',
      next_itme: true
    })
    canv?.add(labeledRect);}