协作模式:
将更改从Client#1的画布传播到客户端#2的画布的最佳方法是什么?以下是我捕获事件并将事件发送到Socket.io的方法。
$scope.canvas.on('object:modified',function(e) {
Socket.whiteboardMessage({
eventId:'object:modified',
event:e.target.toJSON()
});
});
在接收方,此代码可以很好地将新对象添加到屏幕上,但我找不到有关如何选择和更新<的文档/ strong>画布中的现有对象。
fabric.util.enlivenObjects([e.event], function(objects) {
objects.forEach(function(o) {
$scope.canvas.add(o);
});
});
我确实看到对象有个人设置器和一个批量设置器,但我无法弄清楚如何根据事件数据选择现有对象。
理想情况下,流程将是:
希望有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消息时,我都可以通过此行在画布中找到它:
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) { });
答案 0 :(得分:2)
我做了类似的事情,涉及多个用户之间的单个共享画布,并遇到了这个问题。
为了解决这个问题,我为添加到画布的每个对象添加了唯一的ID(使用javascript UUID生成器)(在我的情况下,可能有很多用户一次在画布上工作,因此我需要避免碰撞;在你的情况下,更简单的东西可以工作)。
Fabric对象'set
方法将允许您添加任意属性,如id:o.set('id', yourid)
。在向布局add()
新的Fabric对象(并通过线路发送)之前,请添加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从画布中获取该对象,并使用适当的set
方法或批量复制属性进行变更(或者,如果getObjectById
返回null
,创造它。)