diff --git a/packages/core/__tests__/logicflow.test.ts b/packages/core/__tests__/logicflow.test.ts index 66c3e557a..b1b762c44 100644 --- a/packages/core/__tests__/logicflow.test.ts +++ b/packages/core/__tests__/logicflow.test.ts @@ -1,4 +1,4 @@ -import { BaseNode, BaseNodeModel, Keyboard } from '../src' +import { BaseNode, BaseNodeModel, EventType, Keyboard } from '../src' import LogicFlow from '../src/LogicFlow' // import Tool from '../src/tool' /** @@ -464,6 +464,45 @@ describe('logicflow/apis', () => { }) }) + test('emit node properties change when undo/redo', async () => { + const dom = document.createElement('div') + dom.id = 'history-graph' + document.body.appendChild(dom) + const historyLf = new LogicFlow({ + container: dom, + }) + historyLf.renderRawData(rawData) + historyLf.history.waitTime = 0 + + const propertiesChangeHandler = jest.fn() + historyLf.on(EventType.NODE_PROPERTIES_CHANGE, propertiesChangeHandler) + historyLf.setProperties('node1', { + width: 160, + height: 80, + }) + await new Promise((resolve) => setTimeout(resolve, 20)) + + propertiesChangeHandler.mockClear() + historyLf.undo() + expect(propertiesChangeHandler).toBeCalledWith( + expect.objectContaining({ + id: 'node1', + preProperties: { width: 160, height: 80 }, + properties: {}, + }), + ) + + propertiesChangeHandler.mockClear() + historyLf.redo() + expect(propertiesChangeHandler).toBeCalledWith( + expect.objectContaining({ + id: 'node1', + preProperties: {}, + properties: { width: 160, height: 80 }, + }), + ) + }) + test('delete properties', () => { lf.renderRawData(rawData) lf.deleteProperty('node1', 'a') diff --git a/packages/core/src/LogicFlow.tsx b/packages/core/src/LogicFlow.tsx index fb6257acc..3a8eaa059 100644 --- a/packages/core/src/LogicFlow.tsx +++ b/packages/core/src/LogicFlow.tsx @@ -1,5 +1,5 @@ import { ComponentType, createElement as h, render } from 'preact/compat' -import { cloneDeep, forEach, indexOf, isNil } from 'lodash-es' +import { cloneDeep, forEach, indexOf, isEqual, isNil } from 'lodash-es' import { observer } from '.' import { Options as LFOptions } from './options' import * as _Model from './model' @@ -1160,16 +1160,41 @@ export class LogicFlow { /********************************************************* * History/Resize 相关方法 ********************************************************/ + private emitNodePropertiesChange( + preGraphData: GraphData, + curGraphData: GraphData, + ) { + const preNodeMap = new Map(preGraphData.nodes.map((node) => [node.id, node])) + forEach(curGraphData.nodes, (node) => { + const preNode = preNodeMap.get(node.id) + if (!preNode) return + const preProperties = (preNode.properties ?? {}) as Record + const properties = (node.properties ?? {}) as Record + if (isEqual(preProperties, properties)) return + const keys = Array.from( + new Set([...Object.keys(preProperties), ...Object.keys(properties)]), + ).filter((key) => !isEqual(preProperties[key], properties[key])) + this.graphModel.eventCenter.emit(EventType.NODE_PROPERTIES_CHANGE, { + id: node.id, + keys, + preProperties, + properties, + }) + }) + } + /** * 历史记录操作 * 返回上一步 */ undo() { if (!this.history.undoAble()) return + const preGraphData = this.graphModel.modelToGraphData() // formatData兼容vue数据 const graphData = formatData(this.history.undo()!) this.clearSelectElements() this.graphModel.graphDataToModel(graphData) + this.emitNodePropertiesChange(preGraphData, graphData) } /** @@ -1178,10 +1203,12 @@ export class LogicFlow { */ redo() { if (!this.history.redoAble()) return + const preGraphData = this.graphModel.modelToGraphData() // formatData兼容vue数据 const graphData = formatData(this.history.redo()!) this.clearSelectElements() this.graphModel.graphDataToModel(graphData) + this.emitNodePropertiesChange(preGraphData, graphData) } /**