@logicflow/core 2.1.3 → 2.2.0
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$colon$dev.log +2 -2
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +15 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/es/LogicFlow.d.ts +2 -1
- package/es/LogicFlow.js +4 -1
- package/es/constant/index.d.ts +3 -1
- package/es/constant/index.js +2 -0
- package/es/model/EditConfigModel.d.ts +3 -1
- package/es/model/EditConfigModel.js +5 -0
- package/es/model/GraphModel.d.ts +9 -1
- package/es/model/GraphModel.js +35 -8
- package/es/model/edge/BaseEdgeModel.d.ts +2 -1
- package/es/model/edge/BaseEdgeModel.js +29 -5
- package/es/model/node/BaseNodeModel.d.ts +2 -1
- package/es/model/node/BaseNodeModel.js +29 -5
- package/es/tool/MultipleSelectTool.d.ts +1 -1
- package/es/tool/MultipleSelectTool.js +1 -1
- package/es/util/drag.d.ts +4 -4
- package/es/util/drag.js +12 -6
- package/es/view/Anchor.d.ts +3 -3
- package/es/view/Anchor.js +30 -4
- package/es/view/Control.js +1 -1
- package/es/view/Rotate.js +1 -1
- package/es/view/behavior/dnd.d.ts +4 -8
- package/es/view/behavior/dnd.js +50 -14
- package/es/view/edge/AdjustPoint.d.ts +1 -1
- package/es/view/edge/AdjustPoint.js +1 -1
- package/es/view/edge/BaseEdge.d.ts +2 -1
- package/es/view/edge/BaseEdge.js +18 -1
- package/es/view/edge/PolylineEdge.d.ts +1 -1
- package/es/view/edge/PolylineEdge.js +1 -1
- package/es/view/node/BaseNode.d.ts +2 -1
- package/es/view/node/BaseNode.js +30 -3
- package/es/view/overlay/BezierAdjustOverlay.js +1 -1
- package/es/view/overlay/CanvasOverlay.d.ts +12 -1
- package/es/view/overlay/CanvasOverlay.js +94 -15
- package/es/view/text/BaseText.d.ts +1 -1
- package/es/view/text/BaseText.js +1 -1
- package/lib/LogicFlow.d.ts +2 -1
- package/lib/LogicFlow.js +3 -0
- package/lib/constant/index.d.ts +3 -1
- package/lib/constant/index.js +2 -0
- package/lib/model/EditConfigModel.d.ts +3 -1
- package/lib/model/EditConfigModel.js +5 -0
- package/lib/model/GraphModel.d.ts +9 -1
- package/lib/model/GraphModel.js +35 -8
- package/lib/model/edge/BaseEdgeModel.d.ts +2 -1
- package/lib/model/edge/BaseEdgeModel.js +29 -5
- package/lib/model/node/BaseNodeModel.d.ts +2 -1
- package/lib/model/node/BaseNodeModel.js +29 -5
- package/lib/tool/MultipleSelectTool.d.ts +1 -1
- package/lib/tool/MultipleSelectTool.js +1 -1
- package/lib/util/drag.d.ts +4 -4
- package/lib/util/drag.js +12 -6
- package/lib/view/Anchor.d.ts +3 -3
- package/lib/view/Anchor.js +30 -4
- package/lib/view/Control.js +1 -1
- package/lib/view/Rotate.js +1 -1
- package/lib/view/behavior/dnd.d.ts +4 -8
- package/lib/view/behavior/dnd.js +50 -14
- package/lib/view/edge/AdjustPoint.d.ts +1 -1
- package/lib/view/edge/AdjustPoint.js +1 -1
- package/lib/view/edge/BaseEdge.d.ts +2 -1
- package/lib/view/edge/BaseEdge.js +18 -1
- package/lib/view/edge/PolylineEdge.d.ts +1 -1
- package/lib/view/edge/PolylineEdge.js +1 -1
- package/lib/view/node/BaseNode.d.ts +2 -1
- package/lib/view/node/BaseNode.js +30 -3
- package/lib/view/overlay/BezierAdjustOverlay.js +1 -1
- package/lib/view/overlay/CanvasOverlay.d.ts +12 -1
- package/lib/view/overlay/CanvasOverlay.js +94 -15
- package/lib/view/text/BaseText.d.ts +1 -1
- package/lib/view/text/BaseText.js +1 -1
- package/package.json +1 -1
- package/src/LogicFlow.tsx +9 -1
- package/src/constant/index.ts +2 -0
- package/src/model/EditConfigModel.ts +3 -0
- package/src/model/GraphModel.ts +37 -11
- package/src/model/edge/BaseEdgeModel.ts +32 -5
- package/src/model/node/BaseNodeModel.ts +30 -5
- package/src/tool/MultipleSelectTool.tsx +2 -2
- package/src/util/drag.ts +16 -12
- package/src/view/Anchor.tsx +32 -6
- package/src/view/Control.tsx +1 -1
- package/src/view/Rotate.tsx +1 -1
- package/src/view/behavior/dnd.ts +55 -16
- package/src/view/edge/AdjustPoint.tsx +2 -2
- package/src/view/edge/BaseEdge.tsx +23 -3
- package/src/view/edge/PolylineEdge.tsx +2 -2
- package/src/view/node/BaseNode.tsx +30 -4
- package/src/view/overlay/BezierAdjustOverlay.tsx +1 -1
- package/src/view/overlay/CanvasOverlay.tsx +110 -4
- package/src/view/text/BaseText.tsx +5 -2
- package/stats.html +1 -1
|
@@ -26,7 +26,7 @@ export default class MultipleSelect extends Component<IToolProps> {
|
|
|
26
26
|
})
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
handleMouseDown = (ev:
|
|
29
|
+
handleMouseDown = (ev: PointerEvent) => {
|
|
30
30
|
this.stepDrag.handleMouseDown(ev)
|
|
31
31
|
}
|
|
32
32
|
// 使多选区域的滚轮事件可以触发画布的滚轮事件
|
|
@@ -123,7 +123,7 @@ export default class MultipleSelect extends Component<IToolProps> {
|
|
|
123
123
|
<div
|
|
124
124
|
className="lf-multiple-select"
|
|
125
125
|
style={style}
|
|
126
|
-
|
|
126
|
+
onPointerDown={this.handleMouseDown}
|
|
127
127
|
onContextMenu={this.handleContextMenu}
|
|
128
128
|
onWheel={this.handleWheelEvent}
|
|
129
129
|
/>
|
package/src/util/drag.ts
CHANGED
|
@@ -10,7 +10,7 @@ const LEFT_MOUSE_BUTTON_CODE = 0
|
|
|
10
10
|
export type IDragParams = {
|
|
11
11
|
deltaX: number
|
|
12
12
|
deltaY: number
|
|
13
|
-
event?:
|
|
13
|
+
event?: PointerEvent
|
|
14
14
|
[key: string]: unknown
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -99,16 +99,16 @@ export class StepDrag {
|
|
|
99
99
|
this.model = model
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
handleMouseDown = (e:
|
|
102
|
+
handleMouseDown = (e: PointerEvent) => {
|
|
103
103
|
const DOC: any = window?.document
|
|
104
104
|
if (e.button !== LEFT_MOUSE_BUTTON_CODE) return
|
|
105
105
|
if (this.isStopPropagation) e.stopPropagation()
|
|
106
|
+
e.preventDefault()
|
|
106
107
|
this.isStartDragging = true
|
|
107
108
|
this.startX = e.clientX
|
|
108
109
|
this.startY = e.clientY
|
|
109
|
-
|
|
110
|
-
DOC.addEventListener('
|
|
111
|
-
DOC.addEventListener('mouseup', this.handleMouseUp, false)
|
|
110
|
+
DOC.addEventListener('pointermove', this.handleMouseMove, false)
|
|
111
|
+
DOC.addEventListener('pointerup', this.handleMouseUp, false)
|
|
112
112
|
const elementData = this.model?.getData()
|
|
113
113
|
this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEDOWN`], {
|
|
114
114
|
e,
|
|
@@ -117,8 +117,9 @@ export class StepDrag {
|
|
|
117
117
|
this.startTime = new Date().getTime()
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
handleMouseMove = (e:
|
|
120
|
+
handleMouseMove = (e: PointerEvent) => {
|
|
121
121
|
if (this.isStopPropagation) e.stopPropagation()
|
|
122
|
+
e.preventDefault()
|
|
122
123
|
if (!this.isStartDragging) return
|
|
123
124
|
this.sumDeltaX += e.clientX - this.startX
|
|
124
125
|
this.sumDeltaY += e.clientY - this.startY
|
|
@@ -170,15 +171,19 @@ export class StepDrag {
|
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
|
|
173
|
-
handleMouseUp = (e:
|
|
174
|
+
handleMouseUp = (e: PointerEvent) => {
|
|
174
175
|
const DOC = window.document
|
|
175
176
|
|
|
176
177
|
this.isStartDragging = false
|
|
177
178
|
if (this.isStopPropagation) e.stopPropagation()
|
|
179
|
+
const target = e.target as any
|
|
180
|
+
if (target && typeof target.releasePointerCapture === 'function') {
|
|
181
|
+
target.releasePointerCapture(e.pointerId)
|
|
182
|
+
}
|
|
178
183
|
// fix #568: 如果onDragging在下一个事件循环中触发,而drop在当前事件循环,会出现问题。
|
|
179
184
|
Promise.resolve().then(() => {
|
|
180
|
-
DOC.removeEventListener('
|
|
181
|
-
DOC.removeEventListener('
|
|
185
|
+
DOC.removeEventListener('pointermove', this.handleMouseMove, false)
|
|
186
|
+
DOC.removeEventListener('pointerup', this.handleMouseUp, false)
|
|
182
187
|
const elementData = this.model?.getData()
|
|
183
188
|
this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEUP`], {
|
|
184
189
|
e,
|
|
@@ -195,9 +200,8 @@ export class StepDrag {
|
|
|
195
200
|
}
|
|
196
201
|
cancelDrag = () => {
|
|
197
202
|
const DOC: any = window?.document
|
|
198
|
-
|
|
199
|
-
DOC.removeEventListener('
|
|
200
|
-
DOC.removeEventListener('mouseup', this.handleMouseUp, false)
|
|
203
|
+
DOC.removeEventListener('pointermove', this.handleMouseMove, false)
|
|
204
|
+
DOC.removeEventListener('pointerup', this.handleMouseUp, false)
|
|
201
205
|
this.onDragEnd({ event: undefined })
|
|
202
206
|
this.isDragging = false
|
|
203
207
|
}
|
package/src/view/Anchor.tsx
CHANGED
|
@@ -29,7 +29,7 @@ interface IProps {
|
|
|
29
29
|
anchorIndex: number
|
|
30
30
|
graphModel: GraphModel
|
|
31
31
|
nodeModel: BaseNodeModel
|
|
32
|
-
setHoverOff: (e:
|
|
32
|
+
setHoverOff: (e: PointerEvent) => void
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
interface IState {
|
|
@@ -154,7 +154,7 @@ class Anchor extends Component<IProps, IState> {
|
|
|
154
154
|
endY: y1,
|
|
155
155
|
dragging: true,
|
|
156
156
|
})
|
|
157
|
-
this.moveAnchorEnd(x1, y1)
|
|
157
|
+
this.moveAnchorEnd(x1, y1, event)
|
|
158
158
|
if (nearBoundary.length > 0 && !stopMoveGraph && autoExpand) {
|
|
159
159
|
this.t = createRaf(() => {
|
|
160
160
|
const [translateX, translateY] = nearBoundary
|
|
@@ -164,7 +164,7 @@ class Anchor extends Component<IProps, IState> {
|
|
|
164
164
|
endX: endX - translateX,
|
|
165
165
|
endY: endY - translateY,
|
|
166
166
|
})
|
|
167
|
-
this.moveAnchorEnd(endX - translateX, endY - translateY)
|
|
167
|
+
this.moveAnchorEnd(endX - translateX, endY - translateY, event)
|
|
168
168
|
})
|
|
169
169
|
}
|
|
170
170
|
eventCenter.emit(EventType.ANCHOR_DRAG, {
|
|
@@ -189,6 +189,11 @@ class Anchor extends Component<IProps, IState> {
|
|
|
189
189
|
this.sourceRuleResults.clear()
|
|
190
190
|
this.targetRuleResults.clear()
|
|
191
191
|
const { graphModel, nodeModel, anchorData } = this.props
|
|
192
|
+
// 拖拽结束清理:取消悬浮态
|
|
193
|
+
if (this.preTargetNode) {
|
|
194
|
+
this.preTargetNode.setHovered(false)
|
|
195
|
+
this.preTargetNode = undefined
|
|
196
|
+
}
|
|
192
197
|
|
|
193
198
|
graphModel.eventCenter.emit(EventType.ANCHOR_DRAGEND, {
|
|
194
199
|
data: anchorData,
|
|
@@ -216,7 +221,7 @@ class Anchor extends Component<IProps, IState> {
|
|
|
216
221
|
}
|
|
217
222
|
}
|
|
218
223
|
|
|
219
|
-
checkEnd = (event:
|
|
224
|
+
checkEnd = (event: PointerEvent | null | undefined) => {
|
|
220
225
|
const {
|
|
221
226
|
graphModel,
|
|
222
227
|
nodeModel,
|
|
@@ -289,7 +294,7 @@ class Anchor extends Component<IProps, IState> {
|
|
|
289
294
|
}
|
|
290
295
|
}
|
|
291
296
|
|
|
292
|
-
moveAnchorEnd(endX: number, endY: number) {
|
|
297
|
+
moveAnchorEnd(endX: number, endY: number, event?: PointerEvent) {
|
|
293
298
|
const { graphModel, nodeModel, anchorData } = this.props
|
|
294
299
|
const info = targetNodeInfo(
|
|
295
300
|
{
|
|
@@ -344,12 +349,33 @@ class Anchor extends Component<IProps, IState> {
|
|
|
344
349
|
} else {
|
|
345
350
|
targetNode.setElementState(ElementState.NOT_ALLOW_CONNECT)
|
|
346
351
|
}
|
|
352
|
+
// 人工触发进入目标节点事件,同步设置 hovered 以驱动锚点显隐和样式
|
|
353
|
+
if (!targetNode.isHovered) {
|
|
354
|
+
const nodeData = targetNode.getData()
|
|
355
|
+
if (event) {
|
|
356
|
+
graphModel.eventCenter.emit(EventType.NODE_MOUSEENTER, {
|
|
357
|
+
data: nodeData,
|
|
358
|
+
e: event,
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
targetNode.setHovered(true)
|
|
362
|
+
}
|
|
347
363
|
} else if (
|
|
348
364
|
this.preTargetNode &&
|
|
349
365
|
this.preTargetNode.state !== ElementState.DEFAULT
|
|
350
366
|
) {
|
|
351
367
|
// 为了保证鼠标离开的时候,将上一个节点状态重置为正常状态。
|
|
352
368
|
this.preTargetNode.setElementState(ElementState.DEFAULT)
|
|
369
|
+
// 未命中任何节点:人工派发离开事件并取消悬浮,避免状态残留
|
|
370
|
+
const prevData = this.preTargetNode.getData()
|
|
371
|
+
if (event) {
|
|
372
|
+
graphModel.eventCenter.emit(EventType.NODE_MOUSELEAVE, {
|
|
373
|
+
data: prevData,
|
|
374
|
+
e: event,
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
this.preTargetNode.setHovered(false)
|
|
378
|
+
this.preTargetNode = undefined
|
|
353
379
|
}
|
|
354
380
|
}
|
|
355
381
|
|
|
@@ -375,7 +401,7 @@ class Anchor extends Component<IProps, IState> {
|
|
|
375
401
|
nodeModel,
|
|
376
402
|
})
|
|
377
403
|
}}
|
|
378
|
-
|
|
404
|
+
onPointerDown={(ev) => {
|
|
379
405
|
graphModel.eventCenter.emit(EventType.ANCHOR_MOUSEDOWN, {
|
|
380
406
|
data: anchorData,
|
|
381
407
|
e: ev!,
|
package/src/view/Control.tsx
CHANGED
package/src/view/Rotate.tsx
CHANGED
package/src/view/behavior/dnd.ts
CHANGED
|
@@ -11,6 +11,8 @@ export class Dnd {
|
|
|
11
11
|
nodeConfig: OnDragNodeConfig | null = null
|
|
12
12
|
lf: LogicFlow
|
|
13
13
|
fakeNode: BaseNodeModel | null = null
|
|
14
|
+
docPointerMove?: (e: PointerEvent) => void
|
|
15
|
+
docPointerUp?: (e: PointerEvent) => void
|
|
14
16
|
|
|
15
17
|
constructor(params: { lf: LogicFlow }) {
|
|
16
18
|
const { lf } = params
|
|
@@ -36,19 +38,67 @@ export class Dnd {
|
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
isInsideCanvas(e: PointerEvent): boolean {
|
|
42
|
+
const overlay = this.lf.graphModel.rootEl.querySelector(
|
|
43
|
+
'[name="canvas-overlay"]',
|
|
44
|
+
) as HTMLElement | null
|
|
45
|
+
const topEl = window.document.elementFromPoint(
|
|
46
|
+
e.clientX,
|
|
47
|
+
e.clientY,
|
|
48
|
+
) as HTMLElement | null
|
|
49
|
+
return (
|
|
50
|
+
topEl === overlay ||
|
|
51
|
+
(topEl !== null && !!overlay && overlay.contains(topEl))
|
|
52
|
+
)
|
|
53
|
+
}
|
|
39
54
|
startDrag(nodeConfig: OnDragNodeConfig) {
|
|
40
55
|
const { editConfigModel } = this.lf.graphModel
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
if (editConfigModel?.isSilentMode) return
|
|
57
|
+
this.nodeConfig = nodeConfig
|
|
58
|
+
// 指针移动:根据命中结果判断是否在画布覆盖层上,驱动假节点创建/移动或清理
|
|
59
|
+
this.docPointerMove = (e: PointerEvent) => {
|
|
60
|
+
if (!this.nodeConfig) return
|
|
61
|
+
// 离开画布:清理吸附线与假节点
|
|
62
|
+
if (!this.isInsideCanvas(e)) {
|
|
63
|
+
this.onDragLeave()
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
// 首次进入画布:创建假节点并初始化位置
|
|
67
|
+
if (!this.fakeNode) {
|
|
68
|
+
this.dragEnter(e)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
// 在画布内移动:更新假节点位置与吸附线
|
|
72
|
+
this.onDragOver(e)
|
|
73
|
+
}
|
|
74
|
+
// 指针抬起:在画布内落点生成节点,否则清理假节点
|
|
75
|
+
this.docPointerUp = (e: PointerEvent) => {
|
|
76
|
+
if (!this.nodeConfig) return
|
|
77
|
+
if (this.isInsideCanvas(e)) {
|
|
78
|
+
this.onDrop(e)
|
|
79
|
+
} else {
|
|
80
|
+
this.onDragLeave()
|
|
81
|
+
}
|
|
82
|
+
// 阻止默认行为与冒泡,避免滚动/点击穿透
|
|
83
|
+
e.preventDefault()
|
|
84
|
+
e.stopPropagation()
|
|
85
|
+
// 结束拖拽并移除监听
|
|
86
|
+
this.stopDrag()
|
|
44
87
|
}
|
|
88
|
+
window.document.addEventListener('pointermove', this.docPointerMove)
|
|
89
|
+
window.document.addEventListener('pointerup', this.docPointerUp)
|
|
45
90
|
}
|
|
46
91
|
|
|
47
92
|
stopDrag = () => {
|
|
48
93
|
this.nodeConfig = null
|
|
49
|
-
|
|
94
|
+
if (this.docPointerMove) {
|
|
95
|
+
window.document.removeEventListener('pointermove', this.docPointerMove)
|
|
96
|
+
}
|
|
97
|
+
if (this.docPointerUp) {
|
|
98
|
+
window.document.removeEventListener('pointerup', this.docPointerUp)
|
|
99
|
+
}
|
|
50
100
|
}
|
|
51
|
-
dragEnter = (e:
|
|
101
|
+
dragEnter = (e: PointerEvent) => {
|
|
52
102
|
if (!this.nodeConfig || this.fakeNode) return
|
|
53
103
|
this.fakeNode = this.lf.createFakeNode({
|
|
54
104
|
...this.nodeConfig,
|
|
@@ -107,17 +157,6 @@ export class Dnd {
|
|
|
107
157
|
this.lf.graphModel.removeFakeNode()
|
|
108
158
|
this.fakeNode = null
|
|
109
159
|
}
|
|
110
|
-
|
|
111
|
-
eventMap() {
|
|
112
|
-
return {
|
|
113
|
-
onMouseEnter: this.dragEnter,
|
|
114
|
-
onMouseOver: this.dragEnter, // IE11
|
|
115
|
-
onMouseMove: this.onDragOver,
|
|
116
|
-
onMouseLeave: this.onDragLeave,
|
|
117
|
-
// onMouseOut: this.onDragLeave, // IE11
|
|
118
|
-
onMouseUp: this.onDrop,
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
160
|
}
|
|
122
161
|
|
|
123
162
|
export default Dnd
|
|
@@ -78,7 +78,7 @@ export class AdjustPoint extends Component<IProps, IState> {
|
|
|
78
78
|
})
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
handleMouseDown = (ev:
|
|
81
|
+
handleMouseDown = (ev: PointerEvent) => {
|
|
82
82
|
if (this.stepDrag) {
|
|
83
83
|
this.stepDrag.handleMouseDown(ev)
|
|
84
84
|
}
|
|
@@ -414,7 +414,7 @@ export class AdjustPoint extends Component<IProps, IState> {
|
|
|
414
414
|
return (
|
|
415
415
|
<g
|
|
416
416
|
pointerEvents={dragging ? 'none' : ''}
|
|
417
|
-
|
|
417
|
+
onPointerDown={this.handleMouseDown}
|
|
418
418
|
>
|
|
419
419
|
{!dragging ? getAdjustPointShape(x, y, edgeModel) : ''}
|
|
420
420
|
</g>
|
|
@@ -34,6 +34,7 @@ export abstract class BaseEdge<P extends IProps> extends Component<
|
|
|
34
34
|
startTime?: number
|
|
35
35
|
contextMenuTime?: number
|
|
36
36
|
clickTimer?: number
|
|
37
|
+
longPressTimer?: number
|
|
37
38
|
textRef = createRef()
|
|
38
39
|
|
|
39
40
|
constructor() {
|
|
@@ -479,13 +480,27 @@ export abstract class BaseEdge<P extends IProps> extends Component<
|
|
|
479
480
|
/**
|
|
480
481
|
* 不支持重写
|
|
481
482
|
*/
|
|
482
|
-
handleMouseDown = (e:
|
|
483
|
+
handleMouseDown = (e: PointerEvent) => {
|
|
483
484
|
e.stopPropagation()
|
|
484
485
|
this.startTime = new Date().getTime()
|
|
486
|
+
if (this.longPressTimer) {
|
|
487
|
+
clearTimeout(this.longPressTimer)
|
|
488
|
+
}
|
|
489
|
+
if (e.pointerType === 'touch') {
|
|
490
|
+
this.longPressTimer = window.setTimeout(() => {
|
|
491
|
+
if (!this.props.model.isDragging) {
|
|
492
|
+
this.handleContextMenu(e)
|
|
493
|
+
}
|
|
494
|
+
}, 500)
|
|
495
|
+
}
|
|
485
496
|
}
|
|
486
497
|
handleMouseUp = () => {
|
|
487
498
|
const { model } = this.props
|
|
488
499
|
this.mouseUpDrag = model.isDragging
|
|
500
|
+
if (this.longPressTimer) {
|
|
501
|
+
clearTimeout(this.longPressTimer)
|
|
502
|
+
this.longPressTimer = undefined
|
|
503
|
+
}
|
|
489
504
|
}
|
|
490
505
|
/**
|
|
491
506
|
* 不支持重写
|
|
@@ -606,10 +621,15 @@ export abstract class BaseEdge<P extends IProps> extends Component<
|
|
|
606
621
|
]
|
|
607
622
|
.filter(Boolean)
|
|
608
623
|
.join(' ')}
|
|
609
|
-
|
|
610
|
-
|
|
624
|
+
style={{
|
|
625
|
+
touchAction: 'none',
|
|
626
|
+
WebkitTouchCallout: 'none',
|
|
627
|
+
}}
|
|
611
628
|
onClick={this.handleClick}
|
|
612
629
|
onContextMenu={this.handleContextMenu}
|
|
630
|
+
onPointerDown={this.handleMouseDown}
|
|
631
|
+
onPointerUp={this.handleMouseUp}
|
|
632
|
+
onPointerCancel={this.handleMouseUp}
|
|
613
633
|
onMouseOver={this.setHoverOn}
|
|
614
634
|
onMouseEnter={this.setHoverOn}
|
|
615
635
|
onMouseLeave={this.setHoverOff}
|
|
@@ -95,7 +95,7 @@ export class PolylineEdge extends BaseEdge<IPolylineEdgeProps> {
|
|
|
95
95
|
/**
|
|
96
96
|
* 不支持重写
|
|
97
97
|
*/
|
|
98
|
-
beforeDragStart = (e, appendInfo) => {
|
|
98
|
+
beforeDragStart = (e: PointerEvent, appendInfo) => {
|
|
99
99
|
// 如果允许拖拽调整触发事件处理
|
|
100
100
|
if (appendInfo.draggable) {
|
|
101
101
|
this.drag.handleMouseDown(e)
|
|
@@ -284,7 +284,7 @@ export class PolylineEdge extends BaseEdge<IPolylineEdgeProps> {
|
|
|
284
284
|
append = (
|
|
285
285
|
<g
|
|
286
286
|
className={this.isDragging ? 'lf-dragging' : 'lf-drag-able'}
|
|
287
|
-
|
|
287
|
+
onPointerDown={(e) => this.beforeDragStart(e, appendInfo)}
|
|
288
288
|
>
|
|
289
289
|
<g className={className}>{this.getAppendShape(appendInfo)}</g>
|
|
290
290
|
</g>
|
|
@@ -42,6 +42,7 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
|
|
|
42
42
|
mouseUpDrag?: boolean
|
|
43
43
|
startTime?: number
|
|
44
44
|
modelDisposer: IReactionDisposer
|
|
45
|
+
longPressTimer?: number
|
|
45
46
|
|
|
46
47
|
constructor(props: IProps) {
|
|
47
48
|
super()
|
|
@@ -330,15 +331,27 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
|
|
|
330
331
|
handleMouseUp = () => {
|
|
331
332
|
const { model } = this.props
|
|
332
333
|
this.mouseUpDrag = model.isDragging
|
|
334
|
+
if (this.longPressTimer) {
|
|
335
|
+
clearTimeout(this.longPressTimer)
|
|
336
|
+
this.longPressTimer = undefined
|
|
337
|
+
}
|
|
333
338
|
}
|
|
334
339
|
|
|
335
340
|
handleClick = (e: MouseEvent) => {
|
|
336
341
|
// 节点拖拽进画布之后,不触发click事件相关emit
|
|
337
342
|
// 点拖拽进画布没有触发mousedown事件,没有startTime,用这个值做区分
|
|
338
343
|
const isDragging = this.mouseUpDrag === false
|
|
344
|
+
const curTime = new Date().getTime()
|
|
339
345
|
if (!this.startTime) return
|
|
346
|
+
const timeInterval = curTime - this.startTime
|
|
340
347
|
const { model, graphModel } = this.props
|
|
341
|
-
|
|
348
|
+
// 这里会有一种极端情况:当网格大小是1或者关闭网格吸附时,用触摸板点击节点会触发拖拽事件导致节点无法选中
|
|
349
|
+
// 当触摸板点击节点时,为了防止误触发拖拽导致节点无法选中,允许在非拖拽状态且时间间隔小于100ms时触发点击事件
|
|
350
|
+
if (!isDragging && timeInterval > 100) return
|
|
351
|
+
if (!isDragging) {
|
|
352
|
+
this.onDragEnd()
|
|
353
|
+
this.handleMouseUp()
|
|
354
|
+
}
|
|
342
355
|
// 节点数据,多为事件对象数据抛出
|
|
343
356
|
const nodeData = model.getData()
|
|
344
357
|
const position = graphModel.getPointByClient({
|
|
@@ -423,13 +436,23 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
|
|
|
423
436
|
}
|
|
424
437
|
}
|
|
425
438
|
|
|
426
|
-
handleMouseDown = (ev:
|
|
439
|
+
handleMouseDown = (ev: PointerEvent) => {
|
|
427
440
|
const { model, graphModel } = this.props
|
|
428
441
|
this.startTime = new Date().getTime()
|
|
429
442
|
const { editConfigModel } = graphModel
|
|
430
443
|
if (editConfigModel.adjustNodePosition && model.draggable) {
|
|
431
444
|
this.stepDrag && this.stepDrag.handleMouseDown(ev)
|
|
432
445
|
}
|
|
446
|
+
if (this.longPressTimer) {
|
|
447
|
+
clearTimeout(this.longPressTimer)
|
|
448
|
+
}
|
|
449
|
+
if (ev.pointerType === 'touch') {
|
|
450
|
+
this.longPressTimer = window.setTimeout(() => {
|
|
451
|
+
if (!this.props.model.isDragging) {
|
|
452
|
+
this.handleContextMenu(ev)
|
|
453
|
+
}
|
|
454
|
+
}, 500)
|
|
455
|
+
}
|
|
433
456
|
}
|
|
434
457
|
|
|
435
458
|
handleFocus = () => {
|
|
@@ -440,6 +463,8 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
|
|
|
440
463
|
}
|
|
441
464
|
|
|
442
465
|
handleBlur = () => {
|
|
466
|
+
// 当节点通过自定义锚点实现节点删除时,这里props会变成undefined,需兼容一下
|
|
467
|
+
if (!this.props) return
|
|
443
468
|
const { model, graphModel } = this.props
|
|
444
469
|
graphModel.eventCenter.emit(EventType.NODE_BLUR, {
|
|
445
470
|
data: model.getData(),
|
|
@@ -522,9 +547,10 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
|
|
|
522
547
|
nodeShape = (
|
|
523
548
|
<g
|
|
524
549
|
className={`${this.getStateClassName()} ${className}`}
|
|
525
|
-
|
|
526
|
-
|
|
550
|
+
onPointerDown={this.handleMouseDown}
|
|
551
|
+
onPointerUp={this.handleMouseUp}
|
|
527
552
|
onClick={this.handleClick}
|
|
553
|
+
//因为移动端点击操作完成会按顺序触发enter、leave、click事件,所以会造成节点的闪烁,所以在这里没有统一状态为Pointer
|
|
528
554
|
onMouseEnter={this.setHoverOn}
|
|
529
555
|
onMouseOver={this.setHoverOn}
|
|
530
556
|
onMouseLeave={this.setHoverOff}
|
|
@@ -18,6 +18,12 @@ export class CanvasOverlay extends Component<IProps, IState> {
|
|
|
18
18
|
stepDrag: StepDrag
|
|
19
19
|
stepScrollX = 0
|
|
20
20
|
stepScrollY = 0
|
|
21
|
+
pointers = new Map<number, { x: number; y: number }>()
|
|
22
|
+
pinchStartDistance?: number
|
|
23
|
+
pinchStartScale?: number
|
|
24
|
+
pinchLastCenterX?: number
|
|
25
|
+
pinchLastCenterY?: number
|
|
26
|
+
longPressTimer?: number
|
|
21
27
|
|
|
22
28
|
constructor(props: IProps) {
|
|
23
29
|
super()
|
|
@@ -43,6 +49,10 @@ export class CanvasOverlay extends Component<IProps, IState> {
|
|
|
43
49
|
// return this.props as InjectedProps;
|
|
44
50
|
// }
|
|
45
51
|
onDragging = ({ deltaX, deltaY }: IDragParams) => {
|
|
52
|
+
if (this.longPressTimer) {
|
|
53
|
+
clearTimeout(this.longPressTimer)
|
|
54
|
+
this.longPressTimer = undefined
|
|
55
|
+
}
|
|
46
56
|
this.setState({
|
|
47
57
|
isDragging: true,
|
|
48
58
|
})
|
|
@@ -125,7 +135,7 @@ export class CanvasOverlay extends Component<IProps, IState> {
|
|
|
125
135
|
}
|
|
126
136
|
}
|
|
127
137
|
// 鼠标、触摸板 按下
|
|
128
|
-
|
|
138
|
+
pointerDownHandler = (ev: PointerEvent) => {
|
|
129
139
|
const {
|
|
130
140
|
graphModel: {
|
|
131
141
|
eventCenter,
|
|
@@ -134,6 +144,36 @@ export class CanvasOverlay extends Component<IProps, IState> {
|
|
|
134
144
|
gridSize,
|
|
135
145
|
},
|
|
136
146
|
} = this.props
|
|
147
|
+
this.pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY })
|
|
148
|
+
if (this.longPressTimer) {
|
|
149
|
+
clearTimeout(this.longPressTimer)
|
|
150
|
+
}
|
|
151
|
+
if (ev.pointerType === 'touch') {
|
|
152
|
+
this.longPressTimer = window.setTimeout(() => {
|
|
153
|
+
this.handleContextMenu(ev)
|
|
154
|
+
}, 500)
|
|
155
|
+
}
|
|
156
|
+
// 检测双指触摸,初始化捏合缩放
|
|
157
|
+
if (this.pointers.size === 2) {
|
|
158
|
+
const {
|
|
159
|
+
graphModel: { transformModel, editConfigModel },
|
|
160
|
+
} = this.props
|
|
161
|
+
// 记录两指当前位置用于计算初始距离
|
|
162
|
+
const pts = Array.from(this.pointers.values())
|
|
163
|
+
const dx = pts[0].x - pts[1].x
|
|
164
|
+
const dy = pts[0].y - pts[1].y
|
|
165
|
+
const cx = (pts[0].x + pts[1].x) / 2
|
|
166
|
+
const cy = (pts[0].y + pts[1].y) / 2
|
|
167
|
+
// 记录捏合起始距离与当前缩放,后续按比例计算缩放
|
|
168
|
+
this.pinchStartDistance = Math.hypot(dx, dy)
|
|
169
|
+
this.pinchStartScale = transformModel.SCALE_X
|
|
170
|
+
// 双指操作下取消画布拖拽,避免与捏合缩放冲突
|
|
171
|
+
this.stepDrag.cancelDrag()
|
|
172
|
+
this.pinchLastCenterX = cx
|
|
173
|
+
this.pinchLastCenterY = cy
|
|
174
|
+
editConfigModel.updateEditConfig({ isPinching: true })
|
|
175
|
+
return
|
|
176
|
+
}
|
|
137
177
|
const { adjustEdge, adjustNodePosition, stopMoveGraph } = editConfigModel
|
|
138
178
|
const target = ev.target as HTMLElement
|
|
139
179
|
const isFrozenElement = !adjustEdge && !adjustNodePosition
|
|
@@ -148,13 +188,76 @@ export class CanvasOverlay extends Component<IProps, IState> {
|
|
|
148
188
|
this.clickHandler(ev)
|
|
149
189
|
}
|
|
150
190
|
}
|
|
191
|
+
pointerMoveHandler = (ev: PointerEvent) => {
|
|
192
|
+
// 记录当前指针位置(按 pointerId)
|
|
193
|
+
this.pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY })
|
|
194
|
+
// 当已记录初始捏合距离且存在两指时,执行捏合缩放
|
|
195
|
+
if (this.pinchStartDistance && this.pointers.size >= 2) {
|
|
196
|
+
const {
|
|
197
|
+
graphModel,
|
|
198
|
+
graphModel: { editConfigModel, transformModel },
|
|
199
|
+
} = this.props
|
|
200
|
+
if (editConfigModel.stopZoomGraph) return
|
|
201
|
+
// 取消触摸长按计时,避免捏合过程中误触发上下文菜单
|
|
202
|
+
if (this.longPressTimer) {
|
|
203
|
+
clearTimeout(this.longPressTimer)
|
|
204
|
+
}
|
|
205
|
+
// 计算两指间当前距离
|
|
206
|
+
const pts = Array.from(this.pointers.values())
|
|
207
|
+
const dx = pts[0].x - pts[1].x
|
|
208
|
+
const dy = pts[0].y - pts[1].y
|
|
209
|
+
const dist = Math.hypot(dx, dy)
|
|
210
|
+
// 以初始缩放为基准,根据距离比例得到新的缩放比例
|
|
211
|
+
const scale =
|
|
212
|
+
(this.pinchStartScale ?? transformModel.SCALE_X) *
|
|
213
|
+
(dist / this.pinchStartDistance)
|
|
214
|
+
// 取两指中心作为缩放原点,并转换为画布坐标系
|
|
215
|
+
const cx = (pts[0].x + pts[1].x) / 2
|
|
216
|
+
const cy = (pts[0].y + pts[1].y) / 2
|
|
217
|
+
const pos = graphModel.getPointByClient({ x: cx, y: cy })
|
|
218
|
+
const { x, y } = pos.canvasOverlayPosition
|
|
219
|
+
transformModel.zoom(scale, [x, y])
|
|
220
|
+
// 双指中心位移驱动画布平移,配合缩放实现捏合移动;
|
|
221
|
+
if (!editConfigModel.stopMoveGraph || editConfigModel.isPinching) {
|
|
222
|
+
const deltaX =
|
|
223
|
+
this.pinchLastCenterX === undefined ? 0 : cx - this.pinchLastCenterX
|
|
224
|
+
const deltaY =
|
|
225
|
+
this.pinchLastCenterY === undefined ? 0 : cy - this.pinchLastCenterY
|
|
226
|
+
transformModel.translate(deltaX, deltaY)
|
|
227
|
+
this.pinchLastCenterX = cx
|
|
228
|
+
this.pinchLastCenterY = cy
|
|
229
|
+
}
|
|
230
|
+
ev.preventDefault()
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
pointerUpHandler = (ev: PointerEvent) => {
|
|
234
|
+
this.pointers.delete(ev.pointerId)
|
|
235
|
+
if (this.longPressTimer) {
|
|
236
|
+
clearTimeout(this.longPressTimer)
|
|
237
|
+
this.longPressTimer = undefined
|
|
238
|
+
}
|
|
239
|
+
// 双指松开或仅剩一指:结束捏合手势并清理临时状态
|
|
240
|
+
if (this.pointers.size < 2) {
|
|
241
|
+
// 清空捏合距离与缩放起始值
|
|
242
|
+
this.pinchStartDistance = undefined
|
|
243
|
+
this.pinchStartScale = undefined
|
|
244
|
+
// 清空上一帧的双指中心
|
|
245
|
+
this.pinchLastCenterX = undefined
|
|
246
|
+
this.pinchLastCenterY = undefined
|
|
247
|
+
const {
|
|
248
|
+
graphModel: { editConfigModel },
|
|
249
|
+
} = this.props
|
|
250
|
+
// 标记退出捏合,框选等交互可恢复
|
|
251
|
+
editConfigModel.updateEditConfig({ isPinching: false })
|
|
252
|
+
}
|
|
253
|
+
}
|
|
151
254
|
|
|
152
255
|
render() {
|
|
153
256
|
const {
|
|
154
257
|
graphModel: { transformModel },
|
|
155
258
|
} = this.props
|
|
156
259
|
const { transform } = transformModel.getTransformStyle()
|
|
157
|
-
const { children
|
|
260
|
+
const { children } = this.props
|
|
158
261
|
const { isDragging } = this.state
|
|
159
262
|
|
|
160
263
|
return (
|
|
@@ -164,14 +267,17 @@ export class CanvasOverlay extends Component<IProps, IState> {
|
|
|
164
267
|
height="100%"
|
|
165
268
|
name="canvas-overlay"
|
|
166
269
|
onWheel={this.zoomHandler}
|
|
167
|
-
|
|
270
|
+
onPointerDown={this.pointerDownHandler}
|
|
271
|
+
onPointerMove={this.pointerMoveHandler}
|
|
272
|
+
onPointerUp={this.pointerUpHandler}
|
|
273
|
+
onPointerCancel={this.pointerUpHandler}
|
|
168
274
|
onContextMenu={this.handleContextMenu}
|
|
275
|
+
style={{ touchAction: 'none', WebkitUserSelect: 'none' }}
|
|
169
276
|
className={
|
|
170
277
|
isDragging
|
|
171
278
|
? 'lf-canvas-overlay lf-dragging'
|
|
172
279
|
: 'lf-canvas-overlay lf-drag-able'
|
|
173
280
|
}
|
|
174
|
-
{...dnd.eventMap()}
|
|
175
281
|
>
|
|
176
282
|
<g transform={transform}>{children}</g>
|
|
177
283
|
</svg>
|
|
@@ -73,7 +73,7 @@ export class BaseText<
|
|
|
73
73
|
)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
mouseDownHandler = (e:
|
|
76
|
+
mouseDownHandler = (e: PointerEvent) => {
|
|
77
77
|
const { draggable, model, graphModel } = this.props
|
|
78
78
|
const {
|
|
79
79
|
editConfigModel: { nodeTextDraggable },
|
|
@@ -120,7 +120,10 @@ export class BaseText<
|
|
|
120
120
|
} = this.props
|
|
121
121
|
if (text) {
|
|
122
122
|
return (
|
|
123
|
-
<g
|
|
123
|
+
<g
|
|
124
|
+
onPointerDown={this.mouseDownHandler}
|
|
125
|
+
onDblClick={this.dbClickHandler}
|
|
126
|
+
>
|
|
124
127
|
{this.getShape()}
|
|
125
128
|
</g>
|
|
126
129
|
)
|