协作模式:

将更改从客户端 #1 的 Canvas 传播到客户端 #2 的 Canvas 的最佳方法是什么?下面是我如何捕获事件并将其发送到 Socket.io。

$scope.canvas.on('object:modified',function(e) {
  Socket.whiteboardMessage({
    eventId:'object:modified',
    event:e.target.toJSON()
  });
});

在接收方,此代码非常适合将 对象添加到屏幕,但我找不到有关如何 选择 更新 Canvas 中现有对象的文档。
fabric.util.enlivenObjects([e.event], function(objects) {
  objects.forEach(function(o) {
    $scope.canvas.add(o);
  });
});

我确实看到对象有单独的 setter 和一个批量 setter ,但我无法弄清楚如何根据事件数据选择现有对象。

理想情况下,流程是:
  • 接收带有目标对象数据的事件。
  • 选择 Canvas 中的现有对象。
  • 执行批量更新。
  • 刷新 Canvas 。

  • 希望有 Fabric.JS 经验的人可以帮助我解决这个问题。谢谢!

    更新的答案 - 谢谢 AJM!

    AJM 为每个新创建的元素建议一个唯一的 ID 是正确的。我还能够为所有新创建的绘图路径创建一个新 ID。这是它的工作原理:
    var t = new fabric.IText('Edit me...', {
      left: $scope.width/2-100,
      top: $scope.height/2-50
    });
    t.set('id',randomHash());
    $scope.canvas.add(t);
    

    我还捕获了新创建的路径并添加了一个 id:
    $scope.canvas.on('path:created',function(e) {
      if (e.target.id === undefined) {
        e.target.set('id',randomHash());
      }
    });
    

    但是,我遇到了一个问题,我的 ID 在控制台日志中可见,但在执行 object.toJSON() 后不存在。这是因为 Fabric 有自己的序列化方法,可以将数据缩减为标准化的属性列表。为了包含其他属性,我必须像这样序列化传输数据:
    $scope.canvas.on('object:modified',function(e) {
      Socket.whiteboardMessage({
        object:e.target.toJSON(['id']) // includes "id" in output.
      })
    });
    

    现在每个对象都有一个唯一的 ID 来执行更新。在我的代码的接收方一侧,我添加了 AJM 的对象查找功能。我将此代码放在我的应用程序的“启动”部分,因此它只会运行一次(当然是在加载 Fabric.js 之后!)
    fabric.Canvas.prototype.getObjectById = function (id) {
        var objs = this.getObjects();
        for (var i = 0, len = objs.length; i < len; i++) {
            if (objs[i].id == id) {
                return objs[i];
            }
        }
        return 0;
    };
    

    现在,每当收到带有白板数据的新 socket.io 消息时,我都可以通过以下行在 Canvas 中找到它:
    var obj = $scope.canvas.getObjectById(e.object.id);
    

    插入和删除很容易,但为了更新,最后一段代码做到了:
    obj.set(e.object); // Updates properties
    $scope.canvas.renderAll(); // Redraws canvas
    $scope.canvas.calcOffset(); // Updates offsets
    

    所有这些都要求我处理以下事件。路径一旦创建就被视为对象。
    $scope.canvas.on('object:added',function(e) { });
    $scope.canvas.on('object:modified',function(e) { });
    $scope.canvas.on('object:moving',function(e) { });
    $scope.canvas.on('object:removed',function(e) { });
    $scope.canvas.on('path:created',function(e) { });
    

    最佳答案

    我做了一些类似的事情,涉及多个用户之间的单个共享 Canvas ,并遇到了这个确切的问题。

    为了解决这个问题,我为添加到 Canvas 的每个对象添加了唯一的 ID(使用 javascript UUID 生成器)(在我的例子中,可能有很多用户一次在 Canvas 上工作,因此我需要避免冲突;在你的情况下,一些更简单的方法可以工作)。

    Fabric 对象的 set 方法将允许您添加任意属性,例如 id: o.set('id', yourid) 。在将新的 Fabric 对象 add() 到您的 Canvas (并通过网络发送)之前,添加一个 ID 属性。现在,您将拥有一个唯一的键,您可以通过它来挑选单个对象。

    从那里,您需要一种通过 ID 检索对象的方法。这是我使用的:

    fabric.Canvas.prototype.getObjectById = function (id) {
        var objs = this.getObjects();
        for (var i = 0, len = objs.length; i < len; i++) {
            if (objs[i].id == id) {
                return objs[i];
            }
        }
    
        return null;
    };
    

    当您从套接字接收数据时,通过 ID 从 Canvas 中获取该对象并使用适当的 set 方法或批量复制属性对其进行变异(或者,如果 getObjectById 返回 null ,则创建它)。

    关于events - Fabric.js - 同步对象 :modified event to another client,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38226346/

    10-14 17:42
    查看更多