Good question.
If you add custom properties to objects, these objects are most likely βspecialβ. It seems that subclassing them would be a reasonable solution.
For example, here we will subclass fabric.Image into a named image. These image objects might have names such as Gandalf or Self Help.
fabric.NamedImage = fabric.util.createClass(fabric.Image, { type: 'named-image', initialize: function(element, options) { this.callSuper('initialize', element, options); options && this.set('name', options.name); }, toObject: function() { return fabric.util.object.extend(this.callSuper('toObject'), { name: this.name }); } });
First we give these objects a type. This type is used by loadFromJSON to automatically invoke the fabric.<type>.fromObject . In this case, it will be fabric.NamedImage.fromObject .
Then we overwrite the instance method initialize (constructor), also set the name property when initializing the object (if this property is set).
Then we overwrite the toObject instance method to include the "name" in the returned object (this is the cornerstone of serializing the object in the fabric).
Finally, we also need to implement this fabric.NamedImage.fromObject , which I mentioned earlier, so that loadFromJSON knows which method to call when parsing JSON:
fabric.NamedImage.fromObject = function(object, callback) { fabric.util.loadImage(object.src, function(img) { callback && callback(new fabric.NamedImage(img, object)); }); };
We load the image here (from "object.src"), and then create an instance of fabric.NamedImage from it. Note that at this point, the constructor will already take care of setting the "name", since we previously rewritten the "initialize" method.
And we will also need to indicate that fabric.NamedImage is an asynchronous "class", meaning that its fromObject does not return an instance, but passes it to the callback:
fabric.NamedImage.async = true;
And now we can try everything:
// create image element var img = document.createElement('img'); img.src = 'https://www.google.com/images/srpr/logo3w.png'; // create an instance of named image var namedImg = new fabric.NamedImage(img, { name: 'foobar' }); // add it to canvas canvas.add(namedImg); // save json var json = JSON.stringify(canvas); // clear canvas canvas.clear(); // and load everything from the same json canvas.loadFromJSON(json, function() { // making sure to render canvas at the end canvas.renderAll(); // and checking if object "name" is preserved console.log(canvas.item(0).name); });