@logicflow/extension 2.0.10 → 2.0.12
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.
- package/.turbo/turbo-build.log +9 -17
- package/CHANGELOG.md +37 -0
- package/dist/index.css +278 -1
- package/es/bpmn-elements/presets/Pool/Pool.d.ts +2 -2
- package/es/dynamic-group/index.d.ts +2 -1
- package/es/dynamic-group/index.js +21 -19
- package/es/dynamic-group/model.js +1 -5
- package/es/dynamic-group/node.d.ts +8 -1
- package/es/dynamic-group/node.js +87 -22
- package/es/index.css +278 -1
- package/es/index.less +1 -0
- package/es/materials/group/GroupNode.d.ts +5 -5
- package/es/materials/group/GroupNode.js +3 -3
- package/es/materials/group/index.js +5 -5
- package/es/materials/node-selection/index.d.ts +6 -6
- package/es/materials/node-selection/index.js +90 -10
- package/es/style/index.css +278 -1
- package/es/style/index.less +327 -0
- package/lib/bpmn-elements/presets/Pool/Pool.d.ts +2 -2
- package/lib/dynamic-group/index.d.ts +2 -1
- package/lib/dynamic-group/index.js +21 -19
- package/lib/dynamic-group/model.js +1 -5
- package/lib/dynamic-group/node.d.ts +8 -1
- package/lib/dynamic-group/node.js +87 -22
- package/lib/index.css +278 -1
- package/lib/index.less +1 -0
- package/lib/materials/group/GroupNode.d.ts +5 -5
- package/lib/materials/group/GroupNode.js +3 -3
- package/lib/materials/group/index.js +5 -5
- package/lib/materials/node-selection/index.d.ts +6 -6
- package/lib/materials/node-selection/index.js +89 -9
- package/lib/style/index.css +278 -1
- package/lib/style/index.less +327 -0
- package/package.json +3 -3
- package/src/components/mini-map/index.ts +11 -0
- package/src/dynamic-group/index.ts +29 -8
- package/src/dynamic-group/model.ts +1 -6
- package/src/dynamic-group/node.ts +136 -85
- package/src/index.ts +1 -0
- package/src/materials/group/GroupNode.ts +3 -3
- package/src/materials/group/index.ts +5 -5
- package/src/materials/node-selection/index.ts +115 -14
- package/src/style/index.less +3 -5
- package/src/style/raw.ts +3 -7
- package/src/tools/label/Label.tsx +106 -55
- package/src/tools/label/LabelModel.ts +1 -0
- package/src/tools/label/index.ts +64 -3
- package/src/tools/proximity-connect/index.ts +399 -0
- package/stats.html +1 -1
- package/dist/index.min.js +0 -2
- package/dist/index.min.js.map +0 -1
|
@@ -3,6 +3,7 @@ import LogicFlow, {
|
|
|
3
3
|
h,
|
|
4
4
|
RectNode,
|
|
5
5
|
handleResize,
|
|
6
|
+
CallbackArgs,
|
|
6
7
|
} from '@logicflow/core'
|
|
7
8
|
import { forEach } from 'lodash-es'
|
|
8
9
|
import { DynamicGroupNodeModel } from './model'
|
|
@@ -18,101 +19,151 @@ export interface IDynamicGroupNodeProps {
|
|
|
18
19
|
export class DynamicGroupNode<
|
|
19
20
|
P extends IDynamicGroupNodeProps = IDynamicGroupNodeProps,
|
|
20
21
|
> extends RectNode<P> {
|
|
21
|
-
|
|
22
|
-
super.componentDidMount()
|
|
22
|
+
childrenPositionMap: Map<string, Position> = new Map()
|
|
23
23
|
|
|
24
|
+
onNodeRotate = ({
|
|
25
|
+
model,
|
|
26
|
+
}: Omit<CallbackArgs<'node:rotate'>, 'e' | 'position'>) => {
|
|
24
27
|
const { model: curGroup, graphModel } = this.props
|
|
25
|
-
const {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
const { transformWithContainer, isRestrict } = curGroup
|
|
29
|
+
const childrenPositionMap = this.childrenPositionMap
|
|
30
|
+
if (!transformWithContainer || isRestrict) {
|
|
31
|
+
// isRestrict限制模式下,当前model resize时不能小于占地面积
|
|
32
|
+
// 由于parent:resize=>child:resize计算复杂,需要根据child:resize的判定结果来递归判断parent能否resize
|
|
33
|
+
// 不符合目前 parent:resize成功后emit事件 -> 触发child:resize 的代码交互模式
|
|
34
|
+
// 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
|
|
35
|
+
// 由于transformWidthContainer是控制rotate+resize,为保持transformWidthContainer本来的含义
|
|
36
|
+
// parent:resize=>child:resize不支持,那么parent:rotate=>child:rotate也不支持
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
// DONE: 目前操作是对分组内节点以节点中心旋转节点本身,而按照正常逻辑,应该是以分组中心,旋转节点(跟 Label 旋转操作逻辑一致)
|
|
40
|
+
if (model.id === curGroup.id) {
|
|
41
|
+
const center = { x: curGroup.x, y: curGroup.y }
|
|
42
|
+
forEach(Array.from(curGroup.children), (childId) => {
|
|
43
|
+
const child = graphModel.getNodeModelById(childId)
|
|
28
44
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// 不符合目前 parent:resize成功后emit事件 -> 触发child:resize 的代码交互模式
|
|
36
|
-
// 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
|
|
37
|
-
// 由于transformWidthContainer是控制rotate+resize,为保持transformWidthContainer本来的含义
|
|
38
|
-
// parent:resize=>child:resize不支持,那么parent:rotate=>child:rotate也不支持
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
// DONE: 目前操作是对分组内节点以节点中心旋转节点本身,而按照正常逻辑,应该是以分组中心,旋转节点(跟 Label 旋转操作逻辑一致)
|
|
42
|
-
if (model.id === curGroup.id) {
|
|
43
|
-
const center = { x: curGroup.x, y: curGroup.y }
|
|
44
|
-
forEach(Array.from(curGroup.children), (childId) => {
|
|
45
|
-
const child = graphModel.getNodeModelById(childId)
|
|
46
|
-
|
|
47
|
-
if (child) {
|
|
48
|
-
let point: Position = { x: child.x, y: child.y }
|
|
49
|
-
if (childrenPositionMap.has(child.id)) {
|
|
50
|
-
point = childrenPositionMap.get(child.id)!
|
|
51
|
-
} else {
|
|
52
|
-
childrenPositionMap.set(child.id, point)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 弧度转角度
|
|
56
|
-
let theta = model.rotate * (180 / Math.PI)
|
|
57
|
-
if (theta < 0) theta += 360
|
|
58
|
-
const radian = theta * (Math.PI / 180)
|
|
59
|
-
|
|
60
|
-
const newPoint = rotatePointAroundCenter(point, center, radian)
|
|
61
|
-
|
|
62
|
-
child.moveTo(newPoint.x, newPoint.y)
|
|
63
|
-
child.rotate = model.rotate
|
|
45
|
+
if (child) {
|
|
46
|
+
let point: Position = { x: child.x, y: child.y }
|
|
47
|
+
if (childrenPositionMap.has(child.id)) {
|
|
48
|
+
point = childrenPositionMap.get(child.id)!
|
|
49
|
+
} else {
|
|
50
|
+
childrenPositionMap.set(child.id, point)
|
|
64
51
|
}
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
52
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
|
|
79
|
-
return
|
|
53
|
+
// 弧度转角度
|
|
54
|
+
let theta = model.rotate * (180 / Math.PI)
|
|
55
|
+
if (theta < 0) theta += 360
|
|
56
|
+
const radian = theta * (Math.PI / 180)
|
|
57
|
+
|
|
58
|
+
const newPoint = rotatePointAroundCenter(point, center, radian)
|
|
59
|
+
|
|
60
|
+
child.moveTo(newPoint.x, newPoint.y)
|
|
61
|
+
child.rotate = model.rotate
|
|
80
62
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
onNodeResize = ({
|
|
68
|
+
deltaX,
|
|
69
|
+
deltaY,
|
|
70
|
+
index,
|
|
71
|
+
model,
|
|
72
|
+
preData,
|
|
73
|
+
}: Omit<CallbackArgs<'node:resize'>, 'e' | 'position'>) => {
|
|
74
|
+
const { model: curGroup, graphModel } = this.props
|
|
75
|
+
const { transformWithContainer, isRestrict } = curGroup
|
|
76
|
+
if (!transformWithContainer || isRestrict) {
|
|
77
|
+
// isRestrict限制模式下,当前model resize时不能小于占地面积
|
|
78
|
+
// 由于parent:resize=>child:resize计算复杂,需要根据child:resize的判定结果来递归判断parent能否resize
|
|
79
|
+
// 不符合目前 parent:resize成功后emit事件 -> 触发child:resize 的代码交互模式
|
|
80
|
+
// 因此isRestrict限制模式下不支持联动(parent:resize=>child:resize)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
if (model.id === curGroup.id) {
|
|
84
|
+
// node:resize是group已经改变width和height后的回调
|
|
85
|
+
// 因此这里一定得用preData(没resize改变width之前的值),而不是data/model
|
|
86
|
+
const { properties } = preData
|
|
87
|
+
const { width: groupWidth, height: groupHeight } = properties || {}
|
|
88
|
+
forEach(Array.from(curGroup.children), (childId) => {
|
|
89
|
+
const child = graphModel.getNodeModelById(childId)
|
|
90
|
+
if (child) {
|
|
91
|
+
// 根据比例去控制缩放dx和dy
|
|
92
|
+
const childDx = (child.width / groupWidth!) * deltaX
|
|
93
|
+
const childDy = (child.height / groupHeight!) * deltaY
|
|
94
|
+
|
|
95
|
+
// child.rotate = model.rotate
|
|
96
|
+
handleResize({
|
|
97
|
+
deltaX: childDx,
|
|
98
|
+
deltaY: childDy,
|
|
99
|
+
index,
|
|
100
|
+
nodeModel: child,
|
|
101
|
+
graphModel,
|
|
102
|
+
cancelCallback: () => {},
|
|
103
103
|
})
|
|
104
104
|
}
|
|
105
|
-
}
|
|
106
|
-
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
}
|
|
107
108
|
|
|
109
|
+
onNodeMouseMove = ({
|
|
110
|
+
deltaX,
|
|
111
|
+
deltaY,
|
|
112
|
+
data,
|
|
113
|
+
}: Omit<CallbackArgs<'node:mousemove'>, 'e' | 'position'>) => {
|
|
114
|
+
const { model: curGroup, graphModel } = this.props
|
|
115
|
+
const { transformModel } = graphModel
|
|
116
|
+
const { SCALE_X, SCALE_Y } = transformModel
|
|
117
|
+
if (data.id === curGroup.id) {
|
|
118
|
+
const nodeIds = this.getNodesInGroup(curGroup, graphModel)
|
|
119
|
+
// https://github.com/didi/LogicFlow/issues/1914
|
|
120
|
+
// 当调用lf.fitView()时,会改变整体的SCALE_X和SCALE_Y
|
|
121
|
+
// 由于group的mousemove是在drag.ts的this.onDragging()处理的,在onDragging()里面进行SCALE的处理
|
|
122
|
+
// 而"node:mousemove"emit出来跟onDragging()是同时的,也就是emit出来的数据是没有经过SCALE处理的坐标
|
|
123
|
+
// 因此这里需要增加SCALE的处理
|
|
124
|
+
graphModel.moveNodes(nodeIds, deltaX / SCALE_X, deltaY / SCALE_Y, true)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
graphRendered = () => {
|
|
129
|
+
const { model } = this.props
|
|
130
|
+
// 初始化时,如果 this.isCollapsed 为 true,则主动触发一次折叠操作
|
|
131
|
+
if (model.isCollapsed) {
|
|
132
|
+
// https://github.com/didi/LogicFlow/issues/1918
|
|
133
|
+
// 当lf.render({nodes:[{分组节点}, {普通节点}]})时,由于是顺序遍历
|
|
134
|
+
// 会先触发分组Group节点的new Model => toggleCollapse()
|
|
135
|
+
// => 此时在graphModel.elementsModelMap找不到它的children,因为还没初始化,因此无法正确折叠子元素
|
|
136
|
+
// --------------------
|
|
137
|
+
// 当lf.render({nodes:[{普通节点}, {分组节点}]})时,
|
|
138
|
+
// 会先触发普通节点的new Model => graphModel.elementsModelMap.set(id, new Model())
|
|
139
|
+
// 然后再触发分组Group节点的new Model => toggleCollapse() =>
|
|
140
|
+
// 此时在graphModel.elementsModelMap能找到它的children了,因此可以正确折叠子元素
|
|
141
|
+
// --------------------
|
|
142
|
+
// 因此将整个初始化判断是否【主动触发一次折叠操作】放在"graph:rendered"全部渲染完成后再执行
|
|
143
|
+
model.toggleCollapse(true)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
componentDidMount() {
|
|
148
|
+
super.componentDidMount()
|
|
149
|
+
const { eventCenter } = this.props.graphModel
|
|
150
|
+
// 在 group 旋转时,对组内的所有子节点也进行对应的旋转计算
|
|
151
|
+
eventCenter.on('node:rotate', this.onNodeRotate)
|
|
152
|
+
// 在 group 缩放时,对组内的所有子节点也进行对应的缩放计算
|
|
153
|
+
eventCenter.on('node:resize', this.onNodeResize)
|
|
108
154
|
// 在 group 移动时,对组内的所有子节点也进行对应的移动计算
|
|
109
|
-
eventCenter.on('node:mousemove',
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
155
|
+
eventCenter.on('node:mousemove', this.onNodeMouseMove)
|
|
156
|
+
// 全部渲染完成后,判断是否【主动触发一次折叠操作】
|
|
157
|
+
eventCenter.on('graph:rendered', this.graphRendered)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
componentWillUnmount() {
|
|
161
|
+
super.componentWillUnmount()
|
|
162
|
+
const { eventCenter } = this.props.graphModel
|
|
163
|
+
eventCenter.off('node:rotate', this.onNodeRotate)
|
|
164
|
+
eventCenter.off('node:resize', this.onNodeResize)
|
|
165
|
+
eventCenter.off('node:mousemove', this.onNodeMouseMove)
|
|
166
|
+
eventCenter.off('graph:rendered', this.graphRendered)
|
|
116
167
|
}
|
|
117
168
|
|
|
118
169
|
/**
|
package/src/index.ts
CHANGED
|
@@ -278,10 +278,10 @@ export class GroupNodeModel extends RectResizeModel {
|
|
|
278
278
|
)
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
isAllowMoveTo({
|
|
281
|
+
isAllowMoveTo({ minX, minY, maxX, maxY }) {
|
|
282
282
|
return {
|
|
283
|
-
x:
|
|
284
|
-
y:
|
|
283
|
+
x: minX >= this.x - this.width / 2 && maxX <= this.x + this.width / 2,
|
|
284
|
+
y: minY >= this.y - this.height / 2 && maxY <= this.y + this.height / 2,
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
|
|
@@ -45,12 +45,12 @@ export class Group {
|
|
|
45
45
|
) as GroupNodeModel
|
|
46
46
|
if (groupModel && groupModel.isRestrict) {
|
|
47
47
|
// 如果移动的节点存在分组中,且这个分组禁止子节点移出去。
|
|
48
|
-
const { minX
|
|
48
|
+
const { minX, minY, maxX, maxY } = model.getBounds()
|
|
49
49
|
return groupModel.isAllowMoveTo({
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
minX: minX + deltaX,
|
|
51
|
+
minY: minY + deltaY,
|
|
52
|
+
maxX: maxX + deltaX,
|
|
53
|
+
maxY: maxY + deltaY,
|
|
54
54
|
})
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { get } from 'lodash-es'
|
|
2
|
-
import
|
|
2
|
+
import LogicFlow, {
|
|
3
|
+
BaseNodeModel,
|
|
4
|
+
h,
|
|
5
|
+
PolygonNode,
|
|
6
|
+
PolygonNodeModel,
|
|
7
|
+
} from '@logicflow/core'
|
|
8
|
+
import { ResizeControl } from '@logicflow/core/lib/view/Control'
|
|
3
9
|
|
|
4
10
|
export type INodeSelectionProperties = {
|
|
5
11
|
strokeColor?: string | 'none'
|
|
@@ -124,7 +130,7 @@ class NodeSelectionModel extends PolygonNodeModel<INodeSelectionProperties> {
|
|
|
124
130
|
* 更新points - 多边形顶点坐标集合
|
|
125
131
|
* @param points
|
|
126
132
|
*/
|
|
127
|
-
updatePoints(points) {
|
|
133
|
+
updatePoints(points: [number, number][]) {
|
|
128
134
|
this.points = points
|
|
129
135
|
}
|
|
130
136
|
|
|
@@ -139,7 +145,7 @@ class NodeSelectionModel extends PolygonNodeModel<INodeSelectionProperties> {
|
|
|
139
145
|
/**
|
|
140
146
|
* 计算新的 points 和 x y
|
|
141
147
|
*/
|
|
142
|
-
updatePointsByNodes(nodesIds) {
|
|
148
|
+
updatePointsByNodes(nodesIds: string[]) {
|
|
143
149
|
const points: [number, number][] = []
|
|
144
150
|
let minX = Infinity
|
|
145
151
|
let minY = Infinity
|
|
@@ -165,18 +171,74 @@ class NodeSelectionModel extends PolygonNodeModel<INodeSelectionProperties> {
|
|
|
165
171
|
y: (maxY + minY) / 2,
|
|
166
172
|
})
|
|
167
173
|
}
|
|
174
|
+
|
|
175
|
+
isResize = false
|
|
176
|
+
override resize(
|
|
177
|
+
resizeInfo: ResizeControl.ResizeInfo,
|
|
178
|
+
): ResizeControl.ResizeNodeData {
|
|
179
|
+
this.isResize = true
|
|
180
|
+
const { width, height } = resizeInfo
|
|
181
|
+
const scale = {
|
|
182
|
+
x: width / this.width,
|
|
183
|
+
y: height / this.height,
|
|
184
|
+
}
|
|
185
|
+
const childIds = (this.properties.node_selection_ids || []).slice()
|
|
186
|
+
const childModels: BaseNodeModel[] = []
|
|
187
|
+
const usedGroupId = new Set<string>()
|
|
188
|
+
while (childIds.length) {
|
|
189
|
+
const id = childIds.shift()!
|
|
190
|
+
const node = this.graphModel.nodesMap[id]?.model
|
|
191
|
+
if (!node) {
|
|
192
|
+
continue
|
|
193
|
+
}
|
|
194
|
+
if (!isNodeSelectionModel(node)) {
|
|
195
|
+
childModels.push(node)
|
|
196
|
+
continue
|
|
197
|
+
}
|
|
198
|
+
// 跳出循环引用
|
|
199
|
+
if (usedGroupId.has(node.id)) {
|
|
200
|
+
continue
|
|
201
|
+
}
|
|
202
|
+
usedGroupId.add(node.id)
|
|
203
|
+
childIds.push(...(node.properties.node_selection_ids || []))
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const begin = {
|
|
207
|
+
x: this.x - this.width / 2,
|
|
208
|
+
y: this.y - this.height / 2,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const res = super.resize(resizeInfo)
|
|
212
|
+
|
|
213
|
+
const end = {
|
|
214
|
+
x: this.x - this.width / 2,
|
|
215
|
+
y: this.y - this.height / 2,
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
childModels.forEach((node) => {
|
|
219
|
+
node.width = node.width * scale.x
|
|
220
|
+
node.height = node.height * scale.y
|
|
221
|
+
const deltaX = (node.x - begin.x) * scale.x + end.x - node.x
|
|
222
|
+
const deltaY = (node.y - begin.y) * scale.y + end.y - node.y
|
|
223
|
+
node.move(deltaX, deltaY, true)
|
|
224
|
+
})
|
|
225
|
+
this.isResize = false
|
|
226
|
+
return res
|
|
227
|
+
}
|
|
168
228
|
}
|
|
169
229
|
|
|
230
|
+
const NODE_SELECTION_TYPE = 'node-selection'
|
|
170
231
|
class NodeSelection {
|
|
171
232
|
static pluginName = 'node-selection'
|
|
172
|
-
lf // lf 实例
|
|
233
|
+
lf: LogicFlow // lf 实例
|
|
173
234
|
selectNodes: any[] = [] // 选择的nodes
|
|
174
235
|
currentClickNode // 当前点击的节点,选中的节点是无序的
|
|
175
236
|
d = 10
|
|
176
237
|
|
|
177
|
-
constructor({ lf }) {
|
|
238
|
+
constructor({ lf }: LogicFlow.IExtensionProps) {
|
|
239
|
+
this.lf = lf
|
|
178
240
|
lf.register({
|
|
179
|
-
type:
|
|
241
|
+
type: NODE_SELECTION_TYPE,
|
|
180
242
|
view: NodeSelectionView,
|
|
181
243
|
model: NodeSelectionModel,
|
|
182
244
|
})
|
|
@@ -199,6 +261,8 @@ class NodeSelection {
|
|
|
199
261
|
properties: {
|
|
200
262
|
node_selection_ids: this.selectNodesIds,
|
|
201
263
|
},
|
|
264
|
+
x: 0,
|
|
265
|
+
y: 0,
|
|
202
266
|
})
|
|
203
267
|
node.updatePointsByNodes(this.selectNodesIds)
|
|
204
268
|
}
|
|
@@ -215,7 +279,7 @@ class NodeSelection {
|
|
|
215
279
|
|
|
216
280
|
this.lf
|
|
217
281
|
.getNodeModelById(nodeSelection.id)
|
|
218
|
-
|
|
282
|
+
?.updatePointsByNodes(this.selectNodesIds)
|
|
219
283
|
}
|
|
220
284
|
|
|
221
285
|
/**
|
|
@@ -228,24 +292,44 @@ class NodeSelection {
|
|
|
228
292
|
const oldIds = ids.filter((id) => id !== this.currentClickNode.id)
|
|
229
293
|
return rawData.nodes.find((node) => {
|
|
230
294
|
if (node.type === 'node-selection') {
|
|
231
|
-
const nodeSelectionIds = get(
|
|
295
|
+
const nodeSelectionIds = get(
|
|
296
|
+
node,
|
|
297
|
+
'properties.node_selection_ids',
|
|
298
|
+
[],
|
|
299
|
+
) as string[]
|
|
232
300
|
return oldIds.every((id) => nodeSelectionIds.includes(id))
|
|
233
301
|
}
|
|
234
302
|
return false
|
|
235
303
|
})
|
|
236
304
|
}
|
|
237
305
|
|
|
238
|
-
|
|
306
|
+
protected onNodeChange(lf: LogicFlow, model: BaseNodeModel) {
|
|
307
|
+
const connectedSelections = lf.graphModel.nodes.filter((node) => {
|
|
308
|
+
if (!isNodeSelectionModel(node)) {
|
|
309
|
+
return false
|
|
310
|
+
}
|
|
311
|
+
const childIds: string[] = node.properties.node_selection_ids || []
|
|
312
|
+
return childIds.includes(model.id)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
Promise.resolve().then(() => {
|
|
316
|
+
connectedSelections.forEach((node) => {
|
|
317
|
+
node.updatePointsByNodes(node.properties.node_selection_ids || [])
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
render(lf: LogicFlow) {
|
|
239
323
|
this.lf = lf
|
|
240
324
|
|
|
241
325
|
lf.on('node:click', (val) => {
|
|
242
|
-
if (!val.e.shiftKey || val.data.type ===
|
|
326
|
+
if (!val.e.shiftKey || val.data.type === NODE_SELECTION_TYPE) return
|
|
243
327
|
this.currentClickNode = val.data
|
|
244
328
|
|
|
245
329
|
// 如果selectNodesIds中已存在此节点,则取消选中此节点
|
|
246
330
|
let hasExists = false
|
|
247
331
|
if (this.selectNodesIds.includes(val.data.id)) {
|
|
248
|
-
this.lf.getNodeModelById(val.data.id)
|
|
332
|
+
this.lf.getNodeModelById(val.data.id)?.setSelected(false)
|
|
249
333
|
hasExists = true
|
|
250
334
|
}
|
|
251
335
|
|
|
@@ -263,17 +347,34 @@ class NodeSelection {
|
|
|
263
347
|
}
|
|
264
348
|
})
|
|
265
349
|
lf.graphModel.addNodeMoveRules((model, deltaX, deltaY) => {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
350
|
+
this.onNodeChange(lf, model)
|
|
351
|
+
/**
|
|
352
|
+
* 如果移动的是分组,那么分组的子节点也跟着移动。
|
|
353
|
+
* 忽略来自分组resize导致的move
|
|
354
|
+
*/
|
|
355
|
+
if (isNodeSelectionModel(model) && !model.isResize) {
|
|
356
|
+
const nodeIds = model.properties.node_selection_ids || []
|
|
269
357
|
lf.graphModel.moveNodes(nodeIds, deltaX, deltaY, true)
|
|
270
358
|
return true
|
|
271
359
|
}
|
|
272
360
|
return true
|
|
273
361
|
})
|
|
362
|
+
|
|
363
|
+
lf.graphModel.addNodeResizeRules((model) => {
|
|
364
|
+
if (!isNodeSelectionModel(model)) {
|
|
365
|
+
this.onNodeChange(lf, model)
|
|
366
|
+
}
|
|
367
|
+
return true
|
|
368
|
+
})
|
|
274
369
|
}
|
|
275
370
|
}
|
|
276
371
|
|
|
372
|
+
const isNodeSelectionModel = (
|
|
373
|
+
node: BaseNodeModel,
|
|
374
|
+
): node is NodeSelectionModel => {
|
|
375
|
+
return !!(node && (node.type as string) === NODE_SELECTION_TYPE)
|
|
376
|
+
}
|
|
377
|
+
|
|
277
378
|
export default NodeSelection
|
|
278
379
|
|
|
279
380
|
export { NodeSelection }
|
package/src/style/index.less
CHANGED
|
@@ -32,13 +32,12 @@
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
&-editing {
|
|
35
|
-
|
|
36
|
-
outline: none;
|
|
35
|
+
outline: 2px solid #275dc5;
|
|
37
36
|
cursor: text;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
&-hover {
|
|
41
|
-
|
|
40
|
+
outline: 2px dashed #acacac;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
// textOverflowMode
|
|
@@ -57,13 +56,11 @@
|
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
&-wrap {
|
|
60
|
-
width: 100px; /* 根据需要调整宽度 */
|
|
61
59
|
white-space: normal;
|
|
62
60
|
overflow-wrap: break-word; /* 允许单词内换行 */
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
&-nowrap {
|
|
66
|
-
width: 100px; /* 根据需要调整宽度 */
|
|
67
64
|
overflow: visible;
|
|
68
65
|
white-space: nowrap;
|
|
69
66
|
}
|
|
@@ -179,6 +176,7 @@
|
|
|
179
176
|
/* dndpanel */
|
|
180
177
|
.lf-dndpanel {
|
|
181
178
|
position: absolute;
|
|
179
|
+
z-index: 999;
|
|
182
180
|
margin: 5px;
|
|
183
181
|
padding: 15px 5px;
|
|
184
182
|
background: rgb(255 255 255 / 80%);
|
package/src/style/raw.ts
CHANGED
|
@@ -33,12 +33,11 @@ export const content = `@import url('medium-editor/dist/css/medium-editor.min.cs
|
|
|
33
33
|
cursor: move;
|
|
34
34
|
}
|
|
35
35
|
.lf-label-overlay .lf-label-editor-editing {
|
|
36
|
-
|
|
37
|
-
outline: none;
|
|
36
|
+
outline: 2px solid #275dc5;
|
|
38
37
|
cursor: text;
|
|
39
38
|
}
|
|
40
39
|
.lf-label-overlay .lf-label-editor-hover {
|
|
41
|
-
|
|
40
|
+
outline: 2px dashed #acacac;
|
|
42
41
|
}
|
|
43
42
|
.lf-label-overlay .lf-label-editor-clip {
|
|
44
43
|
width: 100px;
|
|
@@ -55,15 +54,11 @@ export const content = `@import url('medium-editor/dist/css/medium-editor.min.cs
|
|
|
55
54
|
text-overflow: ellipsis;
|
|
56
55
|
}
|
|
57
56
|
.lf-label-overlay .lf-label-editor-wrap {
|
|
58
|
-
width: 100px;
|
|
59
|
-
/* 根据需要调整宽度 */
|
|
60
57
|
white-space: normal;
|
|
61
58
|
overflow-wrap: break-word;
|
|
62
59
|
/* 允许单词内换行 */
|
|
63
60
|
}
|
|
64
61
|
.lf-label-overlay .lf-label-editor-nowrap {
|
|
65
|
-
width: 100px;
|
|
66
|
-
/* 根据需要调整宽度 */
|
|
67
62
|
overflow: visible;
|
|
68
63
|
white-space: nowrap;
|
|
69
64
|
}
|
|
@@ -159,6 +154,7 @@ export const content = `@import url('medium-editor/dist/css/medium-editor.min.cs
|
|
|
159
154
|
/* dndpanel */
|
|
160
155
|
.lf-dndpanel {
|
|
161
156
|
position: absolute;
|
|
157
|
+
z-index: 999;
|
|
162
158
|
margin: 5px;
|
|
163
159
|
padding: 15px 5px;
|
|
164
160
|
background: rgba(255, 255, 255, 0.8);
|