- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我面临一个关于织物事件的奇怪问题。看看这个片段
canvas.on('object:added', function(e) {
console.log(e.target.type);
console.log("Something was Added");
});
canvas.on('object:removed', function(e) {
console.log(e.target.type);
console.log("Something was removed");
});
// Undo Redo Clear
canvas.counter = 0;
var newleft = 0;
canvas.selection = false;
var state = [];
var mods = 0;
canvas.on(
'object:modified', function () {
updateModifications(true);
},
'object:added', function () {
updateModifications(true);
},
'object:removed' , function(e){
updateModifications(true);
console.log('test me');
});
function updateModifications(savehistory) {
if (savehistory === true) {
myjson = JSON.stringify(canvas);
state.push(myjson);
console.log(myjson);
}
}
undo = function undo() {
if (mods < state.length) {
canvas.clear().renderAll();
canvas.loadFromJSON(state[state.length - 1 - mods - 1]);
canvas.renderAll();
mods += 1;
//check_team();
//compare_states(state[state.length - 1 - mods - 1] , state[state.length - 1 - mods + 1])
}
//make_objects_selectable();
}
redo = function redo() {
if (mods > 0) {
canvas.clear().renderAll();
canvas.loadFromJSON(state[state.length - 1 - mods + 1]);
canvas.renderAll();
mods -= 1;
//check_team();
}
//make_objects_selectable();
}
clearcan = function clearcan() {
canvas.clear().renderAll();
newleft = 0;
}
最佳答案
您的撤消和重做功能基本上都做同样的事情,删除 Canvas ,加载新状态并渲染它。清除 Canvas 时,没有 object:removed
事件,但触发了另一个事件,称为 canvas:cleared
.这就是为什么你永远看不到你的 object:removed
撤消/重做时触发的事件。另一方面,您确实看到了 object:added
撤消和重做都被触发,因为我猜 canvas.renderAll
将当前状态的每个对象添加到 Canvas 中(因为之前使用 canvas.clear() 删除了它)。
编辑
更好的解决方案是存储在 Canvas 上发生的每个操作,例如添加、修改或删除,并将每个操作与一些对象数据相关联。例如,您可以有一个 object_added
与添加对象的序列化相关的操作,或 object_removed
与已移除对象的序列化相关联的操作。对于 object_modified
您将需要两个关联的对象序列化,一个是事先修改,一个是修改后。如果是 canvas_cleared
操作,您必须将整个 Canvas 状态存储为关联数据。
一个简单的堆栈结构可以很好地用于操作存储。
function SimpleStackException(msg) {
this.message = msg;
this.name = 'SimpleStackException';
}
function SimpleStack() {
var MAX_ENTRIES = 2048;
var self = this;
self.sp = -1; // stack pointer
self.entries = []; // stack heap
self.push = function(newEntry) {
if (self.sp > MAX_ENTRIES - 1) {
throw new SimpleStackException('Can not push on a full stack.');
}
self.sp++;
self.entries[self.sp] = newEntry;
// make sure to clear the "future" stack after a push occurs
self.entries.splice(self.sp + 1, self.entries.length);
};
self.pop = function() {
if (self.sp < 0) {
throw new SimpleStackException('Can not pop from an empty stack.');
}
var entry = self.entries[self.sp];
self.sp--;
return entry;
};
self.reversePop = function() {
self.sp++;
if (!self.entries[self.sp]) {
self.sp--;
throw new SimpleStackException('Can not reverse pop an entry that has never been created.');
}
return self.entries[self.sp];
}
}
var actionHistory = new SimpleStack();
canvas.getObjects()
中的对象,但这是一个普通的 js 数组,并没有多大帮助。我以 UUID 的形式添加了对象 ID。
var lut = [];
for (var i = 0; i < 256; i++) {
lut[i] = (i < 16 ? '0' : '') + (i).toString(16);
}
function generateUuid() {
var d0 = Math.random() * 0xffffffff | 0;
var d1 = Math.random() * 0xffffffff | 0;
var d2 = Math.random() * 0xffffffff | 0;
var d3 = Math.random() * 0xffffffff | 0;
return lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff] + '-' +
lut[d1 & 0xff] + lut[d1 >> 8 & 0xff] + '-' + lut[d1 >> 16 & 0x0f | 0x40] + lut[d1 >> 24 & 0xff] + '-' +
lut[d2 & 0x3f | 0x80] + lut[d2 >> 8 & 0xff] + '-' + lut[d2 >> 16 & 0xff] + lut[d2 >> 24 & 0xff] +
lut[d3 & 0xff] + lut[d3 >> 8 & 0xff] + lut[d3 >> 16 & 0xff] + lut[d3 >> 24 & 0xff];
}
fabric.Object.prototype.uuid = "";
fabric.Object.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
uuid: this.uuid,
});
};
})(fabric.Object.prototype.toObject);
function getFabricObjectByUuid(uuid) {
var fabricObject = null;
canvas.getObjects().forEach(function(object) {
if (object.uuid === uuid) {
fabricObject = object;
}
});
return fabricObject;
}
actionHistory
因此:
canvas.on('path:created', function(path) {
var object = path.path;
object.uuid = generateUuid();
actionHistory.push({
type: 'object_added',
object: JSON.stringify(object)
});
});
canvas.on('object:added', function(e) {
var object = e.target;
// bypass the event for path objects, as they are handled by `path:created`
if (object.type === 'path') {
return;
}
// if the object has not been given an uuid, that means it is a fresh object created by this client
if (!object.uuid) {
object.uuid = generateUuid();
}
if (!object.bypassHistory) {
actionHistory.push({
type: 'object_added',
object: JSON.stringify(object)
});
}
});
canvas.on('object:modified', function(e) {
var object = e.target;
actionHistory.push({
type: 'object_modified',
objectOld: JSON.stringify(latestTouchedObject),
objectNew: JSON.stringify(object)
});
});
canvas.on('text:changed', function(e) {
var object = e.target;
actionHistory.push({
type: 'text_changed',
objectOld: JSON.stringify(latestTouchedObject),
objectNew: JSON.stringify(object)
});
});
canvas.on('object:removed', function(e) {
var object = e.target;
if (!object.bypassHistory) {
actionHistory.push({
type: 'object_removed',
object: JSON.stringify(object)
});
}
});
canvas.on('canvas:cleared', function(e) {
if (!canvas.bypassHistory) {
actionHistory.push({
type: 'canvas_cleared',
canvas: JSON.stringify(canvas)
});
}
});
actionHistory
上的实际数据.还要注意
uuid
属性实际上是添加到对象中的。关于上面的代码片段有两点需要注意。
path:cleared
来保存该操作。 .但是,在以编程方式绘制线的情况下(例如,在执行重做时),您可能不想存储操作。要添加此自定义属性,请执行以下操作:event.target
轻松获得的object:modified
事件,必须以编程方式跟踪“之前”版本。在我的解决方案中,我有一个高水平 latestTouchedObject
跟踪 Canvas 上最新修改对象的变量。 canvas.on('mouse:down', function(options) {
if (options.target) {
latestTouchedObject = fabric.util.object.clone(options.target);
}
});
function undoAction() {
var action, objectCandidate;
try {
action = actionHistory.pop();
} catch (e) {
console.log(e.message);
return;
}
if (action.type === 'object_added') {
objectCandidate = JSON.parse(action.object);
var object = getFabricObjectByUuid(objectCandidate.uuid);
object.bypassHistory = true;
canvas.remove(object);
} else if (action.type === 'object_removed') {
objectCandidate = JSON.parse(action.object);
fabric.util.enlivenObjects([objectCandidate], function(actualObjects) {
actualObjects[0].uuid = objectCandidate.uuid;
var object = actualObjects[0];
object.bypassHistory = true;
canvas.add(object);
object.bypassHistory = false;
});
} else if (action.type === 'object_modified' || action.type === 'text_changed') {
objectCandidate = JSON.parse(action.objectOld);
fabric.util.enlivenObjects([objectCandidate], function(actualObjects) {
actualObjects[0].uuid = objectCandidate.uuid;
var object = actualObjects[0];
var existingObject = getFabricObjectByUuid(objectCandidate.uuid);
if (existingObject) {
existingObject.bypassRemoveEvent = true;
existingObject.bypassHistory = true;
canvas.remove(existingObject);
}
object.bypassHistory = true;
canvas.add(object);
object.bypassHistory = false;
});
} else if (action.type === 'canvas_cleared') {
var canvasPresentation = JSON.parse(action.canvas);
canvas.bypassHistory = true;
canvas.loadFromJSON(canvasPresentation);
canvas.renderAll();
canvas.bypassHistory = false;
}
}
function redoAction() {
var action, objectCandidate;
try {
action = actionHistory.reversePop();
} catch (e) {
console.log(e.message);
return;
}
if (action.type === 'object_added') {
objectCandidate = JSON.parse(action.object);
fabric.util.enlivenObjects([objectCandidate], function(actualObjects) {
actualObjects[0].uuid = objectCandidate.uuid;
var object = actualObjects[0];
object.bypassHistory = true;
canvas.add(object);
object.bypassHistory = false;
});
} else if (action.type === 'object_removed') {
objectCandidate = JSON.parse(action.object);
var object = getFabricObjectByUuid(objectCandidate.uuid);
object.bypassHistory = true;
canvas.remove(object);
object.bypassHistory = false;
} else if (action.type === 'object_modified' || action.type === 'text_changed') {
objectCandidate = JSON.parse(action.objectNew);
fabric.util.enlivenObjects([objectCandidate], function(actualObjects) {
actualObjects[0].uuid = objectCandidate.uuid;
var object = actualObjects[0];
var existingObject = getFabricObjectByUuid(objectCandidate.uuid);
if (existingObject) {
existingObject.bypassRemoveEvent = true;
existingObject.bypassHistory = true;
canvas.remove(existingObject);
}
object.bypassHistory = true;
canvas.add(object);
object.bypassHistory = false;
});
} else if (action.type === 'canvas_cleared') {
canvas.clear();
}
}
关于javascript - 对象 :removed Event Not Fired - Fabric JS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37273470/
我刚刚偶然发现Fabric并且文档并没有真正说明它是如何工作的。 我有根据的猜测是您需要在客户端和服务器端都安装它。 Python 代码存储在客户端,并在命令运行时通过 Fabric 的有线协议(pr
以下是我对 Hyperledger Fabric 系统的理解。如果有任何不正确的地方,请告诉我。 1) 所以我们有同行(背书人、 anchor 人、将军(拥有分类帐的人)、排序人)。此外,当我们设置结
我部署了一个持久性级别为 Silver 的全新 Service Fabric 集群,fabric:/System/InfrastructureService/FE 服务运行状况不佳,并出现以下错误:
我对使用 Fabric 很感兴趣,api 在未连接到互联网时如何工作? 我发现 firebase(与此工具类似的工具)会将数据存储在本地,然后对服务器进行批量更新。但是,超过 72 小时的任何内容都不
Fabric CA Server 和 Fabric CA Client 的功能是什么? Fabric CA 服务器和 Fabric CA 客户端的角色是什么? 谢谢 最佳答案 Fabric CA 提供
我想在不同的环境中使用相同的应用程序,我在 documentation 中找到了它, Apps with Multiple Environments Let’s say you have an app
我目前正在尝试学习 Hyperledger Fabric,我设法了解了如何设置网络(Orderer、Peers 等),但现在是链代码的一部分。 但是,我发现两个不同的 git 存储库(据我所知)可用于
我在 following this tutorial 时遇到错误 cannot convert from 'System.Fabric.StatelessServiceContext' to 'Sys
在我没有改变任何东西之前它可以工作,但今天我收到了这个错误,这里是我的 gradle buildscript { repositories { mavenCentral() maven
Fabric beta 手动分发有时不会发送邀请电子邮件,即使在它向该人显示“已邀请”的网页中也是如此。如果我点击重新发送邀请,那个人就会收到。我的 QA 团队人员必须一直来找我重新发送邀请。我知道
默认情况下,Hyperledger Fabric 在将许多证书保存到区 block 链之前将其存储在交易中。无论如何或任何想法/技术来最小化区 block 链中的交易大小? 任何想法都非常有用! 最佳
我是 Hyperledger Fabric 的新手。我正在阅读 Fabric 的文档最新版本,但我不清楚 Fabric 的共识。 Fabric 使用的共识是什么?它是如何工作的?请解释。 最佳答案 我
我是 Hyperledger Fabric 的新手,我正在尝试在本地向服务器注册 Fabric 客户端。这是我到目前为止所做的。 go get -u github.com/hyperledger/fa
Hyperledger Fabric 中链和状态数据库的主要区别是什么。我很困惑它们是否相同。 最佳答案 Hyperledger Fabric 中有两个“存储”数据的地方: 账本 状态数据库 账本是真
我尝试将图像上传到分类帐中(将图像转换为 base64 字符串并将其作为交易中的 arg 传递)。 当我发送大小为 30 kb 的图像时,它工作正常,但是对于 100 kb 的图像,我的交易失败了,指
我正在尝试在初始化 Fabric CA 服务器后注册管理员: fabric-ca-server init -b “admin:adminpw” 并启动 CA 服务器: fabric-ca-serve
我正在使用来自 super 账本fabric firstsample的cryptogen工具,它未在 crypto-config/peerorganisation/org1.example.com/m
我离开了一家公司,用于访问 Fabric 的电子邮件已被删除。 现在我在同一家公司工作,他们用相同的句柄重新创建了电子邮件。我不知道这是否是问题所在,但我没有收到任何包含报告的电子邮件,也没有收到 B
如果我有 1 个组织 orgA ,在这个组织下我有 2 个用户:user1和 user2 , 在 orgA 中也有 1 个对等点,让我们称之为 peer0 . 现在想象一下,user1的证书在orgA
全部, 据我所知,在 Hyperledger Fabric 环境中,orderer 将消息传递给 peer。如果有离线对等。恢复到 ON-LINE 时,消息如何传递给对端? orderer如何知道pe
我是一名优秀的程序员,十分优秀!