Javascript Fabricjs-在画布上实现撤消/重做
我是vue和fabricjs的新手,目前正在开发一个处理大量数据的复杂应用程序。 我有多张不同对象的画布,这些画布可能会根据用户交互而改变。 所有更改/对象都存储在对象数组中 演示: 我正在尝试在我的应用程序中实现撤消/重做。 我很难理解下面答案(链接)中的fabricjs撤消/重做方法 从上面的答案(链接)中,我认为它一次处理单个画布,其中包含多个对象,但在我的情况下,我的画布对象存储在一个对象数组中,并将根据用户交互(如添加颜色、添加文本、,添加一次将在所有画布上执行的rect和撤消应反映在所有画布上。简而言之,我有多张画布,里面有相同的对象) 我尝试了下面的非结构方法,其中undo,redo作用于历史索引,该索引将根据undo(递增指针)、redo(递减指针)概念进行更改 基于这种方法,我称之为变异,其中Javascript Fabricjs-在画布上实现撤消/重做,javascript,fabricjs,implementation,undo-redo,Javascript,Fabricjs,Implementation,Undo Redo,我是vue和fabricjs的新手,目前正在开发一个处理大量数据的复杂应用程序。 我有多张不同对象的画布,这些画布可能会根据用户交互而改变。 所有更改/对象都存储在对象数组中 演示: 我正在尝试在我的应用程序中实现撤消/重做。 我很难理解下面答案(链接)中的fabricjs撤消/重做方法 从上面的答案(链接)中,我认为它一次处理单个画布,其中包含多个对象,但在我的情况下,我的画布对象存储在一个对象数组中,并将根据用户交互(如添加颜色、添加文本、,添加一次将在所有画布上执行的rect和撤消应反
apply(state,actiontype){
if(actiontype==undo){
remove the respective objects
pop(data) //pops the data out of other places in the application not the history
historyindex++;
}else if(actiontype==redo){
get the data from history
unshift(data);
historyindex–-;
}
}
我觉得这不是执行撤消/重做操作的最有效方式,因为它包括克隆对象,甚至还必须处理大量数据集。这可能会导致应用程序冻结。任何建议都会很有帮助
代码:(多张画布)
已编辑:我已使用撤消/重做功能更新了示例,使用了结构历史库,仍在尝试找到更好的方法。我认为您需要使用命令模式来完成此操作。它将比使用所有json数据更有效。为此,您需要实施下一种方法:
class AddCommand {
constructor(receiver, controller) {
this.receiver = receiver;
this.controller = controller;
}
execute() {
this.controller.addObject(this.receiver);
}
undo() {
this.controller.removeObject(this.receiver);
}
}
// When you will add object on your canvas invoke also this.history.add(new AddCommand(object, controller))
class RemoveCommand {
constructor(receiver, controller) {
this.receiver = receiver;
this.controller = controller;
}
execute() {
this.controller.removeObject(this.receiver);
}
undo() {
this.controller.addObject(this.receiver);
}
}
fabric.js对每个对象都有saveState方法。您可以将其用于实现转换命令,当您在画布上修改fabric对象时,该命令将添加到历史对象JECCT中
class TransformCommand {
constructor(receiver, options = {}) {
this.receiver = receiver;
this._initStateProperties(options);
this.state = {};
this.prevState = {};
this._saveState();
this._savePrevState();
}
execute() {
this._restoreState();
this.receiver.setCoords();
}
undo() {
this._restorePrevState();
this.receiver.setCoords();
}
// private
_initStateProperties(options) {
this.stateProperties = this.receiver.stateProperties;
if (options.stateProperties && options.stateProperties.length) {
this.stateProperties.push(...options.stateProperties);
}
}
_restoreState() {
this._restore(this.state);
}
_restorePrevState() {
this._restore(this.prevState);
}
_restore(state) {
this.stateProperties.forEach((prop) => {
this.receiver.set(prop, state[prop]);
});
}
_saveState() {
this.stateProperties.forEach((prop) => {
this.state[prop] = this.receiver.get(prop);
});
}
_savePrevState() {
if (this.receiver._stateProperties) {
this.stateProperties.forEach((prop) => {
this.prevState[prop] = this.receiver._stateProperties[prop];
});
}
}
}
现在,您可以在历史记录中添加命令并执行或撤消它们。请不要多次发布同一问题。
class TransformCommand {
constructor(receiver, options = {}) {
this.receiver = receiver;
this._initStateProperties(options);
this.state = {};
this.prevState = {};
this._saveState();
this._savePrevState();
}
execute() {
this._restoreState();
this.receiver.setCoords();
}
undo() {
this._restorePrevState();
this.receiver.setCoords();
}
// private
_initStateProperties(options) {
this.stateProperties = this.receiver.stateProperties;
if (options.stateProperties && options.stateProperties.length) {
this.stateProperties.push(...options.stateProperties);
}
}
_restoreState() {
this._restore(this.state);
}
_restorePrevState() {
this._restore(this.prevState);
}
_restore(state) {
this.stateProperties.forEach((prop) => {
this.receiver.set(prop, state[prop]);
});
}
_saveState() {
this.stateProperties.forEach((prop) => {
this.state[prop] = this.receiver.get(prop);
});
}
_savePrevState() {
if (this.receiver._stateProperties) {
this.stateProperties.forEach((prop) => {
this.prevState[prop] = this.receiver._stateProperties[prop];
});
}
}
}