Fabric.js - 如何使用自定义属性在服务器上保存画布 [英] Fabric.js - how to save canvas on server with custom attributes

查看:30
本文介绍了Fabric.js - 如何使用自定义属性在服务器上保存画布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够将当前画布的状态保存到服务器端数据库,可能是一个 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..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(构造函数)实例方法,在初始化对象时也设置name"属性(如果该属性已给出).

Then we overwrite initialize (constructor) instance method, to also set "name" property when initializing an object (if that property is given).

然后我们重写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 的实例.请注意,此时构造函数将如何处理名称"设置,因为我们之前覆盖了初始化"方法.

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;

现在我们可以试一试:

// 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆