json Fabric.js - 如何使用自定义属性在服务器上保存画布
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11272772/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Fabric.js - how to save canvas on server with custom attributes
提问by sa125
I'd like to be able to save the current canvas' state to a server-side database, probably as a JSON string, and then later restore it with loadFromJSON. Typically, this is easily accomplished using:
我希望能够将当前画布的状态保存到服务器端数据库,可能作为 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');
}
And then
进而
function loadCanvas(json) {
// parse the data into the canvas
canvas.loadFromJSON(json);
// re-render the canvas
canvas.renderAll();
// optional
canvas.calculateOffset();
}
However, I've also been setting a few custom attributes on the fabric objects I'm adding to the canvas using the builtin Object#setmethod:
但是,我还在使用内置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();
The problem is that when I check the request on the server-side, I see that my custom attributes were not parsed from the canvas and sent along with everything else. This probably has to do with how toObjectmethod removes anything that's not a default attribute in the object class. What would be a good way to tackle this issue, such that I'll be able to both save andrestore the canvas from a JSON string sent by the server, and the restored canvas will also include my custom attributes? thanks.
问题是,当我在服务器端检查请求时,我发现我的自定义属性没有从画布中解析出来并与其他所有内容一起发送。这可能与toObject方法如何删除对象类中不是默认属性的任何内容有关。解决这个问题的好方法是什么,这样我就可以从服务器发送的 JSON 字符串中保存和恢复画布,并且恢复的画布还将包括我的自定义属性?谢谢。
回答by kangax
Good question.
好问题。
If you're adding custom properties to objects, those objects are likely "special" in some way. It seems like subclassing them would be a reasonable solution.
如果您要向对象添加自定义属性,则这些对象在某些方面可能是“特殊的”。似乎对它们进行子类化将是一个合理的解决方案。
For example, here's how we would subclass a fabric.Imageinto a named image. Those image objects could then have names like "Gandalf" or "Samwise".
例如,下面是我们如何将 a 子类fabric.Image化为命名图像。然后,这些图像对象可以具有诸如“Gandalf”或“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 });
}
});
First, we give these objects a type. This type is used by loadFromJSONto automatically invoke fabric.<type>.fromObjectmethod. In this case it would be fabric.NamedImage.fromObject.
首先,我们给这些对象一个类型。此类型用于loadFromJSON自动调用fabric.<type>.fromObject方法。在这种情况下,它将是fabric.NamedImage.fromObject.
Then we overwrite initialize(constructor) instance method, to also set "name" property when initializing an object (if that property is given).
然后我们覆盖initialize(构造函数)实例方法,在初始化对象时也设置“name”属性(如果给出了该属性)。
Then we overwrite toObjectinstance method to include "name" in returned object (this is a cornerstone of object serialization in fabric).
然后我们覆盖toObject实例方法以在返回的对象中包含“名称”(这是结构中对象序列化的基石)。
Finally, we'll also need to implement that fabric.NamedImage.fromObjectthat I mentioned earlier, so that loadFromJSONwould know which method to invoke during JSON parsing:
最后,我们还需要实现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));
});
};
We're loading an image here (from "object.src"), then creating an instance of fabric.NamedImageout of it. Note how at that point, constructor will already take care of "name" setting, since we overwrote "initialize" method earlier.
我们在这里加载一个图像(来自“object.src”),然后从中创建一个实例fabric.NamedImage。请注意此时构造函数将如何处理“名称”设置,因为我们之前覆盖了“初始化”方法。
And we'll also need to specify that fabric.NamedImageis an asynchronous "class", meanining that its fromObjectdoes not return an instance, but passes it to a callback:
而且我们还需要指定它fabric.NamedImage是一个异步“类”,这意味着它fromObject不返回实例,而是将其传递给回调:
fabric.NamedImage.async = true;
And now we can try this all out:
现在我们可以试试这一切:
// 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);
});
回答by kbcool
Wow. Am I missing something here?
哇。我在这里错过了什么吗?
I've done this plenty of times and it doesn't need any fancy subclassing.
我已经做过很多次了,它不需要任何花哨的子类化。
The docs cover it: http://fabricjs.com/docs/fabric.Canvas.html#toJSON
文档涵盖它:http: //fabricjs.com/docs/fabric.Canvas.html#toJSON
Just include an array of property names as strings in your call to toJSON().
只需在对 toJSON() 的调用中包含一组属性名称作为字符串。
Eg
例如
canvas.toJSON(['wizard','hobbit']);
Hopefully.... for bonus points you can add a reviver function which will rehydrate your custom attributes.
希望......对于奖励积分,您可以添加一个恢复功能,该功能将为您的自定义属性补水。
Again this is covered in the docs and has an example.
同样,这在文档中有所涉及,并有一个示例。
回答by adrien54
I had the same issue but I didn't want to extend the fabric.js classes.
我有同样的问题,但我不想扩展 fabric.js 类。
I wrote a function that takes the fabric canvas in parameter and returns a stringified version with my special attributes:
我编写了一个函数,该函数将织物画布作为参数并返回一个带有我的特殊属性的字符串化版本:
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);
}
The special attributes seems properly imported when I use canvas.loadFromJSON(), I'm using fabric 1.7.2.
使用时,特殊属性似乎已正确导入,我使用的canvas.loadFromJSON()是 fabric 1.7.2。
回答by Dan Ochiana
A more simple approach would be to add the properties post-stringify:
更简单的方法是在字符串化后添加属性:
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);
回答by Neil VanLandingham
If you don't want to specify the custom attributes you are using every time you call canvas.toJSON(), and you don't want to use a complicated subclassing approach, here is a very simple way to extend Fabric's toObjectmethod.
如果不想在每次调用时都指定使用的自定义属性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);
Then you can set custom properties on Fabric objects.
然后您可以在 Fabric 对象上设置自定义属性。
item.set("wizard","gandalf");
item.set("hobbit","bilbo");
And when you call canvas.toJSON()those properties will persist to the output. If you then use canvas.loadFromJSON()with your JSON output, the custom attributes will be imported and applied to the Fabric objects.
并且当您调用canvas.toJSON()这些属性时,这些属性将持续输出。如果您随后使用canvas.loadFromJSON()JSON 输出,自定义属性将被导入并应用于 Fabric 对象。

