Fabric.js - 如何使用自定义属性在服务器上保存画布 [英] Fabric.js - how to save canvas on server with custom attributes
问题描述
我希望能够将当前画布状态保存到服务器端数据库,可能是作为JSON字符串,然后稍后使用 loadFromJSON
。通常,这是很容易实现使用:
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:
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
方法添加到画布中:
However, I've also been setting a few custom attributes on the fabric objects I'm adding to the canvas using the builtin Object#set
method:
// 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字符串中恢复画布,并且已还原的画布还将包括我的自定义属性?感谢。
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 toObject
method 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 and restore the canvas from a JSON string sent by the server, and the restored canvas will also include my custom attributes? thanks.
推荐答案
好问题。
自定义属性到对象,那些对象可能在某种程度上特殊。似乎子类化它们将是一个合理的解决方案。
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.
例如,下面是我们如何继承一个 fabric.Image
成一个命名的图像。那些图像对象可以有Gandalf或Samwise这样的名称。
For example, here's how we would subclass a fabric.Image
into a named image. Those image objects could then have names like "Gandalf" or "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
。
First, we give these objects a type. This type is used by loadFromJSON
to automatically invoke fabric.<type>.fromObject
method. In this case it would be fabric.NamedImage.fromObject
.
然后我们覆盖 initialize
Then we overwrite initialize
(constructor) instance method, to also set "name" property when initializing an object (if that property is given).
然后,我们覆盖了一个对象的实例方法,并在初始化对象时设置了name属性。 toObject
实例方法在返回的对象中包含name(这是fabric中对象序列化的基石)。
Then we overwrite toObject
instance method to include "name" in returned object (this is a cornerstone of object serialization in fabric).
最后,我们还需要实现我之前提到的 fabric.NamedImage.fromObject
,这样 loadFromJSON
将知道在JSON解析期间调用哪个方法:
Finally, we'll also need to implement that fabric.NamedImage.fromObject
that I mentioned earlier, so that loadFromJSON
would know which method to invoke during JSON parsing:
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方法。
We're loading an image here (from "object.src"), then creating an instance of fabric.NamedImage
out of it. Note how at that point, constructor will already take care of "name" setting, since we overwrote "initialize" method earlier.
我们还需要指定 fabric.NamedImage
是一个异步的类,意味着它的 fromObject
不返回一个实例,回调:
And we'll also need to specify that fabric.NamedImage
is an asynchronous "class", meanining that its fromObject
does not return an instance, but passes it to a callback:
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);
});
这篇关于Fabric.js - 如何使用自定义属性在服务器上保存画布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!