Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fabric.js subclassing fabric.Group - Error: "Cannot read property 'async' of undefined" when load from JSON

Have the following issue:

Trying to subclass fabric.Group:

var CustomGroup = fabric.util.createClass(fabric.Group, {
    type : 'customGroup',

    initialize : function(objects, options) {
        options || ( options = { });

        this.callSuper('initialize', objects, options);
        this.set('customAttribute', options.customAttribute || 'undefinedCustomAttribute');
    },

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

    _render : function(ctx) {
        this.callSuper('_render', ctx);
    }
});

Testcase:

I create a red rectangle and added it to the custom group:

function drawTestRect() {
    // create a rectangle object
    var rect = new fabric.Rect({
        left : 100,
        top : 100,
        fill : 'red',
        width : 20,
        height : 20
    });

    var cgroup = new CustomGroup([rect], {
        top : 50,
        left : 50,
        customAttribute : 'Hello World'
    });

    canvas.add(cgroup);

};

Problem: I want to get JSON of the canvas and afterwards I want to load canvas from JSON.

drawTestRect()

var savedCanvas = canvas.toJSON();

canvas.clear();

canvas.loadFromJSON(savedCanvas);

Everything is working fine (Rect/Group is drawn; JSON is valid), but when I load from JSON, I get the following error in the console:

TypeError: Cannot read property 'async' of undefined

What I've tried yet:

  • I added "CustomGroup.async = false;". But didn't help
like image 860
mahega Avatar asked Jun 24 '14 10:06

mahega


1 Answers

The error "Cannot read property 'async' of undefined" is raised because no "klass" can be found - https://github.com/kangax/fabric.js/blob/master/src/util/misc.js#L214-215.

You have to assign your custom object to fabric object - otherwise canvas.loadFromJSON() doesn't work.

var fabric.CustomGroup = fabric.util.createClass(fabric.Group, {
    type : 'customGroup',

    initialize : function(objects, options) {
        options || ( options = { });

        this.callSuper('initialize', objects, options);
        this.set('customAttribute', options.customAttribute || 'undefinedCustomAttribute');
    },

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

    _render : function(ctx) {
        this.callSuper('_render', ctx);
    }
});

Additionally you have to declare the fromObject method - it's needed for loadFromJSON. In this case your object is load synchronous.

fabric.CustomGroup.fromObject = function (object, callback) {
    var _enlivenedObjects;
    fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
        delete object.objects;
        _enlivenedObjects = enlivenedObjects;
    });
    return new fabric.CustomGroup(_enlivenedObjects, object);
};

If your custom object is loaded async you have to do this:

fabric.CustomGroup.fromObject = function (object, callback) {
    fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
        delete object.objects;
        callback && callback(new fabric.CustomGroup(enlivenedObjects, object));
    });
};

fabric.CustomGroup.async = true;

I've made a small jsfiddle testcase: http://jsfiddle.net/Kienz/qPLY6/

like image 165
Kienz Avatar answered Nov 14 '22 22:11

Kienz