diff --git a/packages/core/__tests__/bugs/1545-spec.test.ts b/packages/core/__tests__/bugs/1545-spec.test.ts new file mode 100644 index 000000000..36c34336f --- /dev/null +++ b/packages/core/__tests__/bugs/1545-spec.test.ts @@ -0,0 +1,38 @@ +import type { NodeConfig, TextConfig } from '../../src/index'; +import { LogicFlow } from '../../src/index'; + +type NodeConfigTextObj = NodeConfig & { text: TextConfig }; +describe('#1545', () => { + const dom = document.createElement('div'); + dom.id = 'main-graph'; + document.body.appendChild(dom); + const lf = new LogicFlow({ + container: dom, + width: 1000, + height: 1000, + grid: true, + }); + + it('clone node text pos should snap to grid', () => { + lf.render({ + nodes: [ + { + id: 'node_id_1', + type: 'rect', + x: 300, + y: 300, + text: { + x: 32, + y: 19, + value: '文本1', + }, + }, + ], + }); + const originNode = lf.getDataById('node_id_1') as NodeConfigTextObj; + const newNode = lf.cloneNode('node_id_1') as NodeConfigTextObj; + expect(originNode.x - originNode.text.x).toEqual(newNode.x - newNode.text.x); + expect(originNode.y - originNode.text.y).toEqual(newNode.y - newNode.text.y); + expect(originNode.text.value).toEqual(newNode.text.value); + }); +}); diff --git a/packages/core/__tests__/model/graphmodel.test.ts b/packages/core/__tests__/model/graphmodel.test.ts new file mode 100644 index 000000000..64f061900 --- /dev/null +++ b/packages/core/__tests__/model/graphmodel.test.ts @@ -0,0 +1,67 @@ +import type { NodeConfig, TextConfig } from '../../src/index'; +import { LogicFlow } from '../../src/index'; + +type NodeConfigTextObj = NodeConfig & { text: TextConfig }; +describe('graphmodel', () => { + const dom = document.createElement('div'); + dom.id = 'main-graph'; + document.body.appendChild(dom); + const lf = new LogicFlow({ + container: dom, + width: 1000, + height: 1000, + keyboard: { + enabled: true, + }, + allowRotation: true, + metaKeyMultipleSelected: true, + grid: true, + snapline: true, + }); + + // 将node节点位置进行grid修正,同时处理node内文字的偏移量,返回一个位置修正过的复制节点NodeModel + test('getModelAfterSnapToGrid', () => { + const rawData = { + nodes: [ + { + id: 'node1', + type: 'rect', + x: 111, + y: 123, + text: { + x: 32, + y: 19, + value: '文本1', + }, + }, + ], + }; + lf.render(rawData); + + const originNode = lf.getDataById('node1') as NodeConfigTextObj; + + // grid=true 默认 gridSize=20 + const newNode = lf.graphModel.getModelAfterSnapToGrid(originNode) as NodeConfigTextObj; + expect(originNode.x - originNode.text.x).toEqual(newNode.x - newNode.text.x); + expect(originNode.y - originNode.text.y).toEqual(newNode.y - newNode.text.y); + expect(originNode.text.value).toEqual(newNode.text.value); + + lf.graphModel.gridSize = 40; + const newNode1 = lf.graphModel.getModelAfterSnapToGrid(originNode) as NodeConfigTextObj; + expect(originNode.x - originNode.text.x).toEqual(newNode1.x - newNode1.text.x); + expect(originNode.y - originNode.text.y).toEqual(newNode1.y - newNode1.text.y); + expect(originNode.text.value).toEqual(newNode1.text.value); + + lf.graphModel.gridSize = 1; + const newNode2 = lf.graphModel.getModelAfterSnapToGrid(originNode) as NodeConfigTextObj; + expect(originNode.x - originNode.text.x).toEqual(newNode2.x - newNode2.text.x); + expect(originNode.y - originNode.text.y).toEqual(newNode2.y - newNode2.text.y); + expect(originNode.text.value).toEqual(newNode2.text.value); + + lf.graphModel.gridSize = 17; + const newNode3 = lf.graphModel.getModelAfterSnapToGrid(originNode) as NodeConfigTextObj; + expect(originNode.x - originNode.text.x).toEqual(newNode3.x - newNode3.text.x); + expect(originNode.y - originNode.text.y).toEqual(newNode3.y - newNode3.text.y); + expect(originNode.text.value).toEqual(newNode3.text.value); + }); +}); diff --git a/packages/core/src/model/GraphModel.ts b/packages/core/src/model/GraphModel.ts index 66e46ee00..741e3da19 100644 --- a/packages/core/src/model/GraphModel.ts +++ b/packages/core/src/model/GraphModel.ts @@ -380,23 +380,7 @@ class GraphModel { return; } if (graphData.nodes) { - this.nodes = map(graphData.nodes, node => { - const Model = this.getModel(node.type); - if (!Model) { - throw new Error(`找不到${node.type}对应的节点。`); - } - const { x: nodeX, y: nodeY } = node; - // 根据 grid 修正节点的 x, y - if (nodeX && nodeY) { - node.x = snapToGrid(nodeX, this.gridSize); - node.y = snapToGrid(nodeY, this.gridSize); - if (typeof node.text === 'object') { - node.text.x -= getGridOffset(nodeX, this.gridSize); - node.text.y -= getGridOffset(nodeY, this.gridSize); - } - } - return new Model(node, this); - }); + this.nodes = map(graphData.nodes, (node: NodeConfig) => this.getModelAfterSnapToGrid(node)); } else { this.nodes = []; } @@ -681,13 +665,7 @@ class GraphModel { if (nodeOriginData.id && this.nodesMap[nodeConfig.id]) { delete nodeOriginData.id; } - const Model = this.getModel(nodeOriginData.type); - if (!Model) { - throw new Error(`找不到${nodeOriginData.type}对应的节点,请确认是否已注册此类型节点。`); - } - nodeOriginData.x = snapToGrid(nodeOriginData.x, this.gridSize); - nodeOriginData.y = snapToGrid(nodeOriginData.y, this.gridSize); - const nodeModel = new Model(nodeOriginData, this); + const nodeModel = this.getModelAfterSnapToGrid(nodeOriginData); this.nodes.push(nodeModel); const nodeData = nodeModel.getData(); const eventData: Record = { data: nodeData }; @@ -697,7 +675,35 @@ class GraphModel { this.eventCenter.emit(eventType, eventData); return nodeModel; } - + /** + * 将node节点位置进行grid修正 + * 同时处理node内文字的偏移量 + * 返回一个位置修正过的复制节点NodeModel + * @param node + */ + getModelAfterSnapToGrid(node: NodeConfig) { + const Model = this.getModel(node.type); + if (!Model) { + throw new Error(`找不到${node.type}对应的节点,请确认是否已注册此类型节点。`); + } + const { x: nodeX, y: nodeY } = node; + // 根据 grid 修正节点的 x, y + if (nodeX && nodeY) { + node.x = snapToGrid(nodeX, this.gridSize); + node.y = snapToGrid(nodeY, this.gridSize); + if (typeof node.text === 'object') { + // 原来的处理是:node.text.x -= getGridOffset(nodeX, this.gridSize); + // 由于snapToGrid()使用了Math.round()四舍五入的做法,因此无法判断需要执行 + // node.text.x = node.text.x + getGridOffset() + // 还是 + // node.text.x = node.text.x - getGridOffset() + // 直接改为node.x - nodeX就可以满足上面的要求 + node.text.x += (node.x - nodeX); + node.text.y += (node.y - nodeY); + } + } + return new Model(node, this); + } /** * 克隆节点 * @param nodeId 节点Id