@logicflow/extension 2.0.11 → 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 +26 -34
- package/CHANGELOG.md +15 -1
- 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/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/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/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
|
@@ -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);
|
|
@@ -25,6 +25,7 @@ export interface ILabelState {
|
|
|
25
25
|
isEditing: boolean
|
|
26
26
|
isHovered: boolean
|
|
27
27
|
isDragging: boolean
|
|
28
|
+
isSelected: boolean
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
@observer
|
|
@@ -52,6 +53,7 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
52
53
|
isEditing: false,
|
|
53
54
|
isHovered: false,
|
|
54
55
|
isDragging: false,
|
|
56
|
+
isSelected: false,
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -75,35 +77,34 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
75
77
|
const {
|
|
76
78
|
editConfigModel: { nodeTextDraggable },
|
|
77
79
|
} = graphModel
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.
|
|
80
|
+
// 当 label 允许拖拽 且不处于拖拽状态、不处于编辑状态时, StepDrag 开启拖拽
|
|
81
|
+
if (
|
|
82
|
+
(label.draggable ?? nodeTextDraggable) &&
|
|
83
|
+
!this.state.isDragging &&
|
|
84
|
+
!this.state.isEditing
|
|
85
|
+
) {
|
|
82
86
|
this.stepDrag.handleMouseDown(e)
|
|
83
87
|
}
|
|
84
88
|
}
|
|
89
|
+
handleMouseUp = (e: MouseEvent) => {
|
|
90
|
+
if (this.state.isDragging) {
|
|
91
|
+
this.stepDrag.handleMouseUp(e)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
85
94
|
handleDragging = ({ deltaX, deltaY }: IDragParams) => {
|
|
86
|
-
|
|
95
|
+
if (!this.state.isDragging) {
|
|
96
|
+
this.setState({ isDragging: true })
|
|
97
|
+
}
|
|
98
|
+
const { label, graphModel } = this.props
|
|
87
99
|
|
|
88
100
|
// DONE: 添加缩放时拖拽的逻辑,对 deltaX 和 deltaY 进行按比例缩放
|
|
89
101
|
const { transformModel } = graphModel
|
|
90
102
|
const [curDeltaX, curDeltaY] = transformModel.fixDeltaXY(deltaX, deltaY)
|
|
91
103
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
const elementLabel = _label as LabelConfig[]
|
|
97
|
-
const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
|
|
98
|
-
|
|
99
|
-
const target = elementLabel[idx]
|
|
100
|
-
elementLabel[idx] = {
|
|
101
|
-
...target,
|
|
102
|
-
x: target.x + curDeltaX,
|
|
103
|
-
y: target.y + curDeltaY,
|
|
104
|
-
}
|
|
105
|
-
const targetElem = graphModel.getElement(element.id)
|
|
106
|
-
targetElem?.setProperty('_label', elementLabel)
|
|
104
|
+
this.setElementModelLabelInfo({
|
|
105
|
+
x: label.x + curDeltaX,
|
|
106
|
+
y: label.y + curDeltaY,
|
|
107
|
+
})
|
|
107
108
|
|
|
108
109
|
graphModel.eventCenter.emit('label:drag', {
|
|
109
110
|
data: label.getData(),
|
|
@@ -114,6 +115,21 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
114
115
|
this.setState({ isDragging: false })
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
handleClick = (e: MouseEvent) => {
|
|
119
|
+
const { label, element, graphModel } = this.props
|
|
120
|
+
// 更新当前Label选中状态
|
|
121
|
+
element.setSelected(!this.state.isSelected)
|
|
122
|
+
this.setState({ isSelected: !this.state.isSelected })
|
|
123
|
+
this.setElementModelLabelInfo({
|
|
124
|
+
isSelected: true,
|
|
125
|
+
})
|
|
126
|
+
graphModel.eventCenter.emit('label:click', {
|
|
127
|
+
data: label.getData(),
|
|
128
|
+
e,
|
|
129
|
+
model: element,
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
117
133
|
handleDbClick = (e: MouseEvent) => {
|
|
118
134
|
const { label, element, graphModel } = this.props
|
|
119
135
|
graphModel.eventCenter.emit('label:dblclick', {
|
|
@@ -162,9 +178,28 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
162
178
|
this.setState({
|
|
163
179
|
isDragging: false,
|
|
164
180
|
isHovered: false,
|
|
181
|
+
isSelected: false,
|
|
165
182
|
})
|
|
166
183
|
}
|
|
167
184
|
|
|
185
|
+
setElementModelLabelInfo(data) {
|
|
186
|
+
const { label, element, graphModel } = this.props
|
|
187
|
+
const {
|
|
188
|
+
properties: { _label },
|
|
189
|
+
} = element
|
|
190
|
+
const elementLabel = _label as LabelConfig[]
|
|
191
|
+
const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
|
|
192
|
+
|
|
193
|
+
const target = elementLabel[idx]
|
|
194
|
+
elementLabel[idx] = {
|
|
195
|
+
...target,
|
|
196
|
+
...data,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const targetElem = graphModel.getElement(element.id)
|
|
200
|
+
targetElem?.setProperty('_label', elementLabel)
|
|
201
|
+
}
|
|
202
|
+
|
|
168
203
|
// 重新计算 Label 大小
|
|
169
204
|
reCalcLabelSize = () => {}
|
|
170
205
|
|
|
@@ -175,37 +210,49 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
175
210
|
const { label, element, graphModel } = this.props
|
|
176
211
|
|
|
177
212
|
// 在点击元素、边或者画布 时,结束 Label 的编辑态
|
|
178
|
-
graphModel.eventCenter.on(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const elementLabel = _label as LabelConfig[]
|
|
190
|
-
const idx = findIndex(elementLabel, (cur) => cur.id === label.id)
|
|
191
|
-
|
|
192
|
-
const target = elementLabel[idx]
|
|
193
|
-
elementLabel[idx] = {
|
|
194
|
-
...target,
|
|
195
|
-
value,
|
|
196
|
-
content,
|
|
213
|
+
graphModel.eventCenter.on(
|
|
214
|
+
'blank:click,node:click,edge:click,label:click',
|
|
215
|
+
({ data }) => {
|
|
216
|
+
// 点击的不是label 、点击的不是当前label、点击的是当前label,且当前 label 处于选中态
|
|
217
|
+
// 则取消选中态
|
|
218
|
+
if (
|
|
219
|
+
data?.type !== 'label' ||
|
|
220
|
+
(data.type === 'label' && data.id !== label.id) ||
|
|
221
|
+
this.state.isSelected
|
|
222
|
+
) {
|
|
223
|
+
this.setState({ isSelected: false })
|
|
197
224
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
225
|
+
// 点击的不是label 、点击的不是当前label、点击的是当前label,且当前 label 处于编辑态
|
|
226
|
+
// 则结束编辑态
|
|
227
|
+
if (
|
|
228
|
+
(data?.type !== 'label' ||
|
|
229
|
+
(data.type == 'label' && data.id !== label.id)) &&
|
|
230
|
+
this.state.isEditing
|
|
231
|
+
) {
|
|
232
|
+
this.setState({ isEditing: false })
|
|
233
|
+
|
|
234
|
+
const value = this.textRef.current?.innerText ?? ''
|
|
235
|
+
const content = this.textRef.current?.innerHTML ?? ''
|
|
236
|
+
|
|
237
|
+
this.setElementModelLabelInfo({
|
|
238
|
+
value,
|
|
239
|
+
content,
|
|
240
|
+
isSelected: false,
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
element.setElementState(ElementState.DEFAULT)
|
|
244
|
+
}
|
|
245
|
+
// 点击的不是label 、点击的不是当前label、点击的是当前label,且当前 label 的文本DOM存在
|
|
246
|
+
// 则结束文本DOM的编辑态
|
|
247
|
+
if (
|
|
248
|
+
(data?.type !== 'label' ||
|
|
249
|
+
(data.type == 'label' && data.id !== label.id)) &&
|
|
250
|
+
this.textRef.current
|
|
251
|
+
) {
|
|
252
|
+
this.textRef.current.contentEditable = 'false'
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
)
|
|
209
256
|
// TODO: 节点拖拽结束后,更新 Label 的位置
|
|
210
257
|
// eventCenter.on('node:drag', () => {})
|
|
211
258
|
// eventCenter.on('node:drop', () => {})
|
|
@@ -216,7 +263,7 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
216
263
|
|
|
217
264
|
componentDidUpdate() {
|
|
218
265
|
// snapshot: any, // previousState: Readonly<ILabelState>, // previousProps: Readonly<ILabelProps>,
|
|
219
|
-
console.log('Label componentDidUpdate')
|
|
266
|
+
// console.log('Label componentDidUpdate')
|
|
220
267
|
// console.log('previousProps', previousProps)
|
|
221
268
|
// console.log('previousState', previousState)
|
|
222
269
|
// console.log('snapshot', snapshot)
|
|
@@ -232,7 +279,7 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
232
279
|
|
|
233
280
|
render() {
|
|
234
281
|
const { label, element, graphModel } = this.props
|
|
235
|
-
const { isDragging, isHovered, isEditing } = this.state
|
|
282
|
+
const { isDragging, isHovered, isSelected, isEditing } = this.state
|
|
236
283
|
const { transformModel } = graphModel
|
|
237
284
|
const { transform } = transformModel.getTransformStyle()
|
|
238
285
|
const {
|
|
@@ -260,13 +307,14 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
260
307
|
? `${transform} rotate(${rotate}deg)`
|
|
261
308
|
: `${transform} rotate(${vertical ? -0.25 : 0}turn)`,
|
|
262
309
|
}
|
|
263
|
-
|
|
264
310
|
return (
|
|
265
311
|
<div
|
|
266
312
|
id={`element-container-${id}`}
|
|
267
313
|
className={classNames('lf-label-editor-container')}
|
|
268
314
|
style={containerStyle}
|
|
269
315
|
onMouseDown={this.handleMouseDown}
|
|
316
|
+
onMouseUp={this.handleMouseUp}
|
|
317
|
+
onClick={this.handleClick}
|
|
270
318
|
onDblClick={this.handleDbClick}
|
|
271
319
|
onBlur={this.handleBlur}
|
|
272
320
|
onMouseEnter={this.setHoverOn}
|
|
@@ -279,12 +327,15 @@ export class Label extends Component<ILabelProps, ILabelState> {
|
|
|
279
327
|
className={classNames('lf-label-editor', {
|
|
280
328
|
'lf-label-editor-dragging': isDragging,
|
|
281
329
|
'lf-label-editor-editing': isEditing,
|
|
282
|
-
'lf-label-editor-hover': !isEditing && isHovered,
|
|
330
|
+
'lf-label-editor-hover': !isEditing && (isHovered || isSelected),
|
|
283
331
|
[`lf-label-editor-${textOverflowMode}`]: !isEditing,
|
|
284
332
|
})}
|
|
285
333
|
style={{
|
|
286
334
|
maxWidth: `${maxLabelWidth}px`,
|
|
287
|
-
|
|
335
|
+
boxSizing: 'border-box',
|
|
336
|
+
display: 'inline-block',
|
|
337
|
+
background:
|
|
338
|
+
isEditing || element.BaseType === 'edge' ? '#fff' : 'transparent',
|
|
288
339
|
...style,
|
|
289
340
|
}}
|
|
290
341
|
dangerouslySetInnerHTML={{ __html: content }}
|
package/src/tools/label/index.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import LogicFlow, { createUuid, GraphModel, TextMode } from '@logicflow/core'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
cloneDeep,
|
|
4
|
+
forEach,
|
|
5
|
+
isArray,
|
|
6
|
+
isEmpty,
|
|
7
|
+
isEqual,
|
|
8
|
+
isObject,
|
|
9
|
+
map,
|
|
10
|
+
} from 'lodash-es'
|
|
3
11
|
import LabelOverlay, { LabelConfigType } from './LabelOverlay'
|
|
4
12
|
import {
|
|
5
13
|
BBoxInfo,
|
|
@@ -53,7 +61,7 @@ export class Label implements Extension {
|
|
|
53
61
|
this.addEventListeners()
|
|
54
62
|
|
|
55
63
|
// TODO: 3. 自定义快捷键,比如 delete,选中 label 时,移除 label
|
|
56
|
-
|
|
64
|
+
this.rewriteShortcut()
|
|
57
65
|
|
|
58
66
|
// 插件中注册 LabelOverlay 工具,用于 label 的编辑
|
|
59
67
|
lf.tool.registerTool(LabelOverlay.toolName, LabelOverlay)
|
|
@@ -377,7 +385,60 @@ export class Label implements Extension {
|
|
|
377
385
|
// TODO: others methods ???
|
|
378
386
|
}
|
|
379
387
|
|
|
380
|
-
|
|
388
|
+
private rewriteShortcut() {
|
|
389
|
+
const { keyboard, graphModel } = this.lf
|
|
390
|
+
const {
|
|
391
|
+
options: { keyboard: keyboardOptions },
|
|
392
|
+
} = keyboard
|
|
393
|
+
keyboard.off(['backspace'])
|
|
394
|
+
keyboard.on(['backspace'], () => {
|
|
395
|
+
if (!keyboardOptions?.enabled) return true
|
|
396
|
+
if (graphModel.textEditElement) return true
|
|
397
|
+
const elements = graphModel.getSelectElements(true)
|
|
398
|
+
this.lf.clearSelectElements()
|
|
399
|
+
const {
|
|
400
|
+
graphModel: { editConfigModel },
|
|
401
|
+
} = this.lf
|
|
402
|
+
elements.edges.forEach((edge) => {
|
|
403
|
+
const { properties } = edge
|
|
404
|
+
if (
|
|
405
|
+
properties &&
|
|
406
|
+
!isEmpty(properties._label) &&
|
|
407
|
+
editConfigModel.textMode === TextMode.LABEL
|
|
408
|
+
) {
|
|
409
|
+
const newLabelList = properties._label.filter(
|
|
410
|
+
(label) => !label.isSelected,
|
|
411
|
+
)
|
|
412
|
+
// 如果两个labelList长度不一致,说明有选中的元素,此时backspace做的动作是删除label
|
|
413
|
+
if (!isEqual(newLabelList.length, properties._label.length)) {
|
|
414
|
+
const edgeModel = graphModel.getEdgeModelById(edge.id)
|
|
415
|
+
edgeModel?.setProperty('_label', newLabelList)
|
|
416
|
+
return
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
edge.id && this.lf.deleteEdge(edge.id)
|
|
420
|
+
})
|
|
421
|
+
elements.nodes.forEach((node) => {
|
|
422
|
+
const { properties } = node
|
|
423
|
+
if (
|
|
424
|
+
properties &&
|
|
425
|
+
!isEmpty(properties._label) &&
|
|
426
|
+
editConfigModel.textMode === TextMode.LABEL
|
|
427
|
+
) {
|
|
428
|
+
const newLabelList = properties._label.filter(
|
|
429
|
+
(label) => !label.isSelected,
|
|
430
|
+
)
|
|
431
|
+
if (!isEqual(newLabelList.length, properties._label.length)) {
|
|
432
|
+
const nodeModel = graphModel.getNodeModelById(node.id)
|
|
433
|
+
nodeModel?.setProperty('_label', newLabelList)
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
node.id && this.lf.deleteNode(node.id)
|
|
438
|
+
})
|
|
439
|
+
return false
|
|
440
|
+
})
|
|
441
|
+
}
|
|
381
442
|
|
|
382
443
|
/**
|
|
383
444
|
* 更新当前渲染使用的 Text or Label 模式
|