首页 > 解决方案 > 如何将自定义方法重新加载到反序列化的 FabricJS 对象?

问题描述

我已经在一个项目中熟悉了 FabricJS。

我有一个扩展的自定义类fabric.Polyline。这个自定义类有很多自定义方法。我的问题是:当我序列化整个画布并稍后使用loadFromJSON()再次加载它时,自定义方法不再存在......

我注意到序列化之前/之后的对象并不完全相同。事实上,我们可以看到,在序列化之后,该方法myCustomClassMethod()不再存在于对象中__proto__

差异项目

我知道loadFromJSON()有一个reviver()重新添加事件监听器的方法,但是我怎样才能重新添加方法呢?教程说我需要添加一个 fromObject() 方法来保存/恢复对象,我尝试使用它但没有运气。

也可能是我的反序列化对象是“常规”对象,而不是 fabricjs 对象实例。但我还没有看到如何让它再次成为织物对象。

MRE 在下面。如您所见,如果在重新加载画布之前调用该方法,则该方法有效,但如果在之后调用该方法则无效。

// create a wrapper around native canvas element (with id="treeCanvas")
var canvas = new fabric.Canvas('treeCanvas', {
    allowTouchScrolling: true,
});

// un-comment log below to inspect objects
canvas.on('mouse:up', function (e) {
    if (e.target != null) {
        //console.log(e.target);
    }
});


// My TreeNode custom class
var TreeNode = fabric.util.createClass(fabric.Polyline, {

    initialize: function (X, Y, armsArray, options) {
        options || (options = {});
        this.callSuper('initialize', options);
        this.X = X;
        this.Y = Y;
        this.armsArray = armsArray;

        this.set({ width: 160, height: 50, originX: 'center', originY: 'center' });
        this.set({ left: this.X, top: this.Y, fill: 'rgba(255, 255, 255, 0)', stroke: 'black', selectable: true });
        this.setCoords();
        this.set({ pathOffset: { x: 0, y: 25 } });

        for (point of this.armsArray) {
            this.points.push({ x: point[0], y: point[1] });
            this.points.push({ x: 0, y: 0 });
        }
    },
    _render: function (ctx) {
        this.callSuper('_render', ctx);
    },

    // this is the method that disappears after serializing
    myCustomClassMethod: function () {
        this.set({ stroke: 'green' });
        canvas.renderAll();
    }
});

// Adding an instance of my custom class to canvas
var node1 = new TreeNode(100, 100, [[-80, 50], [80, 50]], []);
canvas.add(node1);
canvas.renderAll();

// node1.myCustomClassMethod(); // method works before serializing + deserializing


var stringifiedCanvas = JSON.stringify(canvas);
canvas.loadFromJSON(stringifiedCanvas, canvas.renderAll.bind(canvas));

node1.myCustomClassMethod(); // method DOES NOT WORK anymore after deserializing
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>

<div class="container">
    <canvas id="treeCanvas" width="500" height="300"></canvas>
</div>

<script src="canvas.js"></script>

标签: javascriptfabricjs

解决方案


我远不是专家fabricjs,我做的事情有些不同,但你错过了一些重要的部分(在下面的代码中标有“** CHANGE”)

希望这个对你有帮助!


// create a wrapper around native canvas element (with id="treeCanvas")
var canvas = new fabric.Canvas('treeCanvas', {
  allowTouchScrolling: true,
});

// un-comment log below to inspect objects
canvas.on('mouse:up', function(e) {
  if (e.target != null) {
    //console.log(e.target);
  }
});


// ** CHANGE: define Treenode on the fabric instance
fabric.TreeNode = fabric.util.createClass(fabric.Polyline, {

  // ** CHANGE: define the type
  type: 'treeNode',

  initialize: function(X, Y, armsArray, options) {
    options || (options = {});
    this.callSuper('initialize', options);
    this.X = X;
    this.Y = Y;
    this.armsArray = armsArray;

    this.set({
      width: 160,
      height: 50,
      originX: 'center',
      originY: 'center'
    });
    this.set({
      left: this.X,
      top: this.Y,
      fill: null,
      stroke: 'black',
      selectable: true
    });
    this.setCoords();
    this.set({
      pathOffset: {
        x: 0,
        y: 25
      }
    });

    for (point of this.armsArray) {
      this.points.push({
        x: point[0],
        y: point[1]
      });
      this.points.push({
        x: 0,
        y: 0
      });
    }
  },
  _render: function(ctx) {
    this.callSuper('_render', ctx);
  },

  // ** CHANGE: export the custom method when serializing
  toObject: function() {
    return fabric.util.object.extend(this.callSuper('toObject'), {
      myCustomClassMethod: this.myCustomClassMethod
    });
  },

  myCustomClassMethod: function(x, y, color) {
    // console.log("myCustomClassMethod")
    // console.log(this.myCustomClassMethod)

    this.set({
      left: x,
      top: y,
      stroke: color,
      strokeWidth: 10
    });
    canvas.renderAll();
  }
});

fabric.TreeNode.fromObject = function(object, callback) {
  // console.log(object)
};


var node1 = new fabric.TreeNode(100, 100, [
  [-80, 50],
  [80, 50]
], []);
canvas.add(node1);

canvas.renderAll();

// DESERIALIZE
var stringifiedCanvas = JSON.stringify(canvas);
canvas.loadFromJSON(stringifiedCanvas, canvas.renderAll.bind(canvas));

// ** CHANGE: need to get a reference to the restored object
var restored = canvas.getObjects()[0]
///console.log(restored)
restored.myCustomClassMethod(200, 50, "red");
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>

<div class="container">
  <canvas id="treeCanvas" width="500" height="300"></canvas>
</div>

<script src="canvas.js"></script>


推荐阅读