@logicflow/core 2.1.4 → 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.
Files changed (74) hide show
  1. package/.turbo/turbo-build$colon$dev.log +2 -2
  2. package/.turbo/turbo-build.log +6 -6
  3. package/CHANGELOG.md +6 -0
  4. package/dist/index.min.js +1 -1
  5. package/dist/index.min.js.map +1 -1
  6. package/es/model/EditConfigModel.d.ts +3 -1
  7. package/es/model/EditConfigModel.js +5 -0
  8. package/es/model/GraphModel.js +1 -0
  9. package/es/tool/MultipleSelectTool.d.ts +1 -1
  10. package/es/tool/MultipleSelectTool.js +1 -1
  11. package/es/util/drag.d.ts +4 -4
  12. package/es/util/drag.js +12 -6
  13. package/es/view/Anchor.d.ts +3 -3
  14. package/es/view/Anchor.js +30 -4
  15. package/es/view/Control.js +1 -1
  16. package/es/view/Rotate.js +1 -1
  17. package/es/view/behavior/dnd.d.ts +4 -8
  18. package/es/view/behavior/dnd.js +50 -14
  19. package/es/view/edge/AdjustPoint.d.ts +1 -1
  20. package/es/view/edge/AdjustPoint.js +1 -1
  21. package/es/view/edge/BaseEdge.d.ts +2 -1
  22. package/es/view/edge/BaseEdge.js +18 -1
  23. package/es/view/edge/PolylineEdge.d.ts +1 -1
  24. package/es/view/edge/PolylineEdge.js +1 -1
  25. package/es/view/node/BaseNode.d.ts +2 -1
  26. package/es/view/node/BaseNode.js +17 -1
  27. package/es/view/overlay/BezierAdjustOverlay.js +1 -1
  28. package/es/view/overlay/CanvasOverlay.d.ts +12 -1
  29. package/es/view/overlay/CanvasOverlay.js +94 -15
  30. package/es/view/text/BaseText.d.ts +1 -1
  31. package/es/view/text/BaseText.js +1 -1
  32. package/lib/model/EditConfigModel.d.ts +3 -1
  33. package/lib/model/EditConfigModel.js +5 -0
  34. package/lib/model/GraphModel.js +1 -0
  35. package/lib/tool/MultipleSelectTool.d.ts +1 -1
  36. package/lib/tool/MultipleSelectTool.js +1 -1
  37. package/lib/util/drag.d.ts +4 -4
  38. package/lib/util/drag.js +12 -6
  39. package/lib/view/Anchor.d.ts +3 -3
  40. package/lib/view/Anchor.js +30 -4
  41. package/lib/view/Control.js +1 -1
  42. package/lib/view/Rotate.js +1 -1
  43. package/lib/view/behavior/dnd.d.ts +4 -8
  44. package/lib/view/behavior/dnd.js +50 -14
  45. package/lib/view/edge/AdjustPoint.d.ts +1 -1
  46. package/lib/view/edge/AdjustPoint.js +1 -1
  47. package/lib/view/edge/BaseEdge.d.ts +2 -1
  48. package/lib/view/edge/BaseEdge.js +18 -1
  49. package/lib/view/edge/PolylineEdge.d.ts +1 -1
  50. package/lib/view/edge/PolylineEdge.js +1 -1
  51. package/lib/view/node/BaseNode.d.ts +2 -1
  52. package/lib/view/node/BaseNode.js +17 -1
  53. package/lib/view/overlay/BezierAdjustOverlay.js +1 -1
  54. package/lib/view/overlay/CanvasOverlay.d.ts +12 -1
  55. package/lib/view/overlay/CanvasOverlay.js +94 -15
  56. package/lib/view/text/BaseText.d.ts +1 -1
  57. package/lib/view/text/BaseText.js +1 -1
  58. package/package.json +1 -1
  59. package/src/model/EditConfigModel.ts +3 -0
  60. package/src/model/GraphModel.ts +1 -0
  61. package/src/tool/MultipleSelectTool.tsx +2 -2
  62. package/src/util/drag.ts +16 -12
  63. package/src/view/Anchor.tsx +32 -6
  64. package/src/view/Control.tsx +1 -1
  65. package/src/view/Rotate.tsx +1 -1
  66. package/src/view/behavior/dnd.ts +55 -16
  67. package/src/view/edge/AdjustPoint.tsx +2 -2
  68. package/src/view/edge/BaseEdge.tsx +23 -3
  69. package/src/view/edge/PolylineEdge.tsx +2 -2
  70. package/src/view/node/BaseNode.tsx +21 -5
  71. package/src/view/overlay/BezierAdjustOverlay.tsx +1 -1
  72. package/src/view/overlay/CanvasOverlay.tsx +110 -4
  73. package/src/view/text/BaseText.tsx +5 -2
  74. package/stats.html +1 -1
@@ -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: MouseEvent) => {
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
- onMouseDown={this.handleMouseDown}
610
- onMouseUp={this.handleMouseUp}
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
- onMouseDown={(e) => this.beforeDragStart(e, appendInfo)}
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()
@@ -88,9 +89,9 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
88
89
  }
89
90
  }
90
91
 
91
- componentDidMount() { }
92
+ componentDidMount() {}
92
93
 
93
- componentDidUpdate() { }
94
+ componentDidUpdate() {}
94
95
 
95
96
  abstract getShape(): h.JSX.Element | null
96
97
 
@@ -330,6 +331,10 @@ 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) => {
@@ -431,13 +436,23 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
431
436
  }
432
437
  }
433
438
 
434
- handleMouseDown = (ev: MouseEvent) => {
439
+ handleMouseDown = (ev: PointerEvent) => {
435
440
  const { model, graphModel } = this.props
436
441
  this.startTime = new Date().getTime()
437
442
  const { editConfigModel } = graphModel
438
443
  if (editConfigModel.adjustNodePosition && model.draggable) {
439
444
  this.stepDrag && this.stepDrag.handleMouseDown(ev)
440
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
+ }
441
456
  }
442
457
 
443
458
  handleFocus = () => {
@@ -532,9 +547,10 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
532
547
  nodeShape = (
533
548
  <g
534
549
  className={`${this.getStateClassName()} ${className}`}
535
- onMouseDown={this.handleMouseDown}
536
- onMouseUp={this.handleMouseUp}
550
+ onPointerDown={this.handleMouseDown}
551
+ onPointerUp={this.handleMouseUp}
537
552
  onClick={this.handleClick}
553
+ //因为移动端点击操作完成会按顺序触发enter、leave、click事件,所以会造成节点的闪烁,所以在这里没有统一状态为Pointer
538
554
  onMouseEnter={this.setHoverOn}
539
555
  onMouseOver={this.setHoverOn}
540
556
  onMouseLeave={this.setHoverOff}
@@ -71,7 +71,7 @@ export class BezierAdjustAnchor extends Component<IAnchorProps, IState> {
71
71
  x={x}
72
72
  y={y}
73
73
  {...adjustAnchor}
74
- onMouseDown={(ev) => {
74
+ onPointerDown={(ev) => {
75
75
  // if (edgeAddable !== false) {
76
76
  this.dragHandler.handleMouseDown(ev)
77
77
  // }
@@ -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
- mouseDownHandler = (ev: MouseEvent) => {
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, dnd } = this.props
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
- onMouseDown={this.mouseDownHandler}
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: MouseEvent) => {
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 onMouseDown={this.mouseDownHandler} onDblClick={this.dbClickHandler}>
123
+ <g
124
+ onPointerDown={this.mouseDownHandler}
125
+ onDblClick={this.dbClickHandler}
126
+ >
124
127
  {this.getShape()}
125
128
  </g>
126
129
  )