Fabric.js - 如何使用自定义属性在服务器上保存画布

sa1*_*125 51 database json savechanges fabricjs

我希望能够将当前画布的状态保存到服务器端数据库,可能作为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');
}
Run Code Online (Sandbox Code Playgroud)

然后

function loadCanvas(json) {

  // parse the data into the canvas
  canvas.loadFromJSON(json);

  // re-render the canvas
  canvas.renderAll();

  // optional
  canvas.calculateOffset();
}
Run Code Online (Sandbox Code Playgroud)

但是,我还使用内置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();
Run Code Online (Sandbox Code Playgroud)

问题是当我在服务器端检查请求时,我发现我的自定义属性没有从画布中解析出来并与其他所有内容一起发送.这可能与toObject方法如何删除对象类中不是默认属性的任何东西有关.什么是解决此问题的好方法,这样我将能够从服务器发送的JSON字符串中保存恢复画布,并且还原的画布还将包含我的自定义属性?谢谢.

kan*_*gax 69

好问题.

如果要向对象添加自定义属性,那么这些对象在某种程度上可能是"特殊的".似乎将它们子类化将是一个合理的解决方案.

例如,这是我们如何将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 });
  }
});
Run Code Online (Sandbox Code Playgroud)

首先,我们为这些对象提供一种类型.此类型用于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));
  });
};
Run Code Online (Sandbox Code Playgroud)

我们在这里加载一个图像(来自"object.src"),然后创建一个fabric.NamedImageout of it 的实例.注意,在那时,构造函数将已经处理"名称"设置,因为我们之前覆盖了"初始化"方法.

而且我们还需要指定它fabric.NamedImage是一个异步"类",意味着它fromObject不返回实例,而是将其传递给回调:

fabric.NamedImage.async = true;
Run Code Online (Sandbox Code Playgroud)

现在我们可以尝试这一切:

// 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);
});
Run Code Online (Sandbox Code Playgroud)

  • @kangax,这真的很酷,但我正在努力做同样的事情(添加一个名字)到`fabric.Group`的子类它似乎工作到我可以保存JSON但我加载时`Uncaught TypeError:无法读取未定义的属性'async'.我对JS很新,所以可能得到`fromObject();`错了.你会碰巧知道签名吗? (3认同)

kbc*_*ool 8

哇。我在这里想念什么吗?

我已经做了很多次,不需要花哨的子类化。

文档涵盖了它:http : //fabricjs.com/docs/fabric.Canvas.html#toJSON

在对toJSON()的调用中只需包含属性名称数组作为字符串即可。

例如

canvas.toJSON(['wizard','hobbit']);
Run Code Online (Sandbox Code Playgroud)

希望...。对于奖励积分,您可以添加一个齐磊的函数,该函数将为您的自定义属性补水。

再次在文档中进行了介绍,并有一个示例。

  • 我现在意识到这个问题已经有 6 年历史了,哈哈。无论如何,我希望它可以帮助任何遇到它的人。 (2认同)

adr*_*n54 5

我有同样的问题,但我不想扩展 Fabric.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);     
}
Run Code Online (Sandbox Code Playgroud)

当我使用时,特殊属性似乎已正确导入canvas.loadFromJSON(),我正在使用布料1.7.2