@logicflow/extension 2.0.17 → 2.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/CHANGELOG.md +14 -0
  3. package/dist/index.min.js +1 -1
  4. package/dist/index.min.js.map +1 -1
  5. package/es/bpmn-elements-adapter/json2xml.js +4 -7
  6. package/es/components/highlight/index.js +19 -3
  7. package/es/dynamic-group/index.js +0 -2
  8. package/es/dynamic-group/model.js +8 -0
  9. package/es/dynamic-group/node.js +1 -0
  10. package/es/style/raw.d.ts +1 -1
  11. package/es/style/raw.js +1 -1
  12. package/es/tools/label/utils.js +1 -1
  13. package/es/tools/proximity-connect/index.js +25 -4
  14. package/es/tools/snapshot/index.d.ts +47 -20
  15. package/es/tools/snapshot/index.js +459 -246
  16. package/jest.config.js +1 -1
  17. package/lib/bpmn-elements-adapter/json2xml.js +4 -7
  18. package/lib/components/highlight/index.js +18 -2
  19. package/lib/dynamic-group/index.js +0 -2
  20. package/lib/dynamic-group/model.js +8 -0
  21. package/lib/dynamic-group/node.js +1 -0
  22. package/lib/style/raw.d.ts +1 -1
  23. package/lib/style/raw.js +1 -1
  24. package/lib/tools/label/utils.js +1 -1
  25. package/lib/tools/proximity-connect/index.js +24 -3
  26. package/lib/tools/snapshot/index.d.ts +47 -20
  27. package/lib/tools/snapshot/index.js +459 -246
  28. package/package.json +3 -3
  29. package/src/bpmn-elements/index.d.ts +18 -18
  30. package/src/bpmn-elements/presets/Flow/flow.d.ts +4 -4
  31. package/src/bpmn-elements-adapter/__tests__/adapter_in.test.js +14 -12
  32. package/src/bpmn-elements-adapter/__tests__/adapter_out.test.js +8 -8
  33. package/src/bpmn-elements-adapter/constant.ts +11 -11
  34. package/src/bpmn-elements-adapter/json2xml.ts +43 -43
  35. package/src/components/highlight/index.ts +30 -5
  36. package/src/dynamic-group/index.ts +0 -3
  37. package/src/dynamic-group/model.ts +10 -0
  38. package/src/dynamic-group/node.ts +1 -0
  39. package/src/materials/curved-edge/__test__/curved-edge.test.ts +19 -16
  40. package/src/style/raw.ts +4 -0
  41. package/src/tools/label/utils.ts +1 -1
  42. package/src/tools/proximity-connect/index.ts +30 -3
  43. package/src/tools/snapshot/index.ts +325 -152
  44. package/stats.html +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logicflow/extension",
3
- "version": "2.0.17",
3
+ "version": "2.0.19",
4
4
  "description": "LogicFlow Extensions",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
@@ -20,7 +20,7 @@
20
20
  "author": "Logicflow-Team",
21
21
  "license": "Apache-2.0",
22
22
  "peerDependencies": {
23
- "@logicflow/core": "2.0.13"
23
+ "@logicflow/core": "2.0.14"
24
24
  },
25
25
  "dependencies": {
26
26
  "@antv/hierarchy": "^0.6.11",
@@ -31,7 +31,7 @@
31
31
  "preact": "^10.17.1",
32
32
  "rangy": "^1.3.1",
33
33
  "vanilla-picker": "^2.12.3",
34
- "@logicflow/core": "2.0.13"
34
+ "@logicflow/core": "2.0.14"
35
35
  },
36
36
  "devDependencies": {
37
37
  "less": "^4.1.1",
@@ -1,26 +1,26 @@
1
1
  type DefinitionConfigType = {
2
- nodes: string[];
3
- definition: EventDefinitionType[] | TaskDefinitionType[];
4
- };
2
+ nodes: string[]
3
+ definition: EventDefinitionType[] | TaskDefinitionType[]
4
+ }
5
5
 
6
6
  type DefinitionPropertiesType = {
7
- definitionType: string;
8
- timerType?: TimerType;
9
- timerValue?: string;
10
- [key: string]: any;
11
- };
7
+ definitionType: string
8
+ timerType?: TimerType
9
+ timerValue?: string
10
+ [key: string]: any
11
+ }
12
12
 
13
13
  type EventDefinitionType = {
14
- type: string;
15
- icon: string | Object;
16
- toJSON: Function;
17
- properties: DefinitionPropertiesType;
18
- [key: string]: any;
19
- };
14
+ type: string
15
+ icon: string | Object
16
+ toJSON: Function
17
+ properties: DefinitionPropertiesType
18
+ [key: string]: any
19
+ }
20
20
 
21
21
  type TaskDefinitionType = {
22
- type: string;
23
- [key: string]: any;
24
- };
22
+ type: string
23
+ [key: string]: any
24
+ }
25
25
 
26
- type TimerType = 'timerCycle' | 'timerDate' | 'timerDuration';
26
+ type TimerType = 'timerCycle' | 'timerDate' | 'timerDuration'
@@ -1,6 +1,6 @@
1
1
  export type BBoxType = {
2
- minX: number;
3
- minY: number;
4
- maxX: number;
5
- maxY: number;
2
+ minX: number
3
+ minY: number
4
+ maxX: number
5
+ maxY: number
6
6
  }
@@ -3,7 +3,7 @@
3
3
  /* eslint-disable no-new */
4
4
  /* eslint-disable no-undef */
5
5
  /* eslint-disable no-tabs */
6
- import { BPMNAdapter } from '..';
6
+ import { BPMNAdapter } from '..'
7
7
 
8
8
  describe('Test BPMNAdapter: import xml', () => {
9
9
  const graphData = {
@@ -349,7 +349,7 @@ describe('Test BPMNAdapter: import xml', () => {
349
349
  ],
350
350
  },
351
351
  ],
352
- };
352
+ }
353
353
  const xml = ` <bpmn:definitions id="Definitions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="http://logic-flow.org" exporter="logicflow" exporterVersion="1.2.10">
354
354
  <bpmn:process isExecutable="true" id="Process">
355
355
  <bpmn:startEvent id="Event_0rqndvp" name="开始" />
@@ -511,16 +511,18 @@ describe('Test BPMNAdapter: import xml', () => {
511
511
  </bpmndi:BPMNShape>
512
512
  </bpmndi:BPMNPlane>
513
513
  </bpmndi:BPMNDiagram>
514
- </bpmn:definitions>`;
515
- const lf = {};
516
- const adapter = new BPMNAdapter({ lf });
514
+ </bpmn:definitions>`
515
+ const lf = {}
516
+ const adapter = new BPMNAdapter({ lf })
517
517
 
518
518
  // 导入时会处理内部会出boundaryEvents(配合Bpmn节点插件中的task、subProcess使用)但是在这里不需要,所以需要extraProps来过滤掉它
519
519
  it('should convert bpmn to graph data', () => {
520
- expect(adapter.adapterXmlIn(xml, {
521
- excludeFields: {
522
- in: ['properties.boundaryEvents'],
523
- },
524
- })).toEqual(graphData);
525
- });
526
- });
520
+ expect(
521
+ adapter.adapterXmlIn(xml, {
522
+ excludeFields: {
523
+ in: ['properties.boundaryEvents'],
524
+ },
525
+ }),
526
+ ).toEqual(graphData)
527
+ })
528
+ })
@@ -3,7 +3,7 @@
3
3
  /* eslint-disable no-new */
4
4
  /* eslint-disable no-undef */
5
5
  /* eslint-disable no-tabs */
6
- import { BPMNAdapter } from '..';
6
+ import { BPMNAdapter } from '..'
7
7
 
8
8
  describe('Test BPMNAdapter: export xml', () => {
9
9
  const graphData = {
@@ -397,7 +397,7 @@ describe('Test BPMNAdapter: export xml', () => {
397
397
  ],
398
398
  },
399
399
  ],
400
- };
400
+ }
401
401
  const xml = ` <bpmn:definitions id="Definitions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="http://logic-flow.org" exporter="logicflow" exporterVersion="1.2.10">
402
402
  <bpmn:process isExecutable="true" id="Process">
403
403
  <bpmn:startEvent id="Event_0rqndvp" name="开始" />
@@ -559,11 +559,11 @@ describe('Test BPMNAdapter: export xml', () => {
559
559
  </bpmndi:BPMNShape>
560
560
  </bpmndi:BPMNPlane>
561
561
  </bpmndi:BPMNDiagram>
562
- </bpmn:definitions>`;
563
- const lf = {};
564
- const adapter = new BPMNAdapter({ lf });
562
+ </bpmn:definitions>`
563
+ const lf = {}
564
+ const adapter = new BPMNAdapter({ lf })
565
565
 
566
566
  it('should transform logic-flow graph data to bpmn xml', () => {
567
- expect(adapter.adapterXmlOut(graphData)).toEqual(xml);
568
- });
569
- });
567
+ expect(adapter.adapterXmlOut(graphData)).toEqual(xml)
568
+ })
569
+ })
@@ -1,52 +1,52 @@
1
1
  export const StartEventConfig = {
2
2
  width: 40,
3
3
  height: 40,
4
- };
4
+ }
5
5
 
6
6
  export const EndEventConfig = {
7
7
  width: 40,
8
8
  height: 40,
9
- };
9
+ }
10
10
 
11
11
  export const BoundaryEventConfig = {
12
12
  width: 100,
13
13
  height: 80,
14
- };
14
+ }
15
15
 
16
16
  export const IntermediateEventConfig = {
17
17
  width: 100,
18
18
  height: 80,
19
- };
19
+ }
20
20
 
21
21
  export const ParallelGatewayConfig = {
22
22
  width: 100,
23
23
  height: 80,
24
- };
24
+ }
25
25
 
26
26
  export const InclusiveGatewayConfig = {
27
27
  width: 100,
28
28
  height: 80,
29
- };
29
+ }
30
30
 
31
31
  export const ExclusiveGatewayConfig = {
32
32
  width: 100,
33
33
  height: 80,
34
- };
34
+ }
35
35
 
36
36
  export const ServiceTaskConfig = {
37
37
  width: 100,
38
38
  height: 80,
39
- };
39
+ }
40
40
 
41
41
  export const UserTaskConfig = {
42
42
  width: 100,
43
43
  height: 80,
44
- };
44
+ }
45
45
 
46
46
  export const SubProcessConfig = {
47
47
  width: 100,
48
48
  height: 80,
49
- };
49
+ }
50
50
 
51
51
  export const theme = {
52
52
  rect: {
@@ -73,4 +73,4 @@ export const theme = {
73
73
  radius: 3,
74
74
  },
75
75
  },
76
- };
76
+ }
@@ -1,91 +1,91 @@
1
1
  /* eslint-disable guard-for-in */
2
2
  function type(obj: any) {
3
- return Object.prototype.toString.call(obj);
3
+ return Object.prototype.toString.call(obj)
4
4
  }
5
5
 
6
6
  function addSpace(depth: number) {
7
- return ' '.repeat(depth);
7
+ return ' '.repeat(depth)
8
8
  }
9
9
 
10
10
  function handleAttributes(obj: any): any {
11
11
  if (type(obj) === '[object Object]') {
12
12
  return Object.keys(obj).reduce((tmp: any, key: string) => {
13
- let tmpKey = key;
13
+ let tmpKey = key
14
14
  if (key.charAt(0) === '-') {
15
- tmpKey = key.substring(1);
15
+ tmpKey = key.substring(1)
16
16
  }
17
- tmp[tmpKey] = handleAttributes(obj[key]);
18
- return tmp;
19
- }, {});
20
- } if (Array.isArray(obj)) {
21
- return obj.map((item) => handleAttributes(item));
17
+ tmp[tmpKey] = handleAttributes(obj[key])
18
+ return tmp
19
+ }, {})
22
20
  }
23
- return obj;
21
+ if (Array.isArray(obj)) {
22
+ return obj.map((item) => handleAttributes(item))
23
+ }
24
+ return obj
24
25
  }
25
26
 
26
27
  function getAttributes(obj: any) {
27
- let tmp = obj;
28
+ let tmp = obj
28
29
  try {
29
30
  if (typeof tmp !== 'string') {
30
- tmp = JSON.parse(obj);
31
+ tmp = JSON.parse(obj)
31
32
  }
32
33
  } catch (error) {
33
- tmp = JSON.stringify(handleAttributes(obj)).replace(/"/g, '\'');
34
+ tmp = JSON.stringify(handleAttributes(obj)).replace(/"/g, "'")
34
35
  }
35
- return tmp;
36
+ return tmp
36
37
  }
37
38
 
38
- const tn = '\t\n';
39
+ const tn = '\t\n'
39
40
 
40
41
  // @see issue https://github.com/didi/LogicFlow/issues/718, refactoring of function toXml
41
42
  function toXml(obj: any, name: string, depth: number) {
42
- const frontSpace = addSpace(depth);
43
- let str = '';
44
- const prefix = tn + frontSpace;
45
- if (name === '-json') return '';
43
+ const frontSpace = addSpace(depth)
44
+ let str = ''
45
+ const prefix = tn + frontSpace
46
+ if (name === '-json') return ''
46
47
  if (name === '#text') {
47
- return prefix + obj;
48
- } if (name === '#cdata-section') {
49
- return `${prefix}<![CDATA[${obj}]]>`;
50
- } if (name === '#comment') {
51
- return `${prefix}<!--${obj}-->`;
48
+ return prefix + obj
49
+ }
50
+ if (name === '#cdata-section') {
51
+ return `${prefix}<![CDATA[${obj}]]>`
52
+ }
53
+ if (name === '#comment') {
54
+ return `${prefix}<!--${obj}-->`
52
55
  }
53
56
  if (`${name}`.charAt(0) === '-') {
54
- return ` ${name.substring(1)}="${getAttributes(obj)}"`;
57
+ return ` ${name.substring(1)}="${getAttributes(obj)}"`
55
58
  }
56
59
  if (Array.isArray(obj)) {
57
- str += obj.map((item) => toXml(item, name, depth + 1)).join('');
60
+ str += obj.map((item) => toXml(item, name, depth + 1)).join('')
58
61
  } else if (type(obj) === '[object Object]') {
59
- const keys = Object.keys(obj);
60
- let attributes = '';
61
- let children = obj['-json']
62
- ? tn + addSpace(depth + 1) + obj['-json']
63
- : '';
62
+ const keys = Object.keys(obj)
63
+ let attributes = ''
64
+ let children = obj['-json'] ? tn + addSpace(depth + 1) + obj['-json'] : ''
64
65
 
65
- str += `${depth === 0 ? '' : prefix}<${name}`;
66
+ str += `${depth === 0 ? '' : prefix}<${name}`
66
67
 
67
68
  keys.forEach((k) => {
68
69
  k.charAt(0) === '-'
69
70
  ? (attributes += toXml(obj[k], k, depth + 1))
70
- : (children += toXml(obj[k], k, depth + 1));
71
- });
71
+ : (children += toXml(obj[k], k, depth + 1))
72
+ })
72
73
 
73
- str
74
- += attributes
75
- + (children !== '' ? `>${children}${prefix}</${name}>` : ' />');
74
+ str +=
75
+ attributes + (children !== '' ? `>${children}${prefix}</${name}>` : ' />')
76
76
  } else {
77
- str += `${prefix}<${name}>${obj.toString()}</${name}>`;
77
+ str += `${prefix}<${name}>${obj.toString()}</${name}>`
78
78
  }
79
79
 
80
- return str;
80
+ return str
81
81
  }
82
82
 
83
83
  function lfJson2Xml(obj: any) {
84
- let xmlStr = '';
84
+ let xmlStr = ''
85
85
  for (const key in obj) {
86
- xmlStr += toXml(obj[key], key, 0);
86
+ xmlStr += toXml(obj[key], key, 0)
87
87
  }
88
- return xmlStr;
88
+ return xmlStr
89
89
  }
90
90
 
91
- export { lfJson2Xml, handleAttributes };
91
+ export { lfJson2Xml, handleAttributes }
@@ -1,5 +1,5 @@
1
- import LogicFlow, { BaseNodeModel } from '@logicflow/core'
2
- import { concat } from 'lodash-es'
1
+ import LogicFlow, { BaseEdgeModel, BaseNodeModel } from '@logicflow/core'
2
+ import { uniqBy, concat } from 'lodash-es'
3
3
 
4
4
  // 后续并入FlowPath
5
5
  const getPath = (id: string, lf: LogicFlow) => {
@@ -99,7 +99,7 @@ export class Highlight {
99
99
  this.enable = enable
100
100
  }
101
101
 
102
- setMode(mode: IMode) {
102
+ public setMode(mode: IMode) {
103
103
  this.mode = mode
104
104
  }
105
105
 
@@ -119,11 +119,14 @@ export class Highlight {
119
119
  model.sourceNode.updateStyles(this.tempStyles[model.sourceNode.id])
120
120
  model.targetNode.updateStyles(this.tempStyles[model.targetNode.id])
121
121
  }
122
+ this.lf.emit('highlight:single', {
123
+ data: model,
124
+ })
122
125
  }
123
126
 
124
127
  private highlightNeighbours(id: string) {
125
128
  const model = this.lf.getModelById(id)
126
-
129
+ let relateElements: (BaseNodeModel | BaseEdgeModel)[] = []
127
130
  if (model?.BaseType === 'node') {
128
131
  // 高亮节点
129
132
  model.updateStyles(this.tempStyles[id])
@@ -135,19 +138,41 @@ export class Highlight {
135
138
  concat(incomingEdges, outgoingEdges).forEach((edge) => {
136
139
  edge.updateStyles(this.tempStyles[edge.id])
137
140
  })
141
+ relateElements = uniqBy(
142
+ concat(
143
+ relateElements,
144
+ incomingNodes,
145
+ outgoingNodes,
146
+ incomingEdges,
147
+ outgoingEdges,
148
+ ),
149
+ 'id',
150
+ )
138
151
  } else if (model?.BaseType === 'edge') {
139
152
  // 高亮边及对应的节点
140
153
  model.updateStyles(this.tempStyles[id])
141
154
  model.sourceNode.updateStyles(this.tempStyles[model.sourceNode.id])
142
155
  model.targetNode.updateStyles(this.tempStyles[model.targetNode.id])
156
+ relateElements = [model.sourceNode, model.targetNode]
143
157
  }
158
+ this.lf.emit('highlight:neighbours', {
159
+ data: model,
160
+ relateElements,
161
+ })
144
162
  }
145
163
 
146
164
  private highlightPath(id: string) {
147
165
  const path = getPath(id, this.lf)
166
+ const relateElements: any[] = []
148
167
  path.forEach((_id) => {
168
+ const elementModel = this.lf.getModelById(_id)
149
169
  // 高亮路径上所有的边和节点
150
- this.lf.getModelById(_id)?.updateStyles(this.tempStyles[_id])
170
+ elementModel?.updateStyles(this.tempStyles[_id])
171
+ relateElements.push(elementModel)
172
+ })
173
+ this.lf.emit('highlight:path', {
174
+ data: this.lf.getModelById(id),
175
+ relateElements,
151
176
  })
152
177
  }
153
178
 
@@ -513,9 +513,6 @@ export class DynamicGroup {
513
513
  }
514
514
  })
515
515
 
516
- // TODO: 确认,递归的方式,是否将所有嵌套的边数据都有返回
517
- console.log('allRelatedEdges -->>', allRelatedEdges)
518
-
519
516
  // 1. 判断每一条边的开始节点、目标节点是否在 Group 中
520
517
  const edgesInnerGroup = filter(allRelatedEdges, (edge) => {
521
518
  return (
@@ -134,6 +134,7 @@ export class DynamicGroupNodeModel extends RectNodeModel<IGroupNodeProperties> {
134
134
  this.children = children ? new Set(children) : new Set()
135
135
  this.zIndex = zIndex ?? DEFAULT_BOTTOM_Z_INDEX
136
136
  this.isCollapsed = isCollapsed ?? false
137
+ this.setProperties({ isCollapsed: isCollapsed ?? false })
137
138
 
138
139
  const expandWidth = width ?? DEFAULT_GROUP_EXPAND_WIDTH
139
140
  const expandHeight = height ?? DEFAULT_GROUP_EXPAND_HEIGHT
@@ -249,8 +250,17 @@ export class DynamicGroupNodeModel extends RectNodeModel<IGroupNodeProperties> {
249
250
  * @param collapse {boolean} true -> 折叠;false -> 展开
250
251
  */
251
252
  toggleCollapse(collapse?: boolean) {
253
+ const { graphModel } = this
252
254
  const nextCollapseState = !!collapse
255
+ // DONE: 通过 setProperty 设置 isCollapsed 的值 -> 否则无法触发 node:properties-changed 事件
253
256
  this.isCollapsed = nextCollapseState
257
+ this.setProperties({ isCollapsed: nextCollapseState })
258
+
259
+ graphModel.eventCenter.emit('dynamicGroup:collapse', {
260
+ collapse: nextCollapseState,
261
+ nodeModel: this,
262
+ })
263
+
254
264
  // step 1
255
265
  if (nextCollapseState) {
256
266
  this.collapse()
@@ -268,6 +268,7 @@ export class DynamicGroupNode<
268
268
  x: sx,
269
269
  y: sy,
270
270
  onClick: () => {
271
+ // DONE: 抛出折叠或展开事件 -> 在 toggleCollapse 方法中抛出
271
272
  model.toggleCollapse(!model.isCollapsed)
272
273
  },
273
274
  }),
@@ -1,43 +1,46 @@
1
- import { getCurvedEdgePath } from '../index';
1
+ import { getCurvedEdgePath } from '../index'
2
2
 
3
3
  describe('test curved edge ', () => {
4
4
  test('path calculation', () => {
5
- const radius = 5;
5
+ const radius = 5
6
6
 
7
- const points1 = '460,150 670,150';
8
- const path1 = 'M460 150 L 670 150';
7
+ const points1 = '460,150 670,150'
8
+ const path1 = 'M460 150 L 670 150'
9
9
  expect(
10
10
  getCurvedEdgePath(
11
11
  points1.split(' ').map((p) => p.split(',').map((a) => +a)),
12
12
  radius,
13
13
  ),
14
- ).toBe(path1);
14
+ ).toBe(path1)
15
15
 
16
- const points2 = '510,250 540,250 540,175 490,175 490,100 520,100';
17
- const path2 = 'M510 250L 510 250L 535 250 Q 540 250 540 245L 540 245L 540 180 Q 540 175 535 175L 535 175L 495 175 Q 490 175 490 170L 490 170L 490 105 Q 490 100 495 100L 520 100';
16
+ const points2 = '510,250 540,250 540,175 490,175 490,100 520,100'
17
+ const path2 =
18
+ 'M510 250L 510 250L 535 250 Q 540 250 540 245L 540 245L 540 180 Q 540 175 535 175L 535 175L 495 175 Q 490 175 490 170L 490 170L 490 105 Q 490 100 495 100L 520 100'
18
19
  expect(
19
20
  getCurvedEdgePath(
20
21
  points2.split(' ').map((p) => p.split(',').map((a) => +a)),
21
22
  radius,
22
23
  ),
23
- ).toBe(path2);
24
+ ).toBe(path2)
24
25
 
25
- const points3 = '690,120 720,120 720,50 560,50 560,260 690,260';
26
- const path3 = 'M690 120L 690 120L 715 120 Q 720 120 720 115L 720 115L 720 55 Q 720 50 715 50L 715 50L 565 50 Q 560 50 560 55L 560 55L 560 255 Q 560 260 565 260L 690 260';
26
+ const points3 = '690,120 720,120 720,50 560,50 560,260 690,260'
27
+ const path3 =
28
+ 'M690 120L 690 120L 715 120 Q 720 120 720 115L 720 115L 720 55 Q 720 50 715 50L 715 50L 565 50 Q 560 50 560 55L 560 55L 560 255 Q 560 260 565 260L 690 260'
27
29
  expect(
28
30
  getCurvedEdgePath(
29
31
  points3.split(' ').map((p) => p.split(',').map((a) => +a)),
30
32
  radius,
31
33
  ),
32
- ).toBe(path3);
34
+ ).toBe(path3)
33
35
 
34
- const point4 = '690,180 690,210 660,210 660,190 630,190 630,220';
35
- const path4 = 'M690 180L 690 180L 690 205 Q 690 210 685 210L 685 210L 665 210 Q 660 210 660 205L 660 205L 660 195 Q 660 190 655 190L 655 190L 635 190 Q 630 190 630 195L 630 220';
36
+ const point4 = '690,180 690,210 660,210 660,190 630,190 630,220'
37
+ const path4 =
38
+ 'M690 180L 690 180L 690 205 Q 690 210 685 210L 685 210L 665 210 Q 660 210 660 205L 660 205L 660 195 Q 660 190 655 190L 655 190L 635 190 Q 630 190 630 195L 630 220'
36
39
  expect(
37
40
  getCurvedEdgePath(
38
41
  point4.split(' ').map((p) => p.split(',').map((a) => +a)),
39
42
  radius,
40
43
  ),
41
- ).toBe(path4);
42
- });
43
- });
44
+ ).toBe(path4)
45
+ })
46
+ })
package/src/style/raw.ts CHANGED
@@ -193,6 +193,10 @@ export const content = `@import url('medium-editor/dist/css/medium-editor.min.cs
193
193
  background: #eaedf2;
194
194
  border: 1px solid #93a3b4;
195
195
  }
196
+ .lf-mini-map .lf-graph {
197
+ width: 100% !important;
198
+ height: 100% !important;
199
+ }
196
200
  .lf-mini-map-graph {
197
201
  position: relative;
198
202
  overflow: hidden;
@@ -350,7 +350,7 @@ export const calcLabelPositionOnPolyline = (
350
350
  y: minY + (maxY - minY) * yDeltaPercent,
351
351
  }
352
352
  return isPointOnEdge
353
- ? getNewPointAtDistance(points, ratio) ?? point // 函数什么意思
353
+ ? (getNewPointAtDistance(points, ratio) ?? point) // 函数什么意思
354
354
  : positByPercent
355
355
  }
356
356
  // 如果文本在凸包的上方或者下方
@@ -3,6 +3,7 @@ import LogicFlow, {
3
3
  twoPointDistance,
4
4
  BaseNodeModel,
5
5
  BaseEdgeModel,
6
+ isInNode,
6
7
  } from '@logicflow/core'
7
8
  import { assign, isEmpty, isEqual, isNil, isFinite, reduce } from 'lodash-es'
8
9
 
@@ -78,10 +79,37 @@ export class ProximityConnect {
78
79
  },
79
80
  )
80
81
  // 节点、锚点拖拽结束事件
81
- this.lf.graphModel.eventCenter.on('node:drop,anchor:dragend', () => {
82
+ this.lf.graphModel.eventCenter.on('node:drop', () => {
82
83
  if (!this.enable) return
83
84
  this.handleDrop()
84
85
  })
86
+ // 锚点拖拽需要单独判断一下当前拖拽终点是否在某个锚点上,如果是,就不触发插件的连线,以免出现创建了两条连线的问题,表现见 issue 2140
87
+ this.lf.graphModel.eventCenter.on('anchor:dragend', ({ e, edgeModel }) => {
88
+ if (!this.enable) return
89
+ const {
90
+ canvasOverlayPosition: { x: eventX, y: eventY },
91
+ } = this.lf.graphModel.getPointByClient({
92
+ x: e.clientX,
93
+ y: e.clientY,
94
+ })
95
+
96
+ if (edgeModel && this.virtualEdge) {
97
+ const { id: virtualEdgeId } = this.virtualEdge as BaseEdgeModel
98
+ const { targetNodeId } = edgeModel as BaseEdgeModel
99
+ const targetNodeModel =
100
+ this.lf.graphModel.getNodeModelById(targetNodeId)
101
+ if (
102
+ targetNodeModel &&
103
+ isInNode({ x: eventX, y: eventY }, targetNodeModel)
104
+ ) {
105
+ // 如果当前拖拽点在锚点上,就不触发插件的连线
106
+ this.lf.deleteEdge(virtualEdgeId)
107
+ return
108
+ }
109
+ }
110
+
111
+ this.handleDrop()
112
+ })
85
113
  }
86
114
 
87
115
  // 节点拖拽动作
@@ -346,6 +374,7 @@ export class ProximityConnect {
346
374
  endPoint,
347
375
  pointsList,
348
376
  } = this.virtualEdge
377
+ this.lf.deleteEdge(this.virtualEdge.id)
349
378
  this.lf.addEdge({
350
379
  type,
351
380
  sourceNodeId,
@@ -356,7 +385,6 @@ export class ProximityConnect {
356
385
  endPoint,
357
386
  pointsList,
358
387
  })
359
- this.lf.deleteEdge(this.virtualEdge.id)
360
388
  }
361
389
 
362
390
  // 设置虚拟边样式
@@ -369,7 +397,6 @@ export class ProximityConnect {
369
397
 
370
398
  // 设置连线阈值
371
399
  public setThresholdDistance(distance: number) {
372
- console.log('distance', distance)
373
400
  if (!isFinite(distance)) return
374
401
  this.thresholdDistance = distance
375
402
  }