Skip to main content

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;
  }
}