撤销/重做 Undo/Redo

阅读时间约 3 分钟

创建画布时,通过以下配置开启画布撤销/重做能力。

const graph = new Graph({
  history: true,
})

// 等同于
const graph = new Graph({
  history: {
    enabled: true,
  },
})

创建画布后,调用 graph.enableHistory()graph.disableHistory() 来启用和禁用。

if (graph.isHistoryEnabled()) {
  graph.disableHistory()
} else {
  graph.enableHistory()
}

演示

  • 随意移动节点后,Undo 按钮变得可用。
  • 点击 Undo 按钮,节点位置被还原,然后 Redo 按钮变得可用。
  • 点击 Redo 按钮,节点位置被更新。

选项

interface HistoryOptions {
  ignoreAdd?: boolean
  ignoreRemove?: boolean
  ignoreChange?: boolean
  beforeAddCommand?: <T extends ModelEvents>(
    this: HistoryManager,
    event: T,
    args: Model.EventArgs[T],
  ) => any
  afterAddCommand?: <T extends ModelEvents>(
    this: HistoryManager,
    event: T,
    args: Model.EventArgs[T],
    cmd: Command,
  ) => any
  executeCommand?: (
    this: HistoryManager,
    cmd: Command,
    revert: boolean,
    options: KeyValue,
  ) => any
  revertOptionsList?: string[]
  applyOptionsList?: string[]
}

ignoreAdd, ignoreRemove, ignoreChange

默认情况下,画布中节点/边的任何变化(添加/删除/属性变化)都将被追踪,我们提供了一些选项来控制需要追踪哪些变化:

  • ignoreAdd 是否忽略添加,默认为 false
  • ignoreRemove 是否忽略删除,默认为 false
  • ignoreChange 是否忽略属性变化,默认为 false

例如,下面配置只追踪节点和边的属性变化:

const graph = new Graph({
  history: {
    enabled: true,
    ignoreAdd: true,
    ignoreRemove: true,
    ignoreChange: false,
  },
})

beforeAddCommand

当一个命令被添加到 Undo 队列前被调用,如果该方法返回 false,那么这个命令将不会被添加到 Undo 队列中。

const graph = new Graph({
  history: {
    enabled: true,
    beforeAddCommand(event, args) {
      if (args.options) {
        return args.options.ignore !== false
      }
    },
  },
})

afterAddCommand

当一个命令被添加到 Undo 队列后被调用。

executeCommand

executeCommand?: (
  this: HistoryManager,
  cmd: Command,
  revert: boolean,
  options: KeyValue,
) => any

当命令被撤销或重做时被调用,reverttrue 表示命令被撤销,否则表示命令被重做。

revertOptionsList

传递给撤销动作的选项名数组。

const graph = new Graph({
  history: {
    enabled: true,
    revertOptionsList: [ 'option1' ],
  },
})

node.prop('name', 'value', { option1: 5, option2: 6 });
graph.undo(); // -> calls node.prop('name', 'prevValue', { option1: 5 });

applyOptionsList

传递给重做动作的选项名数组。

const graph = new Graph({
  history: {
    enabled: true,
    applyOptionsList: [ 'option2' ],
  },
})

node.set('name', 'value', { option1: 5, option2: 6 });
graph.undo();
graph.redo(); // -> calls node.set('name', 'value', { option2: 6 });

事件

undo

当命令被撤销时触发。

graph.history.on('undo', (args: {
  cmds: Command[]
  options: KeyValue
}) => { 
  // code here
})

redo

当命令被重做时触发。

graph.history.on('redo', (args: {
  cmds: Command[]
  options: KeyValue
}) => { 
  // code here
})

cancel

当命令被取消时触发。

graph.history.on('cancel', (args: {
  cmds: Command[]
  options: KeyValue
}) => { 
  // code here
})

add

当命令被添加到队列时触发。

graph.history.on('add', (args: {
  cmds: Command[]
  options: KeyValue
}) => { 
  // code here
})

clean

当历史队列被清空时触发。

graph.history.on('clean', (args: {
  cmds: Command[] | null
  options: KeyValue
}) => { 
  // code here
})

change

当历史队列改变时触发。

graph.history.on('change', (args: {
  cmds: Command[] | null
  options: KeyValue
}) => { 
  // code here
})

batch

当接收到 batch 命令时触发。

graph.history.on('batch', (args: { 
  cmd: Command 
  options: KeyValue 
}) => { 
  // code here
})

API

graph.undo(...)

undo(options?: KeyValue): this

撤销。options 将被传递到事件回调中。

graph.undoAndCancel(...)

undoAndCancel(options?: KeyValue): this

撤销,并且不添加到重做队列中,所以这个被撤销的命令不能被重做。options 将被传递到事件回调中。

graph.redo(...)

redo(options?: KeyValue): this

重做。options 将被传递到事件回调中。

graph.canUndo()

canUndo(): boolean

是否可以撤销。

graph.canRedo()

canRedo(): boolean

是否可以重做。

graph.cleanHistory(...)

cleanHistory(options?: KeyValue): this

清空历史队列。options 将被传递到事件回调中。

graph.isHistoryEnabled()

isHistoryEnabled(): boolean

是否启用了历史状态。

graph.enableHistory()

enableHistory(): this

启用历史状态。

graph.disableHistory()

disableHistory(): this

禁用历史状态。

graph.toggleHistory(...)

toggleHistory(enabled?: boolean): this

切换历史的启用状态。

参数

名称类型必选默认值描述
enabledboolean-是否启用历史状态,缺省时切换历史的启用状态。