前言
关于画板基本功能的实现,可以看这篇:基于 Fabric.js 实现一个简易画板
准备工作
完善一下 Sketchpad
类的实现:
-
isRecoverable
字段:表示当前是否可以进行恢复操作,以区分已经撤销了部分元素但又重新添加或粘贴了新元素的情况,这种情况是无法继续恢复的。 -
maxLimit
字段:表示撤销操作的最大限制数量。 -
stateStack
字段:存储被撤销的元素列表。
// sketchpad.ts
interface Instance extends Object {
[key: string]: any; // 兼容自定义属性
}
interface FabricObject extends Instance {
top: number;
left: number;
}
class Sketchpad {
// ...
public instance: Canvas;
private isRecoverable = false;
private stateStack: Array<Instance> = [];
private maxLimit = 5;
getObjects() {
return this.instance.getObjects() as FabricObject[]; // 获取画板上的所有元素
}
}
具体代码实现
// sketchpad.ts
insertShape(type: ShapeType) {
const shape: Instance = createShape(type); // 生成对应类型的实例
shape.top = 150;
shape.left = 150;
this.instance.add(shape).renderAll(); // 添加元素到画板上,并重新渲染画板
this.isRecoverable = false; // 添加元素后,无法进行恢复操作
}
undo() {
const target = this.getAllObjects().pop() as FabricObject; // 获取最新添加的元素
// 如果撤销列表已满,移除最早的记录,再加入最新记录
if (this.stateStack.length >= this.maxLimit) {
this.stateStack.shift();
}
this.stateStack.push(target);
this.instance.remove(target).renderAll(); // 从画板上移除元素,并重新渲染画板
this.isRecoverable = true; // 撤销元素后,允许进行恢复操作
}
redo() {
// 当前允许恢复元素,并且撤销列表中存在元素
if (this.isRecoverable && this.stateStack.length > 0) {
const target = this.stateStack.pop() as FabricObject;
this.instance.add(target).renderAll(); // 重新添加元素到画板上
} else {
this.stateStack = []; // 清空当前撤销列表,不可恢复
}
}
函数实现已完成,接下来分别展示未限制和限制了最大撤销空间的效果:
最后
目前的实现方式比较简单,只能反应出元素的增减,而不能反应出元素的变化。
欢迎大家提出建议,一起进步。