我希望能够将当前画布的状态保存到服务器端数据库中,可能作为 JSON 字符串,然后使用 loadFromJSON
恢复它。通常,使用以下命令可以轻松完成此操作:
var canvas = new fabric.Canvas();
function saveCanvas() {
// convert canvas to a json string
var json = JSON.stringify( canvas.toJSON() );
// save via xhr
$.post('/save', { json : json }, function(resp){
// do whatever ...
}, 'json');
}
然后
function loadCanvas(json) {
// parse the data into the canvas
canvas.loadFromJSON(json);
// re-render the canvas
canvas.renderAll();
// optional
canvas.calculateOffset();
}
但是,我也一直在使用内置Object#set
方法在添加到画布的织物对象上设置一些自定义属性:
// get some item from the canvas
var item = canvas.item(0);
// add misc properties
item.set('wizard', 'gandalf');
item.set('hobbit', 'samwise');
// save current state
saveCanvas();
问题是,当我在服务器端检查请求时,我看到我的自定义属性没有从画布中解析并与其他所有内容一起发送。这可能与toObject
方法如何删除对象类中不是默认属性的任何内容有关。解决此问题的好方法是什么,以便我能够从服务器发送的 JSON 字符串保存和还原画布,并且还原的画布还将包含我的自定义属性?谢谢。
好问题。
如果要向对象添加自定义属性,则这些对象可能在某种程度上是"特殊的"。似乎对它们进行子类化将是一个合理的解决方案。
例如,下面介绍了如何将fabric.Image
子类化为命名图像。然后,这些图像对象可以具有诸如"甘道夫"或"Samwise"之类的名称。
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 });
}
});
首先,我们给这些对象一个类型。loadFromJSON
使用此类型自动调用fabric.<type>.fromObject
方法。在这种情况下,它将是 fabric.NamedImage.fromObject
.
然后我们覆盖initialize
(构造函数)实例方法,以便在初始化对象时设置"name"属性(如果该属性给定)。
然后我们覆盖toObject
实例方法以在返回的对象中包含"name"(这是结构中对象序列化的基石)。
最后,我们还需要实现我之前提到的fabric.NamedImage.fromObject
,以便loadFromJSON
知道在 JSON 解析期间调用哪种方法:
fabric.NamedImage.fromObject = function(object, callback) {
fabric.util.loadImage(object.src, function(img) {
callback && callback(new fabric.NamedImage(img, object));
});
};
我们在这里加载一个图像(从"object.src"),然后从中创建fabric.NamedImage
的实例。请注意,在这一点上,构造函数已经处理了"name"设置,因为我们之前覆盖了"initialize"方法。
我们还需要指定 fabric.NamedImage
是一个异步"类",这意味着它的fromObject
不返回实例,而是将其传递给回调:
fabric.NamedImage.async = true;
现在我们可以尝试这一切:
// 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's "name" is preserved
console.log(canvas.item(0).name);
});
哇。我在这里错过了什么吗?
我已经做了很多次了,它不需要任何花哨的子类。
文档涵盖了它:http://fabricjs.com/docs/fabric.Canvas.html#toJSON
只需在对 toJSON() 的调用中包含一组属性名称作为字符串即可。
例如
canvas.toJSON(['wizard','hobbit']);
希望。。。。对于奖励积分,您可以添加一个齐磊功能,这将重新激活您的自定义属性。
同样,这在文档中进行了介绍,并有一个示例。
我遇到了同样的问题,但我不想扩展结构.js类。
我编写了一个函数,该函数在参数中获取织物画布并返回具有我特殊属性的字符串化版本:
function stringifyCanvas(canvas)
{
//array of the attributes not saved by default that I want to save
var additionalFields = ['selectable', 'uid', 'custom'];
sCanvas = JSON.stringify(canvas);
oCanvas = JSON.parse(sCanvas) ;
$.each(oCanvas.objects, function(n, object) {
$.each(additionalFields, function(m, field) {
oCanvas.objects[n][field] = canvas.item(n)[field];
});
});
return JSON.stringify(oCanvas);
}
当我使用canvas.loadFromJSON()
时,特殊属性似乎正确导入,我使用的是织物1.7.2
。
方法是在字符串化后添加属性:
var stringJson = JSON.stringify(this.canvas);
var objectJson = JSON.parse(string.Json);
//remove property1 property
delete objectJson.property1;
//add property2 property
delete objectJson.property2;
// stringify the object again
stringJson = JSON.stringify(objectJson);
// at this point stringJson is ready to be sent over to the server
$http.post('http://serverurl/',stringJson);
如果您不想在每次调用 canvas.toJSON()
时指定您正在使用的自定义属性,并且不想使用复杂的子类化方法,这里有一种非常简单的方法来扩展 Fabric 的 toObject
方法。
//EXTEND THE PROPS FABRIC WILL EXPORT TO JSON
fabric.Object.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
id: this.id,
wizard: this.wizard,
hobbit: this.hobbit,
});
};
})(fabric.Object.prototype.toObject);
然后,您可以在结构对象上设置自定义属性。
item.set("wizard","gandalf");
item.set("hobbit","bilbo");
当您调用canvas.toJSON()
这些属性将保留到输出中。如果随后将canvas.loadFromJSON()
与 JSON 输出一起使用,则将导入自定义属性并将其应用于 Fabric 对象。
http://fabricjs.com/fabric-intro-part-3#serialization
var rect = new fabric.Rect();
rect.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
name: this.name
});
};
})(rect.toObject);
canvas.add(rect);
rect.name = 'trololo';
console.log(JSON.stringify(canvas));