@logicflow/extension 2.0.16 → 2.0.18
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 +7 -7
- package/CHANGELOG.md +14 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/es/components/highlight/index.js +19 -3
- package/es/components/selection-select/index.d.ts +25 -3
- package/es/components/selection-select/index.js +215 -77
- package/es/dynamic-group/index.js +0 -11
- package/es/materials/group/GroupNode.js +0 -1
- package/es/style/raw.d.ts +1 -1
- package/es/style/raw.js +1 -1
- package/es/tools/proximity-connect/index.js +25 -4
- package/es/tools/snapshot/index.d.ts +47 -20
- package/es/tools/snapshot/index.js +459 -246
- package/lib/components/highlight/index.js +18 -2
- package/lib/components/selection-select/index.d.ts +25 -3
- package/lib/components/selection-select/index.js +215 -77
- package/lib/dynamic-group/index.js +0 -11
- package/lib/materials/group/GroupNode.js +0 -1
- package/lib/style/raw.d.ts +1 -1
- package/lib/style/raw.js +1 -1
- package/lib/tools/proximity-connect/index.js +24 -3
- package/lib/tools/snapshot/index.d.ts +47 -20
- package/lib/tools/snapshot/index.js +459 -246
- package/package.json +3 -3
- package/src/components/highlight/index.ts +30 -5
- package/src/components/selection-select/index.ts +198 -64
- package/src/dynamic-group/index.ts +0 -12
- package/src/materials/group/GroupNode.ts +0 -1
- package/src/style/raw.ts +4 -0
- package/src/tools/proximity-connect/index.ts +30 -3
- package/src/tools/snapshot/index.ts +325 -152
- package/stats.html +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logicflow/extension",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.18",
|
|
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.
|
|
23
|
+
"@logicflow/core": "2.0.13"
|
|
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.
|
|
34
|
+
"@logicflow/core": "2.0.13"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"less": "^4.1.1",
|
|
@@ -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
|
-
|
|
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
|
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import LogicFlow from '@logicflow/core'
|
|
2
|
+
import { cloneDeep } from 'lodash-es'
|
|
2
3
|
|
|
3
4
|
import Position = LogicFlow.Position
|
|
4
5
|
import PointTuple = LogicFlow.PointTuple
|
|
5
6
|
|
|
7
|
+
export interface SelectionConfig {
|
|
8
|
+
exclusiveMode?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
export class SelectionSelect {
|
|
7
12
|
static pluginName = 'selectionSelect'
|
|
8
13
|
private container?: HTMLElement
|
|
@@ -13,15 +18,25 @@ export class SelectionSelect {
|
|
|
13
18
|
private disabled = true
|
|
14
19
|
private isWholeNode = true
|
|
15
20
|
private isWholeEdge = true
|
|
21
|
+
exclusiveMode = false // 框选独占模式:true 表示只能进行框选操作,false 表示可以同时进行其他画布操作
|
|
16
22
|
// 用于区分选区和点击事件
|
|
17
23
|
private mouseDownInfo: {
|
|
18
24
|
x: number
|
|
19
25
|
y: number
|
|
20
26
|
time: number
|
|
21
27
|
} | null = null
|
|
28
|
+
// 记录原始的 stopMoveGraph 设置
|
|
29
|
+
private originalStopMoveGraph:
|
|
30
|
+
| boolean
|
|
31
|
+
| 'horizontal'
|
|
32
|
+
| 'vertical'
|
|
33
|
+
| [number, number, number, number] = false
|
|
22
34
|
|
|
23
|
-
constructor({ lf }: LogicFlow.IExtensionProps) {
|
|
35
|
+
constructor({ lf, options }: LogicFlow.IExtensionProps) {
|
|
24
36
|
this.lf = lf
|
|
37
|
+
|
|
38
|
+
this.exclusiveMode = (options?.exclusiveMode as boolean) ?? false
|
|
39
|
+
|
|
25
40
|
// TODO: 有没有既能将方法挂载到lf上,又能提供类型提示的方法?
|
|
26
41
|
lf.openSelectionSelect = () => {
|
|
27
42
|
this.openSelectionSelect()
|
|
@@ -29,46 +44,119 @@ export class SelectionSelect {
|
|
|
29
44
|
lf.closeSelectionSelect = () => {
|
|
30
45
|
this.closeSelectionSelect()
|
|
31
46
|
}
|
|
47
|
+
// 新增切换独占模式的方法
|
|
48
|
+
lf.setSelectionSelectMode = (exclusive: boolean) => {
|
|
49
|
+
this.setExclusiveMode(exclusive)
|
|
50
|
+
}
|
|
51
|
+
// 绑定方法的 this 上下文
|
|
52
|
+
this.handleMouseDown = this.handleMouseDown.bind(this)
|
|
53
|
+
this.draw = this.draw.bind(this)
|
|
54
|
+
this.drawOff = this.drawOff.bind(this)
|
|
32
55
|
}
|
|
33
56
|
|
|
34
57
|
render(_: LogicFlow, domContainer: HTMLElement) {
|
|
35
58
|
this.container = domContainer
|
|
36
59
|
}
|
|
37
60
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
/**
|
|
62
|
+
* 清理选区状态
|
|
63
|
+
*/
|
|
64
|
+
private cleanupSelectionState() {
|
|
65
|
+
// 清理当前的选区状态
|
|
66
|
+
if (this.wrapper) {
|
|
67
|
+
this.wrapper.oncontextmenu = null
|
|
68
|
+
if (this.container && this.wrapper.parentNode === this.container) {
|
|
69
|
+
this.container.removeChild(this.wrapper)
|
|
70
|
+
}
|
|
71
|
+
this.wrapper = undefined
|
|
42
72
|
}
|
|
43
|
-
this.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
73
|
+
this.startPoint = undefined
|
|
74
|
+
this.endPoint = undefined
|
|
75
|
+
this.mouseDownInfo = null
|
|
76
|
+
|
|
77
|
+
// 移除事件监听
|
|
78
|
+
document.removeEventListener('mousemove', this.draw)
|
|
79
|
+
document.removeEventListener('mouseup', this.drawOff)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 切换框选模式
|
|
84
|
+
* @param exclusive 是否为独占模式。true 表示只能进行框选操作,false 表示可以同时进行其他画布操作
|
|
85
|
+
*/
|
|
86
|
+
setExclusiveMode(exclusive: boolean = false) {
|
|
87
|
+
if (this.exclusiveMode === exclusive) return
|
|
88
|
+
|
|
89
|
+
this.cleanupSelectionState()
|
|
90
|
+
this.exclusiveMode = exclusive
|
|
91
|
+
if (this.container && !this.disabled) {
|
|
92
|
+
// 切换事件监听方式
|
|
93
|
+
this.removeEventListeners()
|
|
94
|
+
this.addEventListeners()
|
|
47
95
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private addEventListeners() {
|
|
99
|
+
if (!this.container) return
|
|
100
|
+
|
|
101
|
+
if (this.exclusiveMode) {
|
|
102
|
+
// 独占模式:监听 container 的 mousedown 事件
|
|
103
|
+
this.container.style.pointerEvents = 'auto'
|
|
104
|
+
this.container.addEventListener('mousedown', this.handleMouseDown)
|
|
105
|
+
} else {
|
|
106
|
+
// 非独占模式:监听画布的 blank:mousedown 事件
|
|
107
|
+
this.container.style.pointerEvents = 'none'
|
|
108
|
+
// 使用实例方法而不是箭头函数,这样可以正确移除事件监听
|
|
109
|
+
this.lf.on('blank:mousedown', this.handleBlankMouseDown)
|
|
52
110
|
}
|
|
53
|
-
|
|
54
|
-
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private removeEventListeners() {
|
|
114
|
+
if (this.container) {
|
|
115
|
+
this.container.style.pointerEvents = 'none'
|
|
116
|
+
this.container.removeEventListener('mousedown', this.handleMouseDown)
|
|
55
117
|
}
|
|
56
|
-
//
|
|
118
|
+
// 移除 blank:mousedown 事件监听
|
|
119
|
+
this.lf.off('blank:mousedown', this.handleBlankMouseDown)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 处理画布空白处鼠标按下事件(非独占模式)
|
|
124
|
+
*/
|
|
125
|
+
private handleBlankMouseDown = ({ e }: { e: MouseEvent }) => {
|
|
126
|
+
this.handleMouseDown(e)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 处理鼠标按下事件
|
|
131
|
+
*/
|
|
132
|
+
private handleMouseDown(e: MouseEvent) {
|
|
133
|
+
if (!this.container || this.disabled) return
|
|
134
|
+
|
|
135
|
+
// 禁用右键框选
|
|
57
136
|
const isRightClick = e.button === 2
|
|
58
|
-
if (isRightClick)
|
|
59
|
-
|
|
137
|
+
if (isRightClick) return
|
|
138
|
+
// 清理之前可能存在的选区状态
|
|
139
|
+
this.cleanupSelectionState()
|
|
140
|
+
// 记录鼠标按下时的位置和时间
|
|
141
|
+
this.mouseDownInfo = {
|
|
142
|
+
x: e.clientX,
|
|
143
|
+
y: e.clientY,
|
|
144
|
+
time: Date.now(),
|
|
60
145
|
}
|
|
146
|
+
|
|
147
|
+
// 记录原始设置并临时禁止画布移动
|
|
148
|
+
this.originalStopMoveGraph = this.lf.getEditConfig().stopMoveGraph!
|
|
149
|
+
this.lf.updateEditConfig({
|
|
150
|
+
stopMoveGraph: true,
|
|
151
|
+
})
|
|
152
|
+
|
|
61
153
|
const {
|
|
62
154
|
domOverlayPosition: { x, y },
|
|
63
|
-
} = lf.getPointByClient(e.clientX, e.clientY)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.endPoint = {
|
|
69
|
-
x,
|
|
70
|
-
y,
|
|
71
|
-
}
|
|
155
|
+
} = this.lf.getPointByClient(e.clientX, e.clientY)
|
|
156
|
+
|
|
157
|
+
this.startPoint = { x, y }
|
|
158
|
+
this.endPoint = { x, y }
|
|
159
|
+
|
|
72
160
|
const wrapper = document.createElement('div')
|
|
73
161
|
wrapper.className = 'lf-selection-select'
|
|
74
162
|
wrapper.oncontextmenu = function prevent(ev: MouseEvent) {
|
|
@@ -76,28 +164,13 @@ export class SelectionSelect {
|
|
|
76
164
|
}
|
|
77
165
|
wrapper.style.top = `${this.startPoint.y}px`
|
|
78
166
|
wrapper.style.left = `${this.startPoint.x}px`
|
|
79
|
-
|
|
167
|
+
this.container?.appendChild(wrapper)
|
|
80
168
|
this.wrapper = wrapper
|
|
169
|
+
|
|
81
170
|
document.addEventListener('mousemove', this.draw)
|
|
82
171
|
document.addEventListener('mouseup', this.drawOff)
|
|
83
172
|
}
|
|
84
173
|
|
|
85
|
-
onToolContainerMouseUp = (e: MouseEvent) => {
|
|
86
|
-
if (this.mouseDownInfo) {
|
|
87
|
-
const { x, y, time } = this.mouseDownInfo
|
|
88
|
-
const now = Date.now()
|
|
89
|
-
// 用 mouseDown 和 mouseUp 的位置偏移及时间间隔来判断是否是点击事件
|
|
90
|
-
const isClickEvent =
|
|
91
|
-
Math.abs(e.clientX - x) < 10 &&
|
|
92
|
-
Math.abs(e.clientY - y) < 10 &&
|
|
93
|
-
now - time < 100
|
|
94
|
-
if (isClickEvent) {
|
|
95
|
-
this.lf.clearSelectElements()
|
|
96
|
-
}
|
|
97
|
-
this.mouseDownInfo = null
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
174
|
/**
|
|
102
175
|
* 设置选中的灵敏度
|
|
103
176
|
* @param isWholeEdge 是否要边的起点终点都在选区范围才算选中。默认true
|
|
@@ -118,11 +191,8 @@ export class SelectionSelect {
|
|
|
118
191
|
if (!this.container) {
|
|
119
192
|
return
|
|
120
193
|
}
|
|
121
|
-
this.
|
|
122
|
-
this.
|
|
123
|
-
this.container.addEventListener('mouseup', this.onToolContainerMouseUp)
|
|
124
|
-
// 取消点击事件的穿透,只让 ToolOverlay 接收事件,避免与图形元素的事件冲突
|
|
125
|
-
this.container.style.pointerEvents = 'auto'
|
|
194
|
+
this.cleanupSelectionState()
|
|
195
|
+
this.addEventListeners()
|
|
126
196
|
this.open()
|
|
127
197
|
}
|
|
128
198
|
|
|
@@ -133,13 +203,18 @@ export class SelectionSelect {
|
|
|
133
203
|
if (!this.container) {
|
|
134
204
|
return
|
|
135
205
|
}
|
|
136
|
-
|
|
137
|
-
this.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
206
|
+
// 如果还有未完成的框选,先触发 drawOff 完成框选
|
|
207
|
+
if (this.wrapper && this.startPoint && this.endPoint) {
|
|
208
|
+
// 记录上一次的结束点,用于触发 mouseup 事件
|
|
209
|
+
const lastEndPoint = cloneDeep(this.endPoint)
|
|
210
|
+
const lastEvent = new MouseEvent('mouseup', {
|
|
211
|
+
clientX: lastEndPoint.x,
|
|
212
|
+
clientY: lastEndPoint.y,
|
|
213
|
+
})
|
|
214
|
+
this.drawOff(lastEvent)
|
|
215
|
+
}
|
|
216
|
+
this.cleanupSelectionState()
|
|
217
|
+
this.removeEventListeners()
|
|
143
218
|
this.close()
|
|
144
219
|
}
|
|
145
220
|
|
|
@@ -173,16 +248,37 @@ export class SelectionSelect {
|
|
|
173
248
|
}
|
|
174
249
|
}
|
|
175
250
|
}
|
|
176
|
-
private drawOff = () => {
|
|
251
|
+
private drawOff = (e: MouseEvent) => {
|
|
252
|
+
// 处理鼠标抬起事件
|
|
253
|
+
// 首先判断是否是点击,如果是,则清空框选
|
|
254
|
+
if (this.mouseDownInfo) {
|
|
255
|
+
const { x, y, time } = this.mouseDownInfo
|
|
256
|
+
const isClick =
|
|
257
|
+
Math.abs(e.clientX - x) < 5 &&
|
|
258
|
+
Math.abs(e.clientY - y) < 5 &&
|
|
259
|
+
Date.now() - time < 200
|
|
260
|
+
if (isClick) {
|
|
261
|
+
this.lf.clearSelectElements()
|
|
262
|
+
this.cleanupSelectionState()
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const curStartPoint = cloneDeep(this.startPoint)
|
|
268
|
+
const curEndPoint = cloneDeep(this.endPoint)
|
|
177
269
|
document.removeEventListener('mousemove', this.draw)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
this.wrapper.oncontextmenu = null
|
|
181
|
-
this.container?.removeChild(this.wrapper)
|
|
270
|
+
if (!this.exclusiveMode) {
|
|
271
|
+
document.removeEventListener('mouseup', this.drawOff)
|
|
182
272
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
273
|
+
|
|
274
|
+
// 恢复原始的 stopMoveGraph 设置
|
|
275
|
+
this.lf.updateEditConfig({
|
|
276
|
+
stopMoveGraph: this.originalStopMoveGraph,
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
if (curStartPoint && curEndPoint) {
|
|
280
|
+
const { x, y } = curStartPoint
|
|
281
|
+
const { x: x1, y: y1 } = curEndPoint
|
|
186
282
|
// 返回框选范围,左上角和右下角的坐标
|
|
187
283
|
const lt: PointTuple = [Math.min(x, x1), Math.min(y, y1)]
|
|
188
284
|
const rb: PointTuple = [Math.max(x, x1), Math.max(y, y1)]
|
|
@@ -192,6 +288,13 @@ export class SelectionSelect {
|
|
|
192
288
|
})
|
|
193
289
|
// 选区太小的情况就忽略
|
|
194
290
|
if (Math.abs(x1 - x) < 10 && Math.abs(y1 - y) < 10) {
|
|
291
|
+
if (this.wrapper) {
|
|
292
|
+
this.wrapper.oncontextmenu = null
|
|
293
|
+
if (this.container && this.wrapper.parentNode === this.container) {
|
|
294
|
+
this.container.removeChild(this.wrapper)
|
|
295
|
+
}
|
|
296
|
+
this.wrapper = undefined
|
|
297
|
+
}
|
|
195
298
|
return
|
|
196
299
|
}
|
|
197
300
|
const elements = this.lf.graphModel.getAreaElement(
|
|
@@ -203,6 +306,13 @@ export class SelectionSelect {
|
|
|
203
306
|
)
|
|
204
307
|
const { dynamicGroup, group } = this.lf.graphModel
|
|
205
308
|
const nonGroupedElements: typeof elements = []
|
|
309
|
+
const selectedElements = this.lf.getSelectElements()
|
|
310
|
+
// 同时记录节点和边的ID
|
|
311
|
+
const selectedIds = new Set([
|
|
312
|
+
...selectedElements.nodes.map((node) => node.id),
|
|
313
|
+
...selectedElements.edges.map((edge) => edge.id),
|
|
314
|
+
])
|
|
315
|
+
|
|
206
316
|
elements.forEach((element) => {
|
|
207
317
|
// 如果节点属于分组,则不选中节点,此处兼容旧版 Group 插件
|
|
208
318
|
if (group) {
|
|
@@ -219,15 +329,39 @@ export class SelectionSelect {
|
|
|
219
329
|
return
|
|
220
330
|
}
|
|
221
331
|
}
|
|
332
|
+
// 在独占模式下,如果元素已经被选中,则取消选中
|
|
333
|
+
if (this.exclusiveMode && selectedIds.has(element.id)) {
|
|
334
|
+
this.lf.deselectElementById(element.id)
|
|
335
|
+
return
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 非独占模式下,或者元素未被选中时,选中元素
|
|
222
339
|
this.lf.selectElementById(element.id, true)
|
|
223
340
|
nonGroupedElements.push(element)
|
|
224
341
|
})
|
|
342
|
+
// 重置起始点和终点
|
|
343
|
+
// 注意:这两个值必须在触发closeSelectionSelect方法前充值,否则会导致独占模式下元素无法选中的问题
|
|
344
|
+
this.startPoint = undefined
|
|
345
|
+
this.endPoint = undefined
|
|
346
|
+
// 如果有选中的元素,触发 selection:drop 事件
|
|
347
|
+
if (nonGroupedElements.length > 0) {
|
|
348
|
+
this.lf.emit('selection:drop', { e })
|
|
349
|
+
}
|
|
350
|
+
// 触发 selection:selected 事件
|
|
225
351
|
this.lf.emit('selection:selected', {
|
|
226
352
|
elements: nonGroupedElements,
|
|
227
353
|
leftTopPoint: lt,
|
|
228
354
|
rightBottomPoint: rb,
|
|
229
355
|
})
|
|
230
356
|
}
|
|
357
|
+
|
|
358
|
+
if (this.wrapper) {
|
|
359
|
+
this.wrapper.oncontextmenu = null
|
|
360
|
+
if (this.container && this.wrapper.parentNode === this.container) {
|
|
361
|
+
this.container.removeChild(this.wrapper)
|
|
362
|
+
}
|
|
363
|
+
this.wrapper = undefined
|
|
364
|
+
}
|
|
231
365
|
}
|
|
232
366
|
|
|
233
367
|
private open() {
|
|
@@ -236,7 +236,6 @@ export class DynamicGroup {
|
|
|
236
236
|
const group = this.getGroupByBounds(bounds, node)
|
|
237
237
|
if (group) {
|
|
238
238
|
const isAllowAppendIn = group.isAllowAppendIn(node)
|
|
239
|
-
console.log('isAllowAppendIn', isAllowAppendIn)
|
|
240
239
|
if (isAllowAppendIn) {
|
|
241
240
|
group.addChild(node.id)
|
|
242
241
|
// 建立节点与 group 的映射关系放在了 group.addChild 触发的事件中,与直接调用 addChild 的行为保持一致
|
|
@@ -256,7 +255,6 @@ export class DynamicGroup {
|
|
|
256
255
|
data: groupData,
|
|
257
256
|
childId,
|
|
258
257
|
}: CallbackArgs<'group:add-node'>) => {
|
|
259
|
-
console.log('group:add-node', groupData)
|
|
260
258
|
this.nodeGroupMap.set(childId, groupData.id)
|
|
261
259
|
}
|
|
262
260
|
|
|
@@ -310,7 +308,6 @@ export class DynamicGroup {
|
|
|
310
308
|
if (!isAllowAppendIn) return
|
|
311
309
|
|
|
312
310
|
this.activeGroup = targetGroup
|
|
313
|
-
console.log('this.activeGroup', this.activeGroup)
|
|
314
311
|
this.activeGroup.setAllowAppendChild(true)
|
|
315
312
|
}
|
|
316
313
|
}
|
|
@@ -439,7 +436,6 @@ export class DynamicGroup {
|
|
|
439
436
|
}
|
|
440
437
|
|
|
441
438
|
onGraphRendered = ({ data }: CallbackArgs<'graph:rendered'>) => {
|
|
442
|
-
console.log('data', data)
|
|
443
439
|
forEach(data.nodes, (node) => {
|
|
444
440
|
if (node.children) {
|
|
445
441
|
forEach(node.children, (childId) => {
|
|
@@ -517,9 +513,6 @@ export class DynamicGroup {
|
|
|
517
513
|
}
|
|
518
514
|
})
|
|
519
515
|
|
|
520
|
-
// TODO: 确认,递归的方式,是否将所有嵌套的边数据都有返回
|
|
521
|
-
console.log('allRelatedEdges -->>', allRelatedEdges)
|
|
522
|
-
|
|
523
516
|
// 1. 判断每一条边的开始节点、目标节点是否在 Group 中
|
|
524
517
|
const edgesInnerGroup = filter(allRelatedEdges, (edge) => {
|
|
525
518
|
return (
|
|
@@ -684,7 +677,6 @@ export class DynamicGroup {
|
|
|
684
677
|
})
|
|
685
678
|
|
|
686
679
|
graphModel.dynamicGroup = this
|
|
687
|
-
|
|
688
680
|
lf.on('node:add,node:drop,node:dnd-add', this.onNodeAddOrDrop)
|
|
689
681
|
lf.on('selection:drop', this.onSelectionDrop)
|
|
690
682
|
lf.on('node:delete', this.removeNodeFromGroup)
|
|
@@ -694,8 +686,6 @@ export class DynamicGroup {
|
|
|
694
686
|
lf.on('node:mousemove', this.onNodeMove)
|
|
695
687
|
lf.on('graph:rendered', this.onGraphRendered)
|
|
696
688
|
|
|
697
|
-
lf.on('graph:updated', ({ data }) => console.log('data', data))
|
|
698
|
-
|
|
699
689
|
lf.on('group:add-node', this.onGroupAddNode)
|
|
700
690
|
|
|
701
691
|
// https://github.com/didi/LogicFlow/issues/1346
|
|
@@ -739,8 +729,6 @@ export class DynamicGroup {
|
|
|
739
729
|
forEach(edgesInnerGroup, (edge) => {
|
|
740
730
|
this.createEdge(edge, nodeIdMap, distance)
|
|
741
731
|
})
|
|
742
|
-
|
|
743
|
-
console.log('selectedEdges --->>>', selectedEdges)
|
|
744
732
|
forEach(selectedEdges, (edge) => {
|
|
745
733
|
elements.edges.push(this.createEdge(edge, nodeIdMap, distance))
|
|
746
734
|
})
|
|
@@ -321,7 +321,6 @@ export class GroupNodeModel extends RectResizeModel {
|
|
|
321
321
|
getData() {
|
|
322
322
|
const data = super.getData()
|
|
323
323
|
data.children = []
|
|
324
|
-
console.log('this.children', this.children)
|
|
325
324
|
this.children.forEach((childId) => {
|
|
326
325
|
const model = this.graphModel.getNodeModelById(childId)
|
|
327
326
|
if (model && !model.virtual) {
|
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;
|
|
@@ -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
|
|
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
|
}
|