Fabric.js – 如何使用自定义属性在服务器上保存canvas
我希望能够将当前canvas的状态保存到服务器端数据库,可能是一个JSONstring,然后用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(); }
不过,我也使用内build的Object#set
方法在我添加到canvas的结构对象上设置了一些自定义属性:
// 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();
问题是,当我检查服务器端的请求时,我看到我的自定义属性没有从canvasparsing,并与其他一切发送。 这可能与如何toObject
方法删除不是对象类中的默认属性的东西有关。 解决这个问题的好方法是什么,这样我就能够从服务器发送的JSONstring中保存和恢复canvas,并且恢复的canvas也将包含我的自定义属性? 谢谢。
好问题。
如果您将自定义属性添加到对象,那么这些对象在某些方面可能是“特殊的”。 看来子类化他们将是一个合理的解决scheme。
例如,以下是我们如何将一个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 }); } });
首先,我们给这些对象一个types。 loadFromJSON
使用此types自动调用fabric.<type>.fromObject
方法。 在这种情况下,它将是fabric.NamedImage.fromObject
。
然后,我们重写initialize
(构造函数)实例方法,也初始化一个对象(如果给定的属性)设置“名称”属性。
然后我们覆盖toObject
实例方法,在返回的对象中包含“name”(这是fabric中对象序列化的基石)。
最后,我们还需要实现前面提到的fabric.NamedImage.fromObject
,以便loadFromJSON
知道在JSONparsing期间调用哪个方法:
fabric.NamedImage.fromObject = function(object, callback) { fabric.util.loadImage(object.src, function(img) { callback && callback(new fabric.NamedImage(img, object)); }); };
我们在这里加载一个图像(来自“object.src”),然后创build一个fabric.NamedImage
的实例。 注意到那个时候,构造函数已经在处理“name”设置了,因为之前我们覆盖了“initialize”方法。
我们还需要指定fabric.NamedImage
是一个asynchronous的“类”,意思是它的fromObject
不返回一个实例,而是传递给一个callback:
fabric.NamedImage.async = true;
现在我们可以尝试这一切:
// create image element var img = document.createElement('img'); img.src = 'https://www.google.comhttp://img.dovov.comsrpr/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); });
更简单的方法是添加属性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);
我有同样的问题,但我不想扩展fabric.js类。
我写了一个函数,它将参数中的布料canvas返回到我的特殊属性的string版本:
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
。