Angular Konva 撤销重做教程
当画布状态存储在普通数据对象中,而不是在每次渲染时从画布读取值时,撤销和重做效果最佳。
此示例将矩形位置存储在一个小型历史堆栈中,并在您点击撤销或重做时恢复之前的快照。
说明:拖动矩形以创建历史条目,然后点击撤销和重做以遍历保存的状态。
有关更多详细信息,请参阅 Rect API 参考。
撤销重做示例
import { Component } from '@angular/core';
import { StageConfig } from 'konva/lib/Stage';
import { RectConfig } from 'konva/lib/shapes/Rect';
import {
CoreShapeComponent,
StageComponent,
} from 'ng2-konva';
@Component({
selector: 'app-root',
standalone: true,
template: `
<div>
<button (click)="undo()" [disabled]="!canUndo()">撤销</button>
<button (click)="redo()" [disabled]="!canRedo()">重做</button>
<ko-stage [config]="configStage">
<ko-layer>
<ko-rect
[config]="configRect"
(dragend)="handleDragEnd($event.event)"
></ko-rect>
</ko-layer>
</ko-stage>
</div>
`,
imports: [StageComponent, CoreShapeComponent],
})
export default class App {
private history: RectConfig[] = [];
private currentIndex: number = -1;
public configStage: StageConfig = {
width: window.innerWidth,
height: window.innerHeight,
};
public configRect: RectConfig = {
x: 100,
y: 100,
width: 100,
height: 100,
fill: 'red',
draggable: true
};
constructor() {
this.saveState();
}
private saveState(): void {
// 移除当前索引之后的所有状态
this.history = this.history.slice(0, this.currentIndex + 1);
// 添加当前状态
this.history.push({ ...this.configRect });
this.currentIndex++;
}
public handleDragEnd(event: any): void {
this.configRect = {
...this.configRect,
x: event.target.x(),
y: event.target.y()
};
this.saveState();
}
public undo(): void {
if (this.canUndo()) {
this.currentIndex--;
this.configRect = { ...this.history[this.currentIndex] };
}
}
public redo(): void {
if (this.canRedo()) {
this.currentIndex++;
this.configRect = { ...this.history[this.currentIndex] };
}
}
public canUndo(): boolean {
return this.currentIndex > 0;
}
public canRedo(): boolean {
return this.currentIndex < this.history.length - 1;
}
}
手动构建的历史记录的局限
上述历史记录每一步只记录一个值。生产级编辑器必须记录分组操作,以便多选拖动可以作为一个步骤撤销,还要记录操作完成后才加载完毕的变换和图像。这种状态机通常会比绘图代码更庞大,因此应围绕文档操作而不是原始节点状态来规划历史记录。