diff --git a/examples/x6-example-features/src/pages/history/index.tsx b/examples/x6-example-features/src/pages/history/index.tsx
new file mode 100644
index 00000000000..df309e750c5
--- /dev/null
+++ b/examples/x6-example-features/src/pages/history/index.tsx
@@ -0,0 +1,104 @@
+import React from 'react'
+import { Graph } from '@antv/x6'
+import { Keyboard } from '@antv/x6-plugin-keyboard'
+import { Selection } from '@antv/x6-plugin-selection'
+import { History } from '@antv/x6-plugin-history'
+import '../index.less'
+
+export default class Example extends React.Component<
+ {},
+ { graph: Graph | undefined }
+> {
+ private container: HTMLDivElement
+
+ componentDidMount() {
+ const graph = new Graph({
+ container: this.container,
+ width: 800,
+ height: 600,
+ grid: true,
+ })
+
+ this.setState({ graph })
+
+ const selection = new Selection({ enabled: true })
+ const keyboard = new Keyboard({ enabled: true })
+ const history = new History({ enabled: true, stackSize: 5 })
+
+ graph.use(selection)
+ graph.use(keyboard)
+ graph.use(history)
+
+ graph.addNode({
+ x: 50,
+ y: 50,
+ width: 100,
+ height: 40,
+ attrs: { label: { text: 'A' } },
+ })
+
+ graph.addNode({
+ x: 250,
+ y: 50,
+ width: 100,
+ height: 40,
+ attrs: { label: { text: 'B' } },
+ })
+
+ graph.addNode({
+ x: 350,
+ y: 150,
+ width: 100,
+ height: 40,
+ attrs: { label: { text: 'C' } },
+ })
+
+ keyboard.bindKey('backspace', () => {
+ graph.removeCells(selection.getSelectedCells())
+ })
+ keyboard.bindKey('command+z', () => {
+ this.undo()
+ })
+ keyboard.bindKey('command+shift+z', () => {
+ this.redo()
+ })
+ }
+
+ refContainer = (container: HTMLDivElement) => {
+ this.container = container
+ }
+
+ enablePlugins = () => {
+ const { graph } = this.state
+ graph?.enablePlugins('keyboard')
+ }
+
+ disablePlugins = () => {
+ const { graph } = this.state
+ graph?.disablePlugins('keyboard')
+ }
+
+ undo = () => {
+ const { graph } = this.state
+ const history = graph?.getPlugin('history') as History
+ history?.undo()
+ }
+
+ redo = () => {
+ const { graph } = this.state
+ const history = graph?.getPlugin('history') as History
+ history?.redo()
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ )
+ }
+}
diff --git a/examples/x6-example-features/src/pages/index.tsx b/examples/x6-example-features/src/pages/index.tsx
index 4ae0449ee03..d218d81cedc 100755
--- a/examples/x6-example-features/src/pages/index.tsx
+++ b/examples/x6-example-features/src/pages/index.tsx
@@ -179,6 +179,10 @@ const dataSource = [
example: 'animation/transition',
description: '动画',
},
+ {
+ example: 'history',
+ description: '时光回溯',
+ },
].map((item, index) => ({ key: index, ...item }))
const columns = [
diff --git a/packages/x6-plugin-history/src/index.ts b/packages/x6-plugin-history/src/index.ts
index 84ea02b662d..a3faa0a8289 100644
--- a/packages/x6-plugin-history/src/index.ts
+++ b/packages/x6-plugin-history/src/index.ts
@@ -25,6 +25,7 @@ export class History
protected batchLevel = 0
protected lastBatchIndex = -1
protected freezed = false
+ protected stackSize = 0 // 0: not limit
protected readonly handlers: ((
event: T,
@@ -33,6 +34,8 @@ export class History
constructor(options: History.Options) {
super()
+ const { stackSize = 0 } = options
+ this.stackSize = stackSize
this.options = Util.getOptions(options)
this.validator = new History.Validator({
history: this,
@@ -101,7 +104,7 @@ export class History
const cmd = this.redoStack.pop()
if (cmd) {
this.applyCommand(cmd, options)
- this.undoStack.push(cmd)
+ this.undoStackPush(cmd)
this.notify('redo', cmd, options)
}
}
@@ -424,7 +427,7 @@ export class History
const cmds = this.filterBatchCommand(this.batchCommands)
if (cmds.length > 0) {
this.redoStack = []
- this.undoStack.push(cmds)
+ this.undoStackPush(cmds)
this.consolidateCommands()
this.notify('add', cmds, options)
}
@@ -498,7 +501,7 @@ export class History
this.lastBatchIndex = Math.max(this.lastBatchIndex, 0)
this.emit('batch', { cmd, options })
} else {
- this.undoStack.push(cmd)
+ this.undoStackPush(cmd)
this.consolidateCommands()
this.notify('add', cmd, options)
}
@@ -560,6 +563,17 @@ export class History
this.undoStack.pop()
}
+ protected undoStackPush(cmd: History.Commands) {
+ if (this.stackSize === 0) {
+ this.undoStack.push(cmd)
+ return
+ }
+ if (this.undoStack.length >= this.stackSize) {
+ this.undoStack.shift()
+ }
+ this.undoStack.push(cmd)
+ }
+
@Basecoat.dispose()
dispose() {
this.validator.dispose()
@@ -614,7 +628,9 @@ export namespace History {
cancelInvalid?: boolean
}
- export interface Options extends Partial {}
+ export interface Options extends Partial {
+ stackSize?: number
+ }
interface Data {
id?: string