Akshay Vaghasiya
Akshay Vaghasiya

Reputation: 1637

How to create custom fabricjs object?

I have to create a custom fabricjs object(say, fabric.Demo) which extends fabric.Group object. fabric.Demo object will be used to grouped other two fabric.Group objects. I have searched on the Internet and found only these links as useful.

  1. Link 1
  2. Link 2

But I'm getting this error 'this._objects is undefined'. I know I haven't write _render(). But I don't understand that what to code in _render(). If anyone knows the answer, it will be appreciated.

Here is my code.

(function (global) {

    var fabric = global.fabric || (global.fabric = {}),
            extend = fabric.util.object.extend,
            clone = fabric.util.object.clone;

    var stateProperties = fabric.Text.prototype.stateProperties.concat();
    stateProperties.push(
            'top',
            'left'
            );

    fabric.Demo = fabric.util.createClass(fabric.Group, {
        type: 'demo',
        initialize: function () {

            this.grp = new fabric.Group([], {
                selectable: false,
                padding: 0
            });

            this.grp.add([
                new fabric.Group([
                    new fabric.Text('A', {top: 200, left: 200}),
                    new fabric.Text('B', {top: 200, left: 200})
                ]),
                new fabric.Group([
                    new fabric.Text('C', {top: 200, left: 200}),
                    new fabric.Text('D', {top: 200, left: 200})
                ])
            ]);
        },
        _render: function (ctx) {

        }
    });
})(typeof exports !== 'undefined' ? exports : this);

$(document).ready(function() {
    var canvas = new fabric.Canvas('c');
    var abc = new fabric.Demo();
    canvas.add(abc);
});

Upvotes: 1

Views: 10227

Answers (2)

Mayur Kukadiya
Mayur Kukadiya

Reputation: 2747

Here is the fabric JS custom Object with the use of group inside it.

(function (fabric) {
 "use strict";

fabric.CustomObject = fabric.util.createClass(fabric.Group, {
type: "customObject",
top: 0,
left: 0,
width: 0,
height: 0,
Fill: "#000000",
textObj: null,
rectObj: null,
originX: "left",
originY: "top",
noScaleCache: true,
objectCaching: false,
lockScalingFlip: true,
cacheProperties: fabric.Text.prototype.cacheProperties
  .concat
  //comma saperated string Properties that you want to cache
  (),
initialize: function (options) {
  this.set(options);
  this.rectObj = new fabric.Rect({
    top: 0,
    left: 0,
    width: this.width,
    height: this.height,
    fill: this.Fill,
  });

  this.textObj = new fabric.Textbox("text", {
    // text properties from this custom objects
  });

  this._objects = [this.rectObj, this.textObj];
  //   this custom _set function will set custom properties value to object when it will load from json.
  // at that time loadFromJson function will call this initialize function.
  this._setCustomProperties(this.options);
  this.canvas.renderAll();

  this.on("scaled", (e) => {
    //evenet will file if this custom object scalled
  });
  this.on("scaling", (e) => {
    //evenet will file if this custom object scalling
  });
},
_setCustomProperties(options) {
  let text = this.textObj;
  text.set({
    Fill: options.Fill,
  });
},
toObject: function (propertiesToInclude) {
  // This function is used for serialize this object. (used for create json)
  // not inlclude this.textObj and this.rectObj into json because when object will load from json, init fucntion of this class is called and it will assign this two object textObj and rectObj again.
  var obj = this.callSuper(
    "toObject",
    [
      "objectCaching",
      // ... property list that you want to add into json when this object is convert into json using toJSON() function. (serialize)
    ].concat(propertiesToInclude)
  );
  // delete objects array from json because then object load from json, Init function will call. which will automatically re-assign object and assign _object array.
  delete obj.objects;
  return obj;
},
 });

fabric.CustomObject.fromObject = function (object, callback) {
// This function is used for deserialize json and convert object json into button object again. (called when we call loadFromJson() fucntion on canvas)
return fabric.Object._fromObject("CustomObject", object, callback);
};

fabric.CustomObject.async = true;
})(fabric);

Upvotes: 2

AndreaBogazzi
AndreaBogazzi

Reputation: 14731

If you want to extend Group you have to respect its basic function, render a handfull of objects stored in the _objects array.

So when you initialize your class do not create a this.grp.

instead push your 2 groups inside a _objects array.

fabric.Demo = fabric.util.createClass(fabric.Group, {
        type: 'demo',
        initialize: function () {

            this.grp = new fabric.Group([], {
                selectable: false,
                padding: 0
            });

            this._objects.push(
                new fabric.Group([
                    new fabric.Text('A', {top: 200, left: 200}),
                    new fabric.Text('B', {top: 200, left: 200})
                ]));
            this._objects.push(
                new fabric.Group([
                    new fabric.Text('C', {top: 200, left: 200}),
                    new fabric.Text('D', {top: 200, left: 200})
                ]));
        }
    });
})(typeof exports !== 'undefined' ? exports : this);

extend render functions thinking what you need different from standard group, and do not forget to put the fromObject function if you want to load and restore your canvas.

Upvotes: 5

Related Questions