@logicflow/extension 2.2.0 → 2.2.1

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 (201) hide show
  1. package/README.md +16 -0
  2. package/dist/index.css +1 -1
  3. package/dist/index.min.js +1 -1
  4. package/dist/index.min.js.map +1 -1
  5. package/es/NodeResize/node/RectResize.d.ts +0 -6
  6. package/es/NodeResize/node/RectResize.js +2 -11
  7. package/es/bpmn-elements-adapter/json2xml.d.ts +2 -1
  8. package/es/bpmn-elements-adapter/json2xml.js +18 -4
  9. package/es/bpmn-elements-adapter/xml2json.js +2 -7
  10. package/es/components/control/index.d.ts +1 -0
  11. package/es/components/control/index.js +24 -11
  12. package/es/components/mini-map/index.js +1 -1
  13. package/es/dynamic-group/model.d.ts +2 -1
  14. package/es/dynamic-group/model.js +28 -11
  15. package/es/dynamic-group/node.js +1 -0
  16. package/es/index.css +1 -1
  17. package/es/index.d.ts +1 -0
  18. package/es/index.js +2 -0
  19. package/es/insert-node-in-polyline/index.js +11 -35
  20. package/es/materials/curved-edge/index.js +49 -21
  21. package/es/materials/group/GroupNode.d.ts +0 -6
  22. package/es/materials/group/GroupNode.js +1 -6
  23. package/es/pool/LaneModel.d.ts +90 -0
  24. package/es/pool/LaneModel.js +252 -0
  25. package/es/pool/LaneView.d.ts +40 -0
  26. package/es/pool/LaneView.js +202 -0
  27. package/es/pool/PoolModel.d.ts +120 -0
  28. package/es/pool/PoolModel.js +586 -0
  29. package/es/pool/PoolView.d.ts +17 -0
  30. package/es/pool/PoolView.js +76 -0
  31. package/es/pool/constant.d.ts +15 -0
  32. package/es/pool/constant.js +17 -0
  33. package/es/pool/index.d.ts +89 -0
  34. package/es/pool/index.js +524 -0
  35. package/es/pool/utils.d.ts +19 -0
  36. package/es/pool/utils.js +33 -0
  37. package/es/style/index.css +1 -1
  38. package/es/style/raw.d.ts +1 -1
  39. package/es/style/raw.js +1 -1
  40. package/es/tools/label/LabelOverlay.js +3 -3
  41. package/es/tools/label/mediumEditor.d.ts +1 -1
  42. package/es/tools/label/mediumEditor.js +89 -52
  43. package/es/tools/snapshot/index.d.ts +7 -3
  44. package/es/tools/snapshot/index.js +72 -77
  45. package/lib/NodeResize/node/RectResize.d.ts +0 -6
  46. package/lib/NodeResize/node/RectResize.js +1 -10
  47. package/lib/bpmn-elements-adapter/json2xml.d.ts +2 -1
  48. package/lib/bpmn-elements-adapter/json2xml.js +19 -4
  49. package/lib/bpmn-elements-adapter/xml2json.js +2 -7
  50. package/lib/components/control/index.d.ts +1 -0
  51. package/lib/components/control/index.js +24 -11
  52. package/lib/components/mini-map/index.js +1 -1
  53. package/lib/dynamic-group/model.d.ts +2 -1
  54. package/lib/dynamic-group/model.js +28 -11
  55. package/lib/dynamic-group/node.js +1 -0
  56. package/lib/index.css +1 -1
  57. package/lib/index.d.ts +1 -0
  58. package/lib/index.js +2 -0
  59. package/lib/insert-node-in-polyline/index.js +10 -34
  60. package/lib/materials/curved-edge/index.js +49 -21
  61. package/lib/materials/group/GroupNode.d.ts +0 -6
  62. package/lib/materials/group/GroupNode.js +1 -6
  63. package/lib/pool/LaneModel.d.ts +90 -0
  64. package/lib/pool/LaneModel.js +255 -0
  65. package/lib/pool/LaneView.d.ts +40 -0
  66. package/lib/pool/LaneView.js +205 -0
  67. package/lib/pool/PoolModel.d.ts +120 -0
  68. package/lib/pool/PoolModel.js +589 -0
  69. package/lib/pool/PoolView.d.ts +17 -0
  70. package/lib/pool/PoolView.js +79 -0
  71. package/lib/pool/constant.d.ts +15 -0
  72. package/lib/pool/constant.js +20 -0
  73. package/lib/pool/index.d.ts +89 -0
  74. package/lib/pool/index.js +527 -0
  75. package/lib/pool/utils.d.ts +19 -0
  76. package/lib/pool/utils.js +38 -0
  77. package/lib/style/index.css +1 -1
  78. package/lib/style/raw.d.ts +1 -1
  79. package/lib/style/raw.js +1 -1
  80. package/lib/tools/label/LabelOverlay.js +2 -2
  81. package/lib/tools/label/mediumEditor.d.ts +1 -1
  82. package/lib/tools/label/mediumEditor.js +91 -53
  83. package/lib/tools/snapshot/index.d.ts +7 -3
  84. package/lib/tools/snapshot/index.js +72 -77
  85. package/package.json +10 -7
  86. package/.turbo/turbo-build.log +0 -38
  87. package/CHANGELOG.md +0 -1766
  88. package/__test__/bpmn-adapter.test.js +0 -227
  89. package/es/materials/curved-edge/__test__/curved-edge.test.d.ts +0 -1
  90. package/es/materials/curved-edge/__test__/curved-edge.test.js +0 -18
  91. package/jest.config.js +0 -198
  92. package/lib/materials/curved-edge/__test__/curved-edge.test.d.ts +0 -1
  93. package/lib/materials/curved-edge/__test__/curved-edge.test.js +0 -20
  94. package/rollup.config.js +0 -52
  95. package/src/NodeResize/BasicShape/Ellipse.tsx +0 -22
  96. package/src/NodeResize/BasicShape/Polygon.tsx +0 -24
  97. package/src/NodeResize/BasicShape/Rect.tsx +0 -44
  98. package/src/NodeResize/control/Control.tsx +0 -537
  99. package/src/NodeResize/control/ControlGroup.tsx +0 -76
  100. package/src/NodeResize/control/Util.ts +0 -206
  101. package/src/NodeResize/index.ts +0 -26
  102. package/src/NodeResize/node/DiamondResize.tsx +0 -149
  103. package/src/NodeResize/node/EllipseResize.tsx +0 -140
  104. package/src/NodeResize/node/HtmlResize.tsx +0 -125
  105. package/src/NodeResize/node/RectResize.tsx +0 -146
  106. package/src/NodeResize/node/index.ts +0 -4
  107. package/src/bpmn/constant.ts +0 -56
  108. package/src/bpmn/events/EndEvent.ts +0 -73
  109. package/src/bpmn/events/StartEvent.ts +0 -52
  110. package/src/bpmn/events/index.ts +0 -2
  111. package/src/bpmn/flow/SequenceFlow.ts +0 -25
  112. package/src/bpmn/flow/index.ts +0 -1
  113. package/src/bpmn/gateways/ExclusiveGateway.ts +0 -71
  114. package/src/bpmn/gateways/index.ts +0 -1
  115. package/src/bpmn/getBpmnId.ts +0 -31
  116. package/src/bpmn/index.ts +0 -60
  117. package/src/bpmn/tasks/ServiceTask.ts +0 -63
  118. package/src/bpmn/tasks/UserTask.ts +0 -64
  119. package/src/bpmn/tasks/index.ts +0 -2
  120. package/src/bpmn-adapter/bpmnIds.ts +0 -31
  121. package/src/bpmn-adapter/index.ts +0 -835
  122. package/src/bpmn-adapter/json2xml.ts +0 -127
  123. package/src/bpmn-adapter/xml2json.ts +0 -544
  124. package/src/bpmn-elements/README.md +0 -223
  125. package/src/bpmn-elements/__tests__/definition.test.js +0 -72
  126. package/src/bpmn-elements/index.d.ts +0 -26
  127. package/src/bpmn-elements/index.ts +0 -107
  128. package/src/bpmn-elements/presets/Event/EndEventFactory.ts +0 -114
  129. package/src/bpmn-elements/presets/Event/IntermediateCatchEvent.ts +0 -108
  130. package/src/bpmn-elements/presets/Event/IntermediateThrowEvent.ts +0 -109
  131. package/src/bpmn-elements/presets/Event/StartEventFactory.ts +0 -114
  132. package/src/bpmn-elements/presets/Event/boundaryEventFactory.ts +0 -117
  133. package/src/bpmn-elements/presets/Event/index.ts +0 -14
  134. package/src/bpmn-elements/presets/Flow/flow.d.ts +0 -6
  135. package/src/bpmn-elements/presets/Flow/index.ts +0 -8
  136. package/src/bpmn-elements/presets/Flow/manhattan.ts +0 -691
  137. package/src/bpmn-elements/presets/Flow/sequenceFlow.ts +0 -65
  138. package/src/bpmn-elements/presets/Gateway/gateway.ts +0 -107
  139. package/src/bpmn-elements/presets/Gateway/index.ts +0 -23
  140. package/src/bpmn-elements/presets/Pool/Lane.ts +0 -211
  141. package/src/bpmn-elements/presets/Pool/Pool.ts +0 -284
  142. package/src/bpmn-elements/presets/Pool/index.ts +0 -89
  143. package/src/bpmn-elements/presets/Task/index.ts +0 -122
  144. package/src/bpmn-elements/presets/Task/subProcess.ts +0 -189
  145. package/src/bpmn-elements/presets/Task/task.ts +0 -193
  146. package/src/bpmn-elements/presets/icons.ts +0 -155
  147. package/src/bpmn-elements/utils.ts +0 -52
  148. package/src/bpmn-elements-adapter/README.md +0 -293
  149. package/src/bpmn-elements-adapter/__tests__/adapter_in.test.js +0 -528
  150. package/src/bpmn-elements-adapter/__tests__/adapter_out.test.js +0 -569
  151. package/src/bpmn-elements-adapter/constant.ts +0 -76
  152. package/src/bpmn-elements-adapter/index.ts +0 -1134
  153. package/src/bpmn-elements-adapter/json2xml.ts +0 -91
  154. package/src/bpmn-elements-adapter/xml2json.ts +0 -548
  155. package/src/components/context-menu/index.ts +0 -253
  156. package/src/components/control/index.ts +0 -141
  157. package/src/components/dnd-panel/index.ts +0 -137
  158. package/src/components/highlight/index.ts +0 -227
  159. package/src/components/menu/index.ts +0 -748
  160. package/src/components/mini-map/index.ts +0 -686
  161. package/src/components/selection-select/index.ts +0 -387
  162. package/src/dynamic-group/index.ts +0 -775
  163. package/src/dynamic-group/model.ts +0 -562
  164. package/src/dynamic-group/node.ts +0 -288
  165. package/src/dynamic-group/utils.ts +0 -46
  166. package/src/index.less +0 -1
  167. package/src/index.ts +0 -45
  168. package/src/insert-node-in-polyline/edge.ts +0 -175
  169. package/src/insert-node-in-polyline/index.ts +0 -187
  170. package/src/materials/curved-edge/__test__/curved-edge.test.ts +0 -46
  171. package/src/materials/curved-edge/index.ts +0 -185
  172. package/src/materials/group/GroupNode.ts +0 -442
  173. package/src/materials/group/index.ts +0 -542
  174. package/src/materials/node-selection/index.ts +0 -380
  175. package/src/mindmap/fakerRoot.ts +0 -19
  176. package/src/mindmap/index.ts +0 -328
  177. package/src/mindmap/markContent.ts +0 -81
  178. package/src/mindmap/markContentOption.ts +0 -81
  179. package/src/mindmap/markEntity.ts +0 -82
  180. package/src/mindmap/markRoot.ts +0 -83
  181. package/src/mindmap/theme.ts +0 -11
  182. package/src/rect-label-node/RectLabelNodeView.ts +0 -33
  183. package/src/rect-label-node/index.ts +0 -15
  184. package/src/style/index.less +0 -342
  185. package/src/style/raw.ts +0 -295
  186. package/src/tools/auto-layout/index.ts +0 -282
  187. package/src/tools/flow-path/index.ts +0 -233
  188. package/src/tools/label/Label.tsx +0 -357
  189. package/src/tools/label/LabelModel.ts +0 -83
  190. package/src/tools/label/LabelOverlay.tsx +0 -158
  191. package/src/tools/label/algorithm.ts +0 -42
  192. package/src/tools/label/index.ts +0 -479
  193. package/src/tools/label/mediumEditor.ts +0 -94
  194. package/src/tools/label/utils.ts +0 -395
  195. package/src/tools/proximity-connect/index.ts +0 -435
  196. package/src/tools/snapshot/README.md +0 -145
  197. package/src/tools/snapshot/index.ts +0 -718
  198. package/src/tools/snapshot/utils.ts +0 -163
  199. package/src/turbo-adapter/index.ts +0 -212
  200. package/stats.html +0 -4842
  201. package/tsconfig.json +0 -18
@@ -1,775 +0,0 @@
1
- import LogicFlow, {
2
- BaseEdgeModel,
3
- BaseNodeModel,
4
- EventType,
5
- CallbackArgs,
6
- Model,
7
- transformNodeData,
8
- transformEdgeData,
9
- } from '@logicflow/core'
10
- import { assign, cloneDeep, filter, forEach, has, map, sortBy } from 'lodash-es'
11
- import { DynamicGroupNode } from './node'
12
- import { DynamicGroupNodeModel } from './model'
13
- import { isAllowMoveTo, isBoundsInGroup } from './utils'
14
-
15
- import GraphConfigData = LogicFlow.GraphConfigData
16
- import GraphElements = LogicFlow.GraphElements
17
- import EdgeConfig = LogicFlow.EdgeConfig
18
- import EdgeData = LogicFlow.EdgeData
19
- import NodeData = LogicFlow.NodeData
20
- import BoxBoundsPoint = Model.BoxBoundsPoint
21
- import ElementsInfoInGroup = DynamicGroup.ElementsInfoInGroup
22
-
23
- export * from './node'
24
- export * from './model'
25
-
26
- export const dynamicGroup = {
27
- type: 'dynamic-group',
28
- view: DynamicGroupNode,
29
- model: DynamicGroupNodeModel,
30
- }
31
-
32
- const DEFAULT_TOP_Z_INDEX = -1000
33
- const DEFAULT_BOTTOM_Z_INDEX = -10000
34
-
35
- export class DynamicGroup {
36
- static pluginName = 'dynamicGroup'
37
-
38
- private lf: LogicFlow
39
- topGroupZIndex: number = DEFAULT_BOTTOM_Z_INDEX
40
- // 激活态的 group 节点
41
- activeGroup?: DynamicGroupNodeModel
42
- // 存储节点与 group 的映射关系
43
- nodeGroupMap: Map<string, string> = new Map()
44
-
45
- constructor({ lf, options }: LogicFlow.IExtensionProps) {
46
- lf.register(dynamicGroup)
47
- this.lf = lf
48
- assign(this, options)
49
- // 初始化插件,从监听事件开始及设置规则开始
50
- this.init()
51
- }
52
-
53
- /**
54
- * 获取节点所属的分组
55
- * @param nodeId
56
- */
57
- getGroupByNodeId(nodeId: string) {
58
- const groupId = this.nodeGroupMap.get(nodeId)
59
- if (groupId) {
60
- return this.lf.getNodeModelById(groupId)
61
- }
62
- }
63
-
64
- /**
65
- * 获取自定位置及其所属分组
66
- * 当分组重合时,优先返回最上层的分组
67
- * @param bounds
68
- * @param nodeData
69
- */
70
- getGroupByBounds(
71
- bounds: BoxBoundsPoint,
72
- nodeData: NodeData,
73
- ): DynamicGroupNodeModel | undefined {
74
- const { nodes } = this.lf.graphModel
75
- const groups = filter(nodes, (node) => {
76
- return (
77
- !!node.isGroup &&
78
- isBoundsInGroup(bounds, node) &&
79
- node.id !== nodeData.id
80
- )
81
- })
82
-
83
- const count = groups.length
84
- if (count <= 1) {
85
- return groups[0] as DynamicGroupNodeModel
86
- } else {
87
- let topZIndexGroup = groups[count - 1]
88
- for (let i = count - 2; i >= 0; i--) {
89
- if (groups[i].zIndex > topZIndexGroup.zIndex) {
90
- topZIndexGroup = groups[i]
91
- }
92
- }
93
- return topZIndexGroup as DynamicGroupNodeModel
94
- }
95
- }
96
-
97
- /**
98
- * 提高元素的层级,如果是 group,同时提高其子元素的层级
99
- * @param model
100
- */
101
- sendNodeToFront(model?: BaseNodeModel) {
102
- if (!model || !model.isGroup) return
103
-
104
- this.topGroupZIndex++
105
- model.setZIndex(this.topGroupZIndex)
106
- if (model.children) {
107
- const { children } = model as DynamicGroupNodeModel
108
- forEach(Array.from(children), (nodeId) => {
109
- const node = this.lf.getNodeModelById(nodeId)
110
- this.sendNodeToFront(node)
111
- })
112
- }
113
- }
114
-
115
- /**
116
- * 递归计算某个分组内最高的 zIndex 值
117
- * TODO: 这块儿有点疑问❓如果 node 不是 group,这块儿返回的 maxZIndex 是最小值,但 node 的 zIndex 不一定是这个值
118
- * @param node
119
- */
120
- getMaxZIndex(node: BaseNodeModel) {
121
- let maxZIndex = DEFAULT_BOTTOM_Z_INDEX
122
- if (node.isGroup) {
123
- maxZIndex = Math.max(maxZIndex, node.zIndex)
124
- }
125
- if (node.children) {
126
- const { children } = node as DynamicGroupNodeModel
127
- forEach(Array.from(children), (childId) => {
128
- const child = this.lf.getNodeModelById(childId)
129
- if (child?.isGroup) {
130
- const childMaxZIndex = this.getMaxZIndex(child)
131
- maxZIndex = Math.max(maxZIndex, childMaxZIndex)
132
- }
133
- })
134
- }
135
- return maxZIndex
136
- }
137
-
138
- /**
139
- * 校准当前 topGroupZIndex 的值
140
- * @param nodes
141
- */
142
- calibrateTopGroupZIndex(nodes: NodeData[]) {
143
- // 初始化时 or 增加新节点时,找出所有 nodes 的最大 zIndex
144
- let maxZIndex = DEFAULT_BOTTOM_Z_INDEX
145
- forEach(nodes, (node) => {
146
- const nodeModel = this.lf.getNodeModelById(node.id)
147
- if (nodeModel) {
148
- const currNodeMaxZIndex = this.getMaxZIndex(nodeModel)
149
- if (currNodeMaxZIndex > maxZIndex) {
150
- maxZIndex = currNodeMaxZIndex
151
- }
152
- }
153
- })
154
-
155
- // TODO: 不是很理解这块儿的代码逻辑,需要整理一下
156
- if (this.topGroupZIndex >= maxZIndex) {
157
- // 一般是初始化时/增加新节点时发生,因为外部强行设置了一个很大的 zIndex
158
- // 删除节点不会影响目前最高 zIndex 的赋值
159
- return
160
- }
161
-
162
- // 新增 nodes 中如果存在 zIndex 比 this.topGroupZIndex 大
163
- // 说明 this.topGroupZIndex 已经失去意义,代表不了目前最高 zIndex 的 group,需要重新校准
164
-
165
- // https://github.com/didi/LogicFlow/issues/1535
166
- // 当外部直接设置多个 BaseNode.zIndex = 1 时
167
- // 当点击某一个 node 时,由于这个 this.topGroupZIndex 是从 -10000 开始计算的,
168
- // this.topGroupZIndex + 1 也就是-9999,这就造成当前点击的 node 的 zIndex 远远
169
- // 比其它 node 的 zIndex 小,因此造成 zIndex 错乱的问题
170
- // TODO: 这儿的 nodes 能否直接用传参进来的 nodes 呢???
171
- const allNodes = this.lf.graphModel.nodes
172
- const allGroups = filter(allNodes, (node) => !!node.isGroup)
173
-
174
- let max = this.topGroupZIndex
175
- forEach(allGroups, (group) => {
176
- if (group.zIndex > max) max = group.zIndex
177
- })
178
- this.topGroupZIndex = max
179
- }
180
-
181
- onSelectionDrop = () => {
182
- const { nodes: selectedNodes } = this.lf.graphModel.getSelectElements()
183
- selectedNodes.forEach((node) => {
184
- this.addNodeToGroup(node)
185
- })
186
- }
187
-
188
- onNodeAddOrDrop = ({ data: node }: CallbackArgs<'node:add'>) => {
189
- this.addNodeToGroup(node)
190
- }
191
-
192
- addNodeToGroup = (node: LogicFlow.NodeData) => {
193
- // 1. 如果该节点之前已经在 group 中了,则将其从之前的 group 移除
194
- const preGroupId = this.nodeGroupMap.get(node.id)
195
-
196
- if (preGroupId) {
197
- const group = this.lf.getNodeModelById(
198
- preGroupId,
199
- ) as DynamicGroupNodeModel
200
-
201
- group.removeChild(node.id)
202
- this.nodeGroupMap.delete(node.id)
203
- group.setAllowAppendChild(false)
204
- }
205
-
206
- // 2. 然后再判断这个节点是否在某个 group 范围内,如果是,则将其添加到对应的 group 中
207
- const nodeModel = this.lf.getNodeModelById(node.id)
208
- const bounds = nodeModel?.getBounds()
209
-
210
- if (nodeModel && bounds) {
211
- // TODO: 确认下面的注释内容
212
- // https://github.com/didi/LogicFlow/issues/1261
213
- // 当使用 SelectionSelect 框选后触发 lf.addNode(Group)
214
- // 会触发 appendNodeToGroup() 的执行
215
- // 由于 this.getGroup() 会判断 node.id !== nodeData.id
216
- // 因此当 addNode 是 Group 类型时,this.getGroup() 会一直返回空
217
- // 导致了下面这段代码无法执行,也就是无法将当前添加的 Group 添加到 this.nodeGroupMap 中
218
- // 这导致了折叠分组时触发的 foldEdge() 无法正确通过 getNodeGroup() 拿到正确的 groupId
219
- // 从而导致折叠分组时一直都会创建一个虚拟边
220
- // 而初始化分组时由于正确设置了nodeGroupMap的数据,因此不会产生虚拟边的错误情况
221
- if (nodeModel.isGroup) {
222
- const group = nodeModel as DynamicGroupNodeModel
223
- forEach(Array.from(group.children), (childId) => {
224
- this.nodeGroupMap.set(childId, node.id)
225
- })
226
- // 新增 node 时进行 this.topGroupZIndex 的校准更新
227
- this.calibrateTopGroupZIndex([node])
228
- this.onNodeSelect({
229
- data: node,
230
- isSelected: false,
231
- isMultiple: false,
232
- })
233
- }
234
-
235
- // TODO: 找到这个范围内的 groupModel, 并加 node 添加到该 group
236
- const group = this.getGroupByBounds(bounds, node)
237
- if (group) {
238
- const isAllowAppendIn = group.isAllowAppendIn(node)
239
- if (isAllowAppendIn) {
240
- group.addChild(node.id)
241
- // 建立节点与 group 的映射关系放在了 group.addChild 触发的事件中,与直接调用 addChild 的行为保持一致
242
- group.setAllowAppendChild(false)
243
- } else {
244
- // 抛出不允许插入的事件
245
- this.lf.emit('group:not-allowed', {
246
- group: group.getData(),
247
- node,
248
- })
249
- }
250
- }
251
- }
252
- }
253
-
254
- onGroupAddNode = ({
255
- data: groupData,
256
- childId,
257
- }: CallbackArgs<'group:add-node'>) => {
258
- this.nodeGroupMap.set(childId, groupData.id)
259
- }
260
-
261
- removeNodeFromGroup = ({
262
- data: node,
263
- model,
264
- }: CallbackArgs<'node:delete'>) => {
265
- if (model.isGroup && node.children) {
266
- forEach(
267
- Array.from((node as DynamicGroupNodeModel).children),
268
- (childId) => {
269
- this.nodeGroupMap.delete(childId)
270
- this.lf.deleteNode(childId)
271
- },
272
- )
273
- }
274
-
275
- const groupId = this.nodeGroupMap.get(node.id)
276
- if (groupId) {
277
- const group = this.lf.getNodeModelById(groupId)
278
- group && (group as DynamicGroupNodeModel).removeChild(node.id)
279
- this.nodeGroupMap.delete(node.id)
280
- }
281
- }
282
-
283
- onSelectionDrag = () => {
284
- const { nodes: selectedNodes } = this.lf.graphModel.getSelectElements()
285
- selectedNodes.forEach((node) => {
286
- this.setActiveGroup(node)
287
- })
288
- }
289
- onNodeDrag = ({ data: node }: CallbackArgs<'node:drag'>) => {
290
- this.setActiveGroup(node)
291
- }
292
-
293
- setActiveGroup = (node: LogicFlow.NodeData) => {
294
- const nodeModel = this.lf.getNodeModelById(node.id)
295
- const bounds = nodeModel?.getBounds()
296
-
297
- if (nodeModel && bounds) {
298
- const targetGroup = this.getGroupByBounds(bounds, node)
299
- if (this.activeGroup) {
300
- this.activeGroup.setAllowAppendChild(false)
301
- }
302
-
303
- if (!targetGroup || (nodeModel.isGroup && targetGroup.id === node.id)) {
304
- return
305
- }
306
-
307
- const isAllowAppendIn = targetGroup.isAllowAppendIn(node)
308
- if (!isAllowAppendIn) return
309
-
310
- this.activeGroup = targetGroup
311
- this.activeGroup.setAllowAppendChild(true)
312
- }
313
- }
314
-
315
- /**
316
- * 1. 分组节点默认在普通节点下面
317
- * 2. 分组节点被选中后,会将分组节点以及其内部的其它分组节点放到其余分组节点的上面
318
- * 3. 分组节点取消选中后,不会将分组节点重置为原来的高度
319
- * 4. 由于 LogicFlow 核心目标是支持用户手动绘制流程图,所以暂时不支持一张流程图超过 1000 个分组节点的情况
320
- * @param node
321
- * @param isMultiple
322
- * @param isSelected
323
- */
324
- onNodeSelect = ({
325
- data: node,
326
- isMultiple,
327
- isSelected,
328
- }: Omit<CallbackArgs<'node:click'>, 'e' | 'position'>) => {
329
- const nodeModel = this.lf.getNodeModelById(node.id)
330
- this.sendNodeToFront(nodeModel)
331
-
332
- // 重置所有 group 的 zIndex,防止 group 节点 zIndex 增长为正数(目的是保持 group 节点在最底层)
333
- if (this.topGroupZIndex > DEFAULT_TOP_Z_INDEX) {
334
- const { nodes } = this.lf.graphModel
335
- this.topGroupZIndex = DEFAULT_BOTTOM_Z_INDEX
336
- const groups = sortBy(
337
- filter(nodes, (node) => !!node.isGroup),
338
- 'zIndex',
339
- )
340
-
341
- let preZIndex = 0
342
- forEach(groups, (group) => {
343
- if (group.zIndex !== preZIndex) {
344
- this.topGroupZIndex++
345
- preZIndex = group.zIndex
346
- }
347
- group.setZIndex(this.topGroupZIndex)
348
- })
349
- }
350
-
351
- // FIX #1004
352
- // 如果节点被多选,
353
- // 这个节点是分组,则将分组的所有子节点取消选中
354
- // 这个节点是分组的子节点,且其所属分组节点已选,则取消选中
355
- if (isMultiple && isSelected) {
356
- if (nodeModel?.isGroup) {
357
- const { children } = nodeModel as DynamicGroupNodeModel
358
- forEach(Array.from(children), (childId) => {
359
- const childModel = this.lf.getNodeModelById(childId)
360
- childModel?.setSelected(false)
361
- })
362
- } else {
363
- const groupId = this.nodeGroupMap.get(node.id)
364
- if (groupId) {
365
- const graphModel = this.lf.getNodeModelById(groupId)
366
- graphModel?.isSelected && nodeModel?.setSelected(false)
367
- }
368
- }
369
- }
370
- }
371
-
372
- onNodeMove = ({
373
- deltaX,
374
- deltaY,
375
- data,
376
- }: Omit<CallbackArgs<'node:mousemove'>, 'e' | 'position'>) => {
377
- const { id, x, y, properties } = data
378
- if (!properties) {
379
- return
380
- }
381
- const { width, height } = properties
382
- const groupId = this.nodeGroupMap.get(id)
383
- if (!groupId) {
384
- return
385
- }
386
- const groupModel = this.lf.getNodeModelById(
387
- groupId,
388
- ) as DynamicGroupNodeModel
389
-
390
- if (!groupModel || !groupModel.isRestrict || !groupModel.autoResize) {
391
- return
392
- }
393
- // 当父节点isRestrict=true & autoResize=true
394
- // 子节点在父节点中移动时,父节点会自动调整大小
395
-
396
- // step1: 计算出当前child的bounds
397
- const newX = x + deltaX / 2
398
- const newY = y + deltaY / 2
399
- const minX = newX - width! / 2
400
- const minY = newY - height! / 2
401
- const maxX = newX + width! / 2
402
- const maxY = newY + height! / 2
403
- // step2:比较当前child.bounds与parent.bounds的差异,比如child.minX<parent.minX,那么parent.minX=child.minX
404
- let hasChange = false
405
- const groupBounds = groupModel.getBounds()
406
- const newGroupBounds = Object.assign({}, groupBounds)
407
- if (minX < newGroupBounds.minX) {
408
- newGroupBounds.minX = minX
409
- hasChange = true
410
- }
411
- if (minY < newGroupBounds.minY) {
412
- newGroupBounds.minY = minY
413
- hasChange = true
414
- }
415
- if (maxX > newGroupBounds.maxX) {
416
- newGroupBounds.maxX = maxX
417
- hasChange = true
418
- }
419
- if (maxY > newGroupBounds.maxY) {
420
- newGroupBounds.maxY = maxY
421
- hasChange = true
422
- }
423
- if (!hasChange) {
424
- return
425
- }
426
- // step3: 根据当前parent.bounds去计算出最新的x、y、width、height
427
- const newGroupX =
428
- newGroupBounds.minX + (newGroupBounds.maxX - newGroupBounds.minX) / 2
429
- const newGroupY =
430
- newGroupBounds.minY + (newGroupBounds.maxY - newGroupBounds.minY) / 2
431
- const newGroupWidth = newGroupBounds.maxX - newGroupBounds.minX
432
- const newGroupHeight = newGroupBounds.maxY - newGroupBounds.minY
433
- groupModel.moveTo(newGroupX, newGroupY)
434
- groupModel.width = newGroupWidth
435
- groupModel.height = newGroupHeight
436
- }
437
-
438
- onGraphRendered = ({ data }: CallbackArgs<'graph:rendered'>) => {
439
- forEach(data.nodes, (node) => {
440
- if (node.children) {
441
- forEach(node.children, (childId) => {
442
- this.nodeGroupMap.set(childId, node.id)
443
- })
444
- }
445
- })
446
-
447
- // TODO: 确认一下下面方法的必要性及合理性
448
- // 初始化 nodes 时进行 this.topGroupZIndex 的校准更新
449
- this.calibrateTopGroupZIndex(data.nodes)
450
- }
451
-
452
- removeChildrenInGroupNodeData<
453
- T extends LogicFlow.NodeData | LogicFlow.NodeConfig,
454
- >(nodeData: T) {
455
- const newNodeData = cloneDeep(nodeData)
456
- delete newNodeData.children
457
- if (newNodeData.properties?.children) {
458
- delete newNodeData.properties.children
459
- }
460
- return newNodeData
461
- }
462
-
463
- /**
464
- * 创建一个 Group 类型节点内部所有子节点的副本
465
- * 并且在遍历所有 nodes 的过程中,顺便拿到所有 edges (只在 Group 范围的 edges)
466
- */
467
- initGroupChildNodes(
468
- nodeIdMap: Record<string, string>,
469
- children: Set<string>,
470
- curGroup: DynamicGroupNodeModel,
471
- distance: number,
472
- ): ElementsInfoInGroup {
473
- // Group 中所有子节点
474
- const allChildNodes: BaseNodeModel[] = []
475
- // 属于 Group 内部边的 EdgeData
476
- const edgesDataArr: EdgeData[] = []
477
- // 所有有关联的连线
478
- const allRelatedEdges: BaseEdgeModel[] = []
479
-
480
- forEach(Array.from(children), (childId: string) => {
481
- const childNode = this.lf.getNodeModelById(childId)
482
- if (childNode) {
483
- const childNodeChildren = childNode.children
484
- const childNodeData = childNode.getData()
485
- const eventType = EventType.NODE_GROUP_COPY || 'node:group-copy-add'
486
-
487
- const newNodeConfig = transformNodeData(
488
- this.removeChildrenInGroupNodeData(childNodeData),
489
- distance,
490
- )
491
- const tempChildNode = this.lf.addNode(newNodeConfig, eventType)
492
- curGroup.addChild(tempChildNode.id)
493
-
494
- nodeIdMap[childId] = tempChildNode.id // id 同 childId,做映射存储
495
- allChildNodes.push(tempChildNode)
496
-
497
- // 1. 存储 children 内部节点相关的输入边(incoming)
498
- allRelatedEdges.push(
499
- ...[...tempChildNode.incoming.edges, ...tempChildNode.outgoing.edges],
500
- )
501
-
502
- if (childNodeChildren instanceof Set) {
503
- const { childNodes, edgesData } = this.initGroupChildNodes(
504
- nodeIdMap,
505
- childNodeChildren,
506
- tempChildNode as DynamicGroupNodeModel,
507
- distance,
508
- )
509
-
510
- allChildNodes.push(...childNodes)
511
- edgesDataArr.push(...edgesData)
512
- }
513
- }
514
- })
515
-
516
- // 1. 判断每一条边的开始节点、目标节点是否在 Group 中
517
- const edgesInnerGroup = filter(allRelatedEdges, (edge) => {
518
- return (
519
- has(nodeIdMap, edge.sourceNodeId) && has(nodeIdMap, edge.targetNodeId)
520
- )
521
- })
522
- // 2. 为「每一条 Group 的内部边」构建出 EdgeData 数据,得到 EdgeConfig,生成新的线
523
- const edgesDataInnerGroup = map(edgesInnerGroup, (edge) => {
524
- return edge.getData()
525
- })
526
-
527
- return {
528
- childNodes: allChildNodes,
529
- edgesData: edgesDataArr.concat(edgesDataInnerGroup),
530
- }
531
- }
532
-
533
- /**
534
- * 根据参数 edge 选择是新建边还是基于已有边,复制一条边出来
535
- * @param edge
536
- * @param nodeIdMap
537
- * @param distance
538
- */
539
- createEdge(
540
- edge: EdgeConfig | EdgeData,
541
- nodeIdMap: Record<string, string>,
542
- distance: number,
543
- ) {
544
- const { sourceNodeId, targetNodeId } = edge
545
- const sourceId = nodeIdMap[sourceNodeId] ?? sourceNodeId
546
- const targetId = nodeIdMap[targetNodeId] ?? targetNodeId
547
-
548
- // 如果是有 id 且 text 是对象的边,需要重新计算位置,否则直接用 edgeConfig 生成边
549
- let newEdgeConfig = cloneDeep(edge)
550
- if (edge.id && typeof edge.text === 'object' && edge.text !== null) {
551
- newEdgeConfig = transformEdgeData(edge as EdgeData, distance)
552
- }
553
-
554
- return this.lf.graphModel.addEdge({
555
- ...newEdgeConfig,
556
- sourceNodeId: sourceId,
557
- targetNodeId: targetId,
558
- })
559
- }
560
-
561
- /**
562
- * 检测group:resize后的bounds是否会小于children的bounds
563
- * 限制group进行resize时不能小于内部的占地面积
564
- * @param groupModel
565
- * @param deltaX
566
- * @param deltaY
567
- * @param newWidth
568
- * @param newHeight
569
- */
570
- checkGroupBoundsWithChildren(
571
- groupModel: DynamicGroupNodeModel,
572
- deltaX: number,
573
- deltaY: number,
574
- newWidth: number,
575
- newHeight: number,
576
- ) {
577
- if (groupModel.children) {
578
- const { children, x, y } = groupModel
579
- // 根据deltaX和deltaY计算出当前model的bounds
580
- const newX = x + deltaX / 2
581
- const newY = y + deltaY / 2
582
- const groupMinX = newX - newWidth / 2
583
- const groupMinY = newY - newHeight / 2
584
- const groupMaxX = newX + newWidth / 2
585
- const groupMaxY = newY + newHeight / 2
586
-
587
- const childrenArray = Array.from(children)
588
- for (let i = 0; i < childrenArray.length; i++) {
589
- const childId = childrenArray[i]
590
- const child = this.lf.getNodeModelById(childId)
591
- if (!child) {
592
- continue
593
- }
594
- const childBounds = child.getBounds()
595
- const { minX, minY, maxX, maxY } = childBounds
596
- // parent:resize后的bounds不能小于child:bounds,否则阻止其resize
597
- const canResize =
598
- groupMinX <= minX &&
599
- groupMinY <= minY &&
600
- groupMaxX >= maxX &&
601
- groupMaxY >= maxY
602
- if (!canResize) {
603
- return false
604
- }
605
- }
606
- }
607
-
608
- return true
609
- }
610
-
611
- /**
612
- * Group 插件的初始化方法
613
- * TODO:1. 待讨论,可能之前插件分类是有意义的 components, material, tools
614
- * 区别是:1. 有些插件就是自定义节点,可能会有初始化方法 init,但不必要有 render (比如 Group)
615
- * 2. 有些插件是渲染一些部件(比如 MiniMap、Control、Menu 等)必须要有 render
616
- * 3. 工具类的,init 、 render
617
- * 该如何分类呢?并如何完善插件的类型
618
- *
619
- * TODO: 2. 插件的 destroy 方法该做些什么,是否应该加 destroy 方法
620
- * TODO: 3. 是否应该定义一个 Extension 的基类,所有插件基于这个基类来开发,这样在初始化的时候就可以确认执行什么方法
621
- */
622
- init() {
623
- const { lf } = this
624
- const { graphModel } = lf
625
- // 添加分组节点移动规则
626
- // 1. 移动分组节点时,同时移动分组内所有节点
627
- // 2. 移动子节点时,判断是否有限制规则(isRestrict)
628
- graphModel.addNodeMoveRules((model, deltaX, deltaY) => {
629
- // 判断如果是 group,移动时需要同时移动组内的所有节点
630
- if (model.isGroup) {
631
- // https://github.com/didi/LogicFlow/issues/1826
632
- // 这里不应该触发移动子节点的逻辑,这里是判断是否可以移动,而不是触发移动逻辑
633
- // 而且这里触发移动,会导致resize操作的this.x变动也会触发子item的this.x变动
634
- // resize时的deltaX跟正常移动的deltaX是不同的
635
-
636
- // const nodeIds = this.getNodesInGroup(model as DynamicGroupNodeModel)
637
- // graphModel.moveNodes(nodeIds, deltaX, deltaY, true)
638
- return true
639
- }
640
-
641
- const groupId = this.nodeGroupMap.get(model.id)!
642
- const groupModel = this.lf.getNodeModelById(
643
- groupId,
644
- ) as DynamicGroupNodeModel
645
-
646
- if (groupModel && groupModel.isRestrict) {
647
- if (groupModel.autoResize) {
648
- // 子节点在父节点中移动时,父节点会自动调整大小
649
- // 在node:mousemove中进行父节点的调整
650
- return true
651
- } else {
652
- // 如果移动的节点存在于某个分组中,且这个分组禁止子节点移出去
653
- const groupBounds = groupModel.getBounds()
654
- return isAllowMoveTo(groupBounds, model, deltaX, deltaY)
655
- }
656
- }
657
-
658
- return true
659
- })
660
-
661
- // https://github.com/didi/LogicFlow/issues/1442
662
- // https://github.com/didi/LogicFlow/issues/937
663
- // 添加分组节点resize规则
664
- // isRestrict限制模式下,当前model resize时不能小于children的占地面积
665
- // 并且在isRestrict限制模式下,transformWidthContainer即使设置为true,也无效
666
- graphModel.addNodeResizeRules((model, deltaX, deltaY, width, height) => {
667
- if (model.isGroup && model.isRestrict) {
668
- return this.checkGroupBoundsWithChildren(
669
- model as DynamicGroupNodeModel,
670
- deltaX,
671
- deltaY,
672
- width,
673
- height,
674
- )
675
- }
676
- return true
677
- })
678
-
679
- graphModel.dynamicGroup = this
680
- lf.on('node:add,node:drop,node:dnd-add', this.onNodeAddOrDrop)
681
- lf.on('selection:drop', this.onSelectionDrop)
682
- lf.on('node:delete', this.removeNodeFromGroup)
683
- lf.on('node:drag,node:dnd-drag', this.onNodeDrag)
684
- lf.on('selection:drag', this.onSelectionDrag)
685
- lf.on('node:click', this.onNodeSelect)
686
- lf.on('node:mousemove', this.onNodeMove)
687
- lf.on('graph:rendered', this.onGraphRendered)
688
-
689
- lf.on('group:add-node', this.onGroupAddNode)
690
-
691
- // https://github.com/didi/LogicFlow/issues/1346
692
- // 重写 addElements() 方法,在 addElements() 原有基础上增加对 group 内部所有 nodes 和 edges 的复制功能
693
- // 使用场景:addElements api 项目内部目前只在快捷键粘贴时使用(此处解决的也应该是粘贴场景的问题)
694
- lf.addElements = (
695
- { nodes: selectedNodes, edges: selectedEdges }: GraphConfigData,
696
- distance = 40,
697
- ): GraphElements => {
698
- // oldNodeId -> newNodeId 映射 Map
699
- const nodeIdMap: Record<string, string> = {}
700
- // 本次添加的所有节点和边
701
- const elements: GraphElements = {
702
- nodes: [],
703
- edges: [],
704
- }
705
- // 所有属于分组内的边 -> sourceNodeId 和 targetNodeId 都在 Group 内
706
- const edgesInnerGroup: EdgeData[] = []
707
-
708
- forEach(selectedNodes, (node) => {
709
- const originId = node.id
710
- const children = node.properties?.children ?? node.children
711
-
712
- const model = lf.addNode(this.removeChildrenInGroupNodeData(node))
713
-
714
- if (originId) nodeIdMap[originId] = model.id
715
- elements.nodes.push(model) // 此时为 group 的 nodeModel
716
-
717
- // TODO: 递归创建 group 的 nodeModel 的 children
718
- if (model.isGroup) {
719
- const { edgesData } = this.initGroupChildNodes(
720
- nodeIdMap,
721
- children,
722
- model as DynamicGroupNodeModel,
723
- distance,
724
- )
725
- edgesInnerGroup.push(...edgesData)
726
- }
727
- })
728
-
729
- forEach(edgesInnerGroup, (edge) => {
730
- this.createEdge(edge, nodeIdMap, distance)
731
- })
732
- forEach(selectedEdges, (edge) => {
733
- elements.edges.push(this.createEdge(edge, nodeIdMap, distance))
734
- })
735
-
736
- // 返回 elements 进行选中效果,即触发 element.selectElementById()
737
- // shortcut.ts 也会对最外层的 nodes 和 edges 进行偏移,即 translationNodeData()
738
- return elements
739
- }
740
-
741
- this.render()
742
- }
743
-
744
- render() {}
745
-
746
- destroy() {
747
- // 销毁监听的事件,并移除渲染的 dom 内容
748
- this.lf.off('node:add,node:drop,node:dnd-add', this.onNodeAddOrDrop)
749
- this.lf.off('selection:drop', this.onSelectionDrop)
750
- this.lf.off('node:delete', this.removeNodeFromGroup)
751
- this.lf.off('node:drag,node:dnd-drag', this.onNodeDrag)
752
- this.lf.off('selection:drag', this.onSelectionDrag)
753
- this.lf.off('node:click', this.onNodeSelect)
754
- this.lf.off('node:mousemove', this.onNodeMove)
755
- this.lf.off('graph:rendered', this.onGraphRendered)
756
- this.lf.off('group:add-node', this.onGroupAddNode)
757
-
758
- // 还原 lf.addElements 方法?
759
- // 移除 graphModel 上重写的 addNodeMoveRules 方法?
760
- // TODO: 讨论一下插件该具体做些什么
761
- }
762
- }
763
-
764
- export namespace DynamicGroup {
765
- export type ElementsInfoInGroup = {
766
- childNodes: BaseNodeModel[] // 分组节点的所有子节点 model
767
- edgesData: EdgeData[] // 属于分组内的线的 EdgeData (即开始节点和结束节点都在 Group 内)
768
- }
769
-
770
- export type DynamicGroupOptions = Partial<{
771
- isCollapsed: boolean
772
- }>
773
- }
774
-
775
- export default DynamicGroup