@logicflow/core 2.1.4 → 2.2.0-alpha.1

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 (82) hide show
  1. package/.turbo/turbo-build$colon$dev.log +57 -2
  2. package/.turbo/turbo-build.log +7 -7
  3. package/CHANGELOG.md +15 -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 +5 -1
  7. package/es/model/EditConfigModel.js +10 -0
  8. package/es/model/GraphModel.d.ts +1 -0
  9. package/es/model/GraphModel.js +3 -1
  10. package/es/model/node/BaseNodeModel.js +3 -1
  11. package/es/options.d.ts +3 -1
  12. package/es/tool/MultipleSelectTool.d.ts +1 -1
  13. package/es/tool/MultipleSelectTool.js +1 -1
  14. package/es/util/drag.d.ts +4 -4
  15. package/es/util/drag.js +11 -6
  16. package/es/view/Anchor.d.ts +4 -3
  17. package/es/view/Anchor.js +58 -23
  18. package/es/view/Control.js +1 -1
  19. package/es/view/Rotate.js +1 -1
  20. package/es/view/behavior/dnd.d.ts +4 -8
  21. package/es/view/behavior/dnd.js +50 -14
  22. package/es/view/edge/AdjustPoint.d.ts +1 -1
  23. package/es/view/edge/AdjustPoint.js +1 -1
  24. package/es/view/edge/BaseEdge.d.ts +2 -1
  25. package/es/view/edge/BaseEdge.js +18 -1
  26. package/es/view/edge/PolylineEdge.d.ts +1 -1
  27. package/es/view/edge/PolylineEdge.js +1 -1
  28. package/es/view/node/BaseNode.d.ts +2 -1
  29. package/es/view/node/BaseNode.js +17 -1
  30. package/es/view/overlay/BezierAdjustOverlay.js +1 -1
  31. package/es/view/overlay/CanvasOverlay.d.ts +12 -1
  32. package/es/view/overlay/CanvasOverlay.js +94 -15
  33. package/es/view/text/BaseText.d.ts +1 -1
  34. package/es/view/text/BaseText.js +1 -1
  35. package/lib/model/EditConfigModel.d.ts +5 -1
  36. package/lib/model/EditConfigModel.js +10 -0
  37. package/lib/model/GraphModel.d.ts +1 -0
  38. package/lib/model/GraphModel.js +3 -1
  39. package/lib/model/node/BaseNodeModel.js +3 -1
  40. package/lib/options.d.ts +3 -1
  41. package/lib/tool/MultipleSelectTool.d.ts +1 -1
  42. package/lib/tool/MultipleSelectTool.js +1 -1
  43. package/lib/util/drag.d.ts +4 -4
  44. package/lib/util/drag.js +11 -6
  45. package/lib/view/Anchor.d.ts +4 -3
  46. package/lib/view/Anchor.js +58 -23
  47. package/lib/view/Control.js +1 -1
  48. package/lib/view/Rotate.js +1 -1
  49. package/lib/view/behavior/dnd.d.ts +4 -8
  50. package/lib/view/behavior/dnd.js +50 -14
  51. package/lib/view/edge/AdjustPoint.d.ts +1 -1
  52. package/lib/view/edge/AdjustPoint.js +1 -1
  53. package/lib/view/edge/BaseEdge.d.ts +2 -1
  54. package/lib/view/edge/BaseEdge.js +18 -1
  55. package/lib/view/edge/PolylineEdge.d.ts +1 -1
  56. package/lib/view/edge/PolylineEdge.js +1 -1
  57. package/lib/view/node/BaseNode.d.ts +2 -1
  58. package/lib/view/node/BaseNode.js +17 -1
  59. package/lib/view/overlay/BezierAdjustOverlay.js +1 -1
  60. package/lib/view/overlay/CanvasOverlay.d.ts +12 -1
  61. package/lib/view/overlay/CanvasOverlay.js +94 -15
  62. package/lib/view/text/BaseText.d.ts +1 -1
  63. package/lib/view/text/BaseText.js +1 -1
  64. package/package.json +1 -1
  65. package/src/model/EditConfigModel.ts +6 -0
  66. package/src/model/GraphModel.ts +5 -0
  67. package/src/model/node/BaseNodeModel.ts +4 -1
  68. package/src/options.ts +6 -1
  69. package/src/tool/MultipleSelectTool.tsx +2 -2
  70. package/src/util/drag.ts +15 -12
  71. package/src/view/Anchor.tsx +84 -35
  72. package/src/view/Control.tsx +1 -1
  73. package/src/view/Rotate.tsx +1 -1
  74. package/src/view/behavior/dnd.ts +55 -16
  75. package/src/view/edge/AdjustPoint.tsx +2 -2
  76. package/src/view/edge/BaseEdge.tsx +23 -3
  77. package/src/view/edge/PolylineEdge.tsx +2 -2
  78. package/src/view/node/BaseNode.tsx +21 -5
  79. package/src/view/overlay/BezierAdjustOverlay.tsx +1 -1
  80. package/src/view/overlay/CanvasOverlay.tsx +110 -4
  81. package/src/view/text/BaseText.tsx +5 -2
  82. package/stats.html +1 -1
@@ -168,6 +168,10 @@ var BaseNode = /** @class */ (function (_super) {
168
168
  _this.handleMouseUp = function () {
169
169
  var model = _this.props.model;
170
170
  _this.mouseUpDrag = model.isDragging;
171
+ if (_this.longPressTimer) {
172
+ clearTimeout(_this.longPressTimer);
173
+ _this.longPressTimer = undefined;
174
+ }
171
175
  };
172
176
  _this.handleClick = function (e) {
173
177
  // 节点拖拽进画布之后,不触发click事件相关emit
@@ -268,6 +272,16 @@ var BaseNode = /** @class */ (function (_super) {
268
272
  if (editConfigModel.adjustNodePosition && model.draggable) {
269
273
  _this.stepDrag && _this.stepDrag.handleMouseDown(ev);
270
274
  }
275
+ if (_this.longPressTimer) {
276
+ clearTimeout(_this.longPressTimer);
277
+ }
278
+ if (ev.pointerType === 'touch') {
279
+ _this.longPressTimer = window.setTimeout(function () {
280
+ if (!_this.props.model.isDragging) {
281
+ _this.handleContextMenu(ev);
282
+ }
283
+ }, 500);
284
+ }
271
285
  };
272
286
  _this.handleFocus = function () {
273
287
  var _a = _this.props, model = _a.model, graphModel = _a.graphModel;
@@ -449,7 +463,9 @@ var BaseNode = /** @class */ (function (_super) {
449
463
  if (adjustNodePosition && draggable) {
450
464
  this.stepDrag.setStep(gridSize * SCALE_X);
451
465
  }
452
- nodeShape = (_jsx("g", __assign({ className: "".concat(this.getStateClassName(), " ").concat(className), onMouseDown: this.handleMouseDown, onMouseUp: this.handleMouseUp, onClick: this.handleClick, onMouseEnter: this.setHoverOn, onMouseOver: this.setHoverOn, onMouseLeave: this.setHoverOff, onMouseOut: this.onMouseOut, onContextMenu: this.handleContextMenu, onFocus: this.handleFocus, onBlur: this.handleBlur }, restAttributes, { children: nodeShapeInner })));
466
+ nodeShape = (_jsx("g", __assign({ className: "".concat(this.getStateClassName(), " ").concat(className), onPointerDown: this.handleMouseDown, onPointerUp: this.handleMouseUp, onClick: this.handleClick,
467
+ //因为移动端点击操作完成会按顺序触发enter、leave、click事件,所以会造成节点的闪烁,所以在这里没有统一状态为Pointer
468
+ onMouseEnter: this.setHoverOn, onMouseOver: this.setHoverOn, onMouseLeave: this.setHoverOff, onMouseOut: this.onMouseOut, onContextMenu: this.handleContextMenu, onFocus: this.handleFocus, onBlur: this.handleBlur }, restAttributes, { children: nodeShapeInner })));
453
469
  }
454
470
  return nodeShape;
455
471
  };
@@ -88,7 +88,7 @@ var BezierAdjustAnchor = /** @class */ (function (_super) {
88
88
  var x = position.x, y = position.y;
89
89
  var bezierModel = this.props.bezierModel;
90
90
  var adjustAnchor = bezierModel.getEdgeStyle().adjustAnchor;
91
- return (_jsx(Circle, __assign({ className: "lf-bezier-adjust-anchor", x: x, y: y }, adjustAnchor, { onMouseDown: function (ev) {
91
+ return (_jsx(Circle, __assign({ className: "lf-bezier-adjust-anchor", x: x, y: y }, adjustAnchor, { onPointerDown: function (ev) {
92
92
  // if (edgeAddable !== false) {
93
93
  _this.dragHandler.handleMouseDown(ev);
94
94
  // }
@@ -13,13 +13,24 @@ export declare class CanvasOverlay extends Component<IProps, IState> {
13
13
  stepDrag: StepDrag;
14
14
  stepScrollX: number;
15
15
  stepScrollY: number;
16
+ pointers: Map<number, {
17
+ x: number;
18
+ y: number;
19
+ }>;
20
+ pinchStartDistance?: number;
21
+ pinchStartScale?: number;
22
+ pinchLastCenterX?: number;
23
+ pinchLastCenterY?: number;
24
+ longPressTimer?: number;
16
25
  constructor(props: IProps);
17
26
  onDragging: ({ deltaX, deltaY }: IDragParams) => void;
18
27
  onDragEnd: () => void;
19
28
  zoomHandler: (ev: WheelEvent) => void;
20
29
  clickHandler: (ev: MouseEvent) => void;
21
30
  handleContextMenu: (ev: MouseEvent) => void;
22
- mouseDownHandler: (ev: MouseEvent) => void;
31
+ pointerDownHandler: (ev: PointerEvent) => void;
32
+ pointerMoveHandler: (ev: PointerEvent) => void;
33
+ pointerUpHandler: (ev: PointerEvent) => void;
23
34
  render(): import("preact/compat").JSX.Element;
24
35
  }
25
36
  export default CanvasOverlay;
@@ -13,17 +13,6 @@ var __extends = (this && this.__extends) || (function () {
13
13
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
14
14
  };
15
15
  })();
16
- var __assign = (this && this.__assign) || function () {
17
- __assign = Object.assign || function(t) {
18
- for (var s, i = 1, n = arguments.length; i < n; i++) {
19
- s = arguments[i];
20
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
21
- t[p] = s[p];
22
- }
23
- return t;
24
- };
25
- return __assign.apply(this, arguments);
26
- };
27
16
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
28
17
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
29
18
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -41,11 +30,16 @@ var CanvasOverlay = /** @class */ (function (_super) {
41
30
  var _this = _super.call(this) || this;
42
31
  _this.stepScrollX = 0;
43
32
  _this.stepScrollY = 0;
33
+ _this.pointers = new Map();
44
34
  // get InjectedProps() {
45
35
  // return this.props as InjectedProps;
46
36
  // }
47
37
  _this.onDragging = function (_a) {
48
38
  var deltaX = _a.deltaX, deltaY = _a.deltaY;
39
+ if (_this.longPressTimer) {
40
+ clearTimeout(_this.longPressTimer);
41
+ _this.longPressTimer = undefined;
42
+ }
49
43
  _this.setState({
50
44
  isDragging: true,
51
45
  });
@@ -123,8 +117,36 @@ var CanvasOverlay = /** @class */ (function (_super) {
123
117
  }
124
118
  };
125
119
  // 鼠标、触摸板 按下
126
- _this.mouseDownHandler = function (ev) {
120
+ _this.pointerDownHandler = function (ev) {
127
121
  var _a = _this.props.graphModel, eventCenter = _a.eventCenter, editConfigModel = _a.editConfigModel, SCALE_X = _a.transformModel.SCALE_X, gridSize = _a.gridSize;
122
+ _this.pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY });
123
+ if (_this.longPressTimer) {
124
+ clearTimeout(_this.longPressTimer);
125
+ }
126
+ if (ev.pointerType === 'touch') {
127
+ _this.longPressTimer = window.setTimeout(function () {
128
+ _this.handleContextMenu(ev);
129
+ }, 500);
130
+ }
131
+ // 检测双指触摸,初始化捏合缩放
132
+ if (_this.pointers.size === 2) {
133
+ var _b = _this.props.graphModel, transformModel = _b.transformModel, editConfigModel_1 = _b.editConfigModel;
134
+ // 记录两指当前位置用于计算初始距离
135
+ var pts = Array.from(_this.pointers.values());
136
+ var dx = pts[0].x - pts[1].x;
137
+ var dy = pts[0].y - pts[1].y;
138
+ var cx = (pts[0].x + pts[1].x) / 2;
139
+ var cy = (pts[0].y + pts[1].y) / 2;
140
+ // 记录捏合起始距离与当前缩放,后续按比例计算缩放
141
+ _this.pinchStartDistance = Math.hypot(dx, dy);
142
+ _this.pinchStartScale = transformModel.SCALE_X;
143
+ // 双指操作下取消画布拖拽,避免与捏合缩放冲突
144
+ _this.stepDrag.cancelDrag();
145
+ _this.pinchLastCenterX = cx;
146
+ _this.pinchLastCenterY = cy;
147
+ editConfigModel_1.updateEditConfig({ isPinching: true });
148
+ return;
149
+ }
128
150
  var adjustEdge = editConfigModel.adjustEdge, adjustNodePosition = editConfigModel.adjustNodePosition, stopMoveGraph = editConfigModel.stopMoveGraph;
129
151
  var target = ev.target;
130
152
  var isFrozenElement = !adjustEdge && !adjustNodePosition;
@@ -140,6 +162,63 @@ var CanvasOverlay = /** @class */ (function (_super) {
140
162
  _this.clickHandler(ev);
141
163
  }
142
164
  };
165
+ _this.pointerMoveHandler = function (ev) {
166
+ var _a;
167
+ // 记录当前指针位置(按 pointerId)
168
+ _this.pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY });
169
+ // 当已记录初始捏合距离且存在两指时,执行捏合缩放
170
+ if (_this.pinchStartDistance && _this.pointers.size >= 2) {
171
+ var _b = _this.props, graphModel = _b.graphModel, _c = _b.graphModel, editConfigModel = _c.editConfigModel, transformModel = _c.transformModel;
172
+ if (editConfigModel.stopZoomGraph)
173
+ return;
174
+ // 取消触摸长按计时,避免捏合过程中误触发上下文菜单
175
+ if (_this.longPressTimer) {
176
+ clearTimeout(_this.longPressTimer);
177
+ }
178
+ // 计算两指间当前距离
179
+ var pts = Array.from(_this.pointers.values());
180
+ var dx = pts[0].x - pts[1].x;
181
+ var dy = pts[0].y - pts[1].y;
182
+ var dist = Math.hypot(dx, dy);
183
+ // 以初始缩放为基准,根据距离比例得到新的缩放比例
184
+ var scale = ((_a = _this.pinchStartScale) !== null && _a !== void 0 ? _a : transformModel.SCALE_X) *
185
+ (dist / _this.pinchStartDistance);
186
+ // 取两指中心作为缩放原点,并转换为画布坐标系
187
+ var cx = (pts[0].x + pts[1].x) / 2;
188
+ var cy = (pts[0].y + pts[1].y) / 2;
189
+ var pos = graphModel.getPointByClient({ x: cx, y: cy });
190
+ var _d = pos.canvasOverlayPosition, x = _d.x, y = _d.y;
191
+ transformModel.zoom(scale, [x, y]);
192
+ // 双指中心位移驱动画布平移,配合缩放实现捏合移动;
193
+ if (!editConfigModel.stopMoveGraph || editConfigModel.isPinching) {
194
+ var deltaX = _this.pinchLastCenterX === undefined ? 0 : cx - _this.pinchLastCenterX;
195
+ var deltaY = _this.pinchLastCenterY === undefined ? 0 : cy - _this.pinchLastCenterY;
196
+ transformModel.translate(deltaX, deltaY);
197
+ _this.pinchLastCenterX = cx;
198
+ _this.pinchLastCenterY = cy;
199
+ }
200
+ ev.preventDefault();
201
+ }
202
+ };
203
+ _this.pointerUpHandler = function (ev) {
204
+ _this.pointers.delete(ev.pointerId);
205
+ if (_this.longPressTimer) {
206
+ clearTimeout(_this.longPressTimer);
207
+ _this.longPressTimer = undefined;
208
+ }
209
+ // 双指松开或仅剩一指:结束捏合手势并清理临时状态
210
+ if (_this.pointers.size < 2) {
211
+ // 清空捏合距离与缩放起始值
212
+ _this.pinchStartDistance = undefined;
213
+ _this.pinchStartScale = undefined;
214
+ // 清空上一帧的双指中心
215
+ _this.pinchLastCenterX = undefined;
216
+ _this.pinchLastCenterY = undefined;
217
+ var editConfigModel = _this.props.graphModel.editConfigModel;
218
+ // 标记退出捏合,框选等交互可恢复
219
+ editConfigModel.updateEditConfig({ isPinching: false });
220
+ }
221
+ };
143
222
  var _a = props.graphModel, gridSize = _a.gridSize, eventCenter = _a.eventCenter;
144
223
  _this.stepDrag = new StepDrag({
145
224
  onDragging: _this.onDragging,
@@ -159,11 +238,11 @@ var CanvasOverlay = /** @class */ (function (_super) {
159
238
  CanvasOverlay.prototype.render = function () {
160
239
  var transformModel = this.props.graphModel.transformModel;
161
240
  var transform = transformModel.getTransformStyle().transform;
162
- var _a = this.props, children = _a.children, dnd = _a.dnd;
241
+ var children = this.props.children;
163
242
  var isDragging = this.state.isDragging;
164
- return (_jsx("svg", __assign({ xmlns: "http://www.w3.org/2000/svg", width: "100%", height: "100%", name: "canvas-overlay", onWheel: this.zoomHandler, onMouseDown: this.mouseDownHandler, onContextMenu: this.handleContextMenu, className: isDragging
243
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "100%", height: "100%", name: "canvas-overlay", onWheel: this.zoomHandler, onPointerDown: this.pointerDownHandler, onPointerMove: this.pointerMoveHandler, onPointerUp: this.pointerUpHandler, onPointerCancel: this.pointerUpHandler, onContextMenu: this.handleContextMenu, style: { touchAction: 'none', WebkitUserSelect: 'none' }, className: isDragging
165
244
  ? 'lf-canvas-overlay lf-dragging'
166
- : 'lf-canvas-overlay lf-drag-able' }, dnd.eventMap(), { children: _jsx("g", { transform: transform, children: children }) })));
245
+ : 'lf-canvas-overlay lf-drag-able', children: _jsx("g", { transform: transform, children: children }) }));
167
246
  };
168
247
  CanvasOverlay = __decorate([
169
248
  observer
@@ -14,7 +14,7 @@ export declare class BaseText<P extends IBaseTextProps, S extends IBaseTextState
14
14
  stepperDrag: StepDrag;
15
15
  constructor(props: P);
16
16
  getShape(): h.JSX.Element | null;
17
- mouseDownHandler: (e: MouseEvent) => void;
17
+ mouseDownHandler: (e: PointerEvent) => void;
18
18
  onDragging: ({ deltaX, deltaY }: IDragParams) => void;
19
19
  dbClickHandler: () => void;
20
20
  render(): h.JSX.Element | undefined;
@@ -119,7 +119,7 @@ var BaseText = /** @class */ (function (_super) {
119
119
  BaseText.prototype.render = function () {
120
120
  var text = this.props.model.text;
121
121
  if (text) {
122
- return (_jsx("g", { onMouseDown: this.mouseDownHandler, onDblClick: this.dbClickHandler, children: this.getShape() }));
122
+ return (_jsx("g", { onPointerDown: this.mouseDownHandler, onDblClick: this.dbClickHandler, children: this.getShape() }));
123
123
  }
124
124
  };
125
125
  return BaseText;
@@ -114,6 +114,8 @@ export interface IEditConfigType {
114
114
  nodeTextMode: TextMode;
115
115
  edgeTextMode: TextMode;
116
116
  snapGrid: boolean;
117
+ isPinching: boolean;
118
+ anchorProximityValidate: boolean;
117
119
  }
118
120
  export type IConfigKeys = keyof IEditConfigType;
119
121
  /**
@@ -129,6 +131,7 @@ export declare class EditConfigModel {
129
131
  stopMoveGraph: boolean;
130
132
  stopScrollGraph: boolean;
131
133
  snapGrid: boolean;
134
+ isPinching: boolean;
132
135
  /*********************************************************
133
136
  * 文本相关配置(全局)
134
137
  ********************************************************/
@@ -145,6 +148,7 @@ export declare class EditConfigModel {
145
148
  edgeTextDraggable: boolean;
146
149
  edgeTextMultiple: boolean;
147
150
  edgeTextVertical: boolean;
151
+ anchorProximityValidate: boolean;
148
152
  /*********************************************************
149
153
  * 节点相关配置
150
154
  ********************************************************/
@@ -170,7 +174,7 @@ export declare class EditConfigModel {
170
174
  multipleSelectKey: string;
171
175
  constructor(config: Partial<IEditConfigType>);
172
176
  updateEditConfig(config: Partial<IEditConfigType>): void;
173
- computeConfig(config: Partial<IEditConfigType>): Partial<IEditConfigType> & Pick<Partial<IEditConfigType>, "textMode" | "adjustEdgeStartAndEnd" | "edgeTextDraggable" | "edgeTextEdit" | "nodeTextDraggable" | "nodeTextEdit" | "adjustEdge" | "edgeTextMode" | "nodeTextMode" | "allowRotate" | "allowResize" | "isSilentMode" | "stopScrollGraph" | "stopZoomGraph" | "stopMoveGraph" | "textEdit" | "snapGrid" | "adjustNodePosition" | "hoverOutline" | "nodeSelectedOutline" | "edgeSelectedOutline" | "adjustEdgeMiddle" | "adjustEdgeStart" | "adjustEdgeEnd" | "hideAnchors" | "autoExpand" | "textDraggable" | "multipleSelectKey" | "nodeTextMultiple" | "edgeTextMultiple" | "nodeTextVertical" | "edgeTextVertical">;
177
+ computeConfig(config: Partial<IEditConfigType>): Partial<IEditConfigType> & Pick<Partial<IEditConfigType>, "textMode" | "adjustEdgeStartAndEnd" | "edgeTextDraggable" | "edgeTextEdit" | "nodeTextDraggable" | "nodeTextEdit" | "adjustEdge" | "edgeTextMode" | "nodeTextMode" | "allowRotate" | "allowResize" | "isSilentMode" | "stopScrollGraph" | "stopZoomGraph" | "stopMoveGraph" | "textEdit" | "snapGrid" | "adjustEdgeMiddle" | "adjustEdgeStart" | "adjustEdgeEnd" | "adjustNodePosition" | "hideAnchors" | "autoExpand" | "hoverOutline" | "nodeSelectedOutline" | "edgeSelectedOutline" | "textDraggable" | "multipleSelectKey" | "nodeTextMultiple" | "edgeTextMultiple" | "nodeTextVertical" | "edgeTextVertical" | "isPinching" | "anchorProximityValidate">;
174
178
  updateTextMode(textMode: TextMode): void;
175
179
  getConfig(): IEditConfigType;
176
180
  }
@@ -65,6 +65,8 @@ var allKeys = [
65
65
  'edgeTextMultiple', // 是否支持多个边文本
66
66
  'nodeTextVertical', // 节点文本是否纵向显示
67
67
  'edgeTextVertical', // 边文本是否纵向显示
68
+ 'isPinching', //是否是双指捏合态
69
+ 'anchorProximityValidate', // 仅在靠近锚点时触发连接校验
68
70
  ];
69
71
  /**
70
72
  * 页面编辑配置
@@ -79,6 +81,7 @@ var EditConfigModel = /** @class */ (function () {
79
81
  this.stopMoveGraph = false;
80
82
  this.stopScrollGraph = false;
81
83
  this.snapGrid = false;
84
+ this.isPinching = false;
82
85
  /*********************************************************
83
86
  * 文本相关配置(全局)
84
87
  ********************************************************/
@@ -97,6 +100,7 @@ var EditConfigModel = /** @class */ (function () {
97
100
  this.edgeTextDraggable = false;
98
101
  this.edgeTextMultiple = false; // 是否支持多个边文本
99
102
  this.edgeTextVertical = false; // 边文本朝向是否是纵向
103
+ this.anchorProximityValidate = false; // 仅在靠近锚点时触发连接校验
100
104
  /*********************************************************
101
105
  * 节点相关配置
102
106
  ********************************************************/
@@ -196,6 +200,9 @@ var EditConfigModel = /** @class */ (function () {
196
200
  __decorate([
197
201
  mobx_1.observable
198
202
  ], EditConfigModel.prototype, "snapGrid", void 0);
203
+ __decorate([
204
+ mobx_1.observable
205
+ ], EditConfigModel.prototype, "isPinching", void 0);
199
206
  __decorate([
200
207
  mobx_1.observable
201
208
  ], EditConfigModel.prototype, "textMode", void 0);
@@ -235,6 +242,9 @@ var EditConfigModel = /** @class */ (function () {
235
242
  __decorate([
236
243
  mobx_1.observable
237
244
  ], EditConfigModel.prototype, "edgeTextVertical", void 0);
245
+ __decorate([
246
+ mobx_1.observable
247
+ ], EditConfigModel.prototype, "anchorProximityValidate", void 0);
238
248
  __decorate([
239
249
  mobx_1.observable
240
250
  ], EditConfigModel.prototype, "hideAnchors", void 0);
@@ -30,6 +30,7 @@ export declare class GraphModel {
30
30
  animation?: boolean | LFOptions.AnimationConfig;
31
31
  idGenerator?: (type?: string) => string | undefined;
32
32
  edgeGenerator: LFOptions.Definition['edgeGenerator'];
33
+ customTargetAnchor?: LFOptions.Definition['customTargetAnchor'];
33
34
  nodeModelMap: Map<string, BaseNodeModel>;
34
35
  edgeModelMap: Map<string, BaseEdgeModel>;
35
36
  elementsModelMap: Map<string, BaseNodeModel | BaseEdgeModel>;
@@ -102,7 +102,7 @@ var GraphModel = /** @class */ (function () {
102
102
  // 控制是否开启局部渲染
103
103
  this.partial = false;
104
104
  this.waitCleanEffects = [];
105
- var container = options.container, partial = options.partial, _c = options.background, background = _c === void 0 ? {} : _c, grid = options.grid, idGenerator = options.idGenerator, edgeGenerator = options.edgeGenerator, animation = options.animation, customTrajectory = options.customTrajectory;
105
+ var container = options.container, partial = options.partial, _c = options.background, background = _c === void 0 ? {} : _c, grid = options.grid, idGenerator = options.idGenerator, edgeGenerator = options.edgeGenerator, animation = options.animation, customTrajectory = options.customTrajectory, customTargetAnchor = options.customTargetAnchor;
106
106
  this.rootEl = container;
107
107
  this.partial = !!partial;
108
108
  this.background = background;
@@ -157,6 +157,7 @@ var GraphModel = /** @class */ (function () {
157
157
  this.idGenerator = idGenerator;
158
158
  this.edgeGenerator = (0, util_1.createEdgeGenerator)(this, edgeGenerator);
159
159
  this.customTrajectory = customTrajectory;
160
+ this.customTargetAnchor = customTargetAnchor;
160
161
  }
161
162
  Object.defineProperty(GraphModel.prototype, "nodesMap", {
162
163
  get: function () {
@@ -1102,6 +1103,7 @@ var GraphModel = /** @class */ (function () {
1102
1103
  var _a;
1103
1104
  this.selectElements.forEach(function (element) {
1104
1105
  element === null || element === void 0 ? void 0 : element.setSelected(false);
1106
+ element === null || element === void 0 ? void 0 : element.setHovered(false);
1105
1107
  });
1106
1108
  this.selectElements.clear();
1107
1109
  /**
@@ -552,7 +552,9 @@ var BaseNodeModel = /** @class */ (function () {
552
552
  * 手动连接边到节点时,需要连接的锚点
553
553
  */
554
554
  BaseNodeModel.prototype.getTargetAnchor = function (position) {
555
- return (0, util_1.getClosestAnchor)(position, this);
555
+ var _a;
556
+ var customTargetAnchor = this.graphModel.customTargetAnchor;
557
+ return ((_a = customTargetAnchor === null || customTargetAnchor === void 0 ? void 0 : customTargetAnchor(this, position)) !== null && _a !== void 0 ? _a : (0, util_1.getClosestAnchor)(position, this));
556
558
  };
557
559
  /**
558
560
  * 获取节点BBox
package/lib/options.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TransformModel } from './model';
1
+ import type { TransformModel, BaseNodeModel, Model } from './model';
2
2
  import { createElement as h } from 'preact/compat';
3
3
  import LogicFlow from './LogicFlow';
4
4
  import { KeyboardDef } from './keyboard';
@@ -21,6 +21,7 @@ export declare namespace Options {
21
21
  edge: boolean;
22
22
  };
23
23
  type EdgeGeneratorType = (sourceNode: LogicFlow.NodeData, targetNode: LogicFlow.NodeData, currentEdge?: Partial<LogicFlow.EdgeConfig>) => any;
24
+ type customTargetAnchorType = (nodeModel: BaseNodeModel, position: LogicFlow.Point) => Model.AnchorInfo | undefined;
24
25
  interface CustomAnchorLineProps {
25
26
  sourcePoint: LogicFlow.Point;
26
27
  targetPoint: LogicFlow.Point;
@@ -67,6 +68,7 @@ export declare namespace Options {
67
68
  disabledTools?: string[];
68
69
  idGenerator?: (type?: string) => string;
69
70
  edgeGenerator?: EdgeGeneratorType;
71
+ customTargetAnchor?: customTargetAnchorType;
70
72
  customTrajectory?: (props: CustomAnchorLineProps) => h.JSX.Element;
71
73
  themeMode?: 'radius' | 'dark' | 'colorful';
72
74
  parentTransform?: TransformModel;
@@ -5,7 +5,7 @@ export default class MultipleSelect extends Component<IToolProps> {
5
5
  static toolName: string;
6
6
  stepDrag: StepDrag;
7
7
  constructor(props: IToolProps);
8
- handleMouseDown: (ev: MouseEvent) => void;
8
+ handleMouseDown: (ev: PointerEvent) => void;
9
9
  handleWheelEvent: (ev: WheelEvent) => void;
10
10
  onDragging: ({ deltaX, deltaY }: IDragParams) => void;
11
11
  handleContextMenu: (ev: MouseEvent) => void;
@@ -149,7 +149,7 @@ var MultipleSelect = /** @class */ (function (_super) {
149
149
  height: "".concat(y1 - y + 20 * SCALE_Y, "px"),
150
150
  'border-width': "".concat(2 * SCALE_X, "px"),
151
151
  };
152
- return ((0, jsx_runtime_1.jsx)("div", { className: "lf-multiple-select", style: style, onMouseDown: this.handleMouseDown, onContextMenu: this.handleContextMenu, onWheel: this.handleWheelEvent }));
152
+ return ((0, jsx_runtime_1.jsx)("div", { className: "lf-multiple-select", style: style, onPointerDown: this.handleMouseDown, onContextMenu: this.handleContextMenu, onWheel: this.handleWheelEvent }));
153
153
  };
154
154
  MultipleSelect.toolName = 'multiple-select-tool';
155
155
  MultipleSelect = __decorate([
@@ -3,7 +3,7 @@ import EventEmitter from '../event/eventEmitter';
3
3
  export type IDragParams = {
4
4
  deltaX: number;
5
5
  deltaY: number;
6
- event?: MouseEvent;
6
+ event?: PointerEvent;
7
7
  [key: string]: unknown;
8
8
  };
9
9
  export type ICreateDragParams = {
@@ -40,9 +40,9 @@ export declare class StepDrag {
40
40
  constructor({ onDragStart, onDragging, onDragEnd, eventType, eventCenter, step, isStopPropagation, model, data, }: IStepperDragProps);
41
41
  setStep(step: number): void;
42
42
  setModel(model: Model.BaseModel): void;
43
- handleMouseDown: (e: MouseEvent) => void;
44
- handleMouseMove: (e: MouseEvent) => void;
45
- handleMouseUp: (e: MouseEvent) => void;
43
+ handleMouseDown: (e: PointerEvent) => void;
44
+ handleMouseMove: (e: PointerEvent) => void;
45
+ handleMouseUp: (e: PointerEvent) => void;
46
46
  cancelDrag: () => void;
47
47
  destroy: () => void;
48
48
  }
package/lib/util/drag.js CHANGED
@@ -29,8 +29,8 @@ var StepDrag = /** @class */ (function () {
29
29
  _this.isStartDragging = true;
30
30
  _this.startX = e.clientX;
31
31
  _this.startY = e.clientY;
32
- DOC.addEventListener('mousemove', _this.handleMouseMove, false);
33
- DOC.addEventListener('mouseup', _this.handleMouseUp, false);
32
+ DOC.addEventListener('pointermove', _this.handleMouseMove, false);
33
+ DOC.addEventListener('pointerup', _this.handleMouseUp, false);
34
34
  var elementData = (_a = _this.model) === null || _a === void 0 ? void 0 : _a.getData();
35
35
  (_b = _this.eventCenter) === null || _b === void 0 ? void 0 : _b.emit(constant_1.EventType["".concat(_this.eventType, "_MOUSEDOWN")], {
36
36
  e: e,
@@ -42,6 +42,7 @@ var StepDrag = /** @class */ (function () {
42
42
  var _a, _b;
43
43
  if (_this.isStopPropagation)
44
44
  e.stopPropagation();
45
+ e.preventDefault();
45
46
  if (!_this.isStartDragging)
46
47
  return;
47
48
  _this.sumDeltaX += e.clientX - _this.startX;
@@ -97,11 +98,15 @@ var StepDrag = /** @class */ (function () {
97
98
  _this.isStartDragging = false;
98
99
  if (_this.isStopPropagation)
99
100
  e.stopPropagation();
101
+ var target = e.target;
102
+ if (target && typeof target.releasePointerCapture === 'function') {
103
+ target.releasePointerCapture(e.pointerId);
104
+ }
100
105
  // fix #568: 如果onDragging在下一个事件循环中触发,而drop在当前事件循环,会出现问题。
101
106
  Promise.resolve().then(function () {
102
107
  var _a, _b, _c;
103
- DOC.removeEventListener('mousemove', _this.handleMouseMove, false);
104
- DOC.removeEventListener('mouseup', _this.handleMouseUp, false);
108
+ DOC.removeEventListener('pointermove', _this.handleMouseMove, false);
109
+ DOC.removeEventListener('pointerup', _this.handleMouseUp, false);
105
110
  var elementData = (_a = _this.model) === null || _a === void 0 ? void 0 : _a.getData();
106
111
  (_b = _this.eventCenter) === null || _b === void 0 ? void 0 : _b.emit(constant_1.EventType["".concat(_this.eventType, "_MOUSEUP")], {
107
112
  e: e,
@@ -119,8 +124,8 @@ var StepDrag = /** @class */ (function () {
119
124
  };
120
125
  this.cancelDrag = function () {
121
126
  var DOC = window === null || window === void 0 ? void 0 : window.document;
122
- DOC.removeEventListener('mousemove', _this.handleMouseMove, false);
123
- DOC.removeEventListener('mouseup', _this.handleMouseUp, false);
127
+ DOC.removeEventListener('pointermove', _this.handleMouseMove, false);
128
+ DOC.removeEventListener('pointerup', _this.handleMouseUp, false);
124
129
  _this.onDragEnd({ event: undefined });
125
130
  _this.isDragging = false;
126
131
  };
@@ -13,7 +13,7 @@ interface IProps {
13
13
  anchorIndex: number;
14
14
  graphModel: GraphModel;
15
15
  nodeModel: BaseNodeModel;
16
- setHoverOff: (e: MouseEvent) => void;
16
+ setHoverOff: (e: PointerEvent) => void;
17
17
  }
18
18
  interface IState {
19
19
  startX: number;
@@ -38,8 +38,9 @@ declare class Anchor extends Component<IProps, IState> {
38
38
  incomingEdgeList: import("../model").BaseEdgeModel<LogicFlow.PropertiesType>[];
39
39
  outgoingEdgeList: import("../model").BaseEdgeModel<LogicFlow.PropertiesType>[];
40
40
  };
41
- checkEnd: (event: MouseEvent | null | undefined) => import("../model").BaseEdgeModel<LogicFlow.PropertiesType> | null | undefined;
42
- moveAnchorEnd(endX: number, endY: number): void;
41
+ checkEnd: (event: PointerEvent | null | undefined) => import("../model").BaseEdgeModel<LogicFlow.PropertiesType> | null | undefined;
42
+ moveAnchorEnd(endX: number, endY: number, event?: PointerEvent): void;
43
+ validateAndSetState(targetNode: BaseNodeModel, anchorId: string | undefined, targetAnchor: AnchorConfig, nodeModel: BaseNodeModel, anchorData: AnchorConfig): void;
43
44
  isShowLine(): boolean;
44
45
  render(): import("preact/compat").JSX.Element;
45
46
  }
@@ -105,7 +105,7 @@ var Anchor = /** @class */ (function (_super) {
105
105
  endY: y1,
106
106
  dragging: true,
107
107
  });
108
- _this.moveAnchorEnd(x1, y1);
108
+ _this.moveAnchorEnd(x1, y1, event);
109
109
  if (nearBoundary.length > 0 && !stopMoveGraph && autoExpand) {
110
110
  _this.t = (0, util_1.createRaf)(function () {
111
111
  var _a = __read(nearBoundary, 2), translateX = _a[0], translateY = _a[1];
@@ -115,7 +115,7 @@ var Anchor = /** @class */ (function (_super) {
115
115
  endX: endX - translateX,
116
116
  endY: endY - translateY,
117
117
  });
118
- _this.moveAnchorEnd(endX - translateX, endY - translateY);
118
+ _this.moveAnchorEnd(endX - translateX, endY - translateY, event);
119
119
  });
120
120
  }
121
121
  eventCenter.emit(constant_1.EventType.ANCHOR_DRAG, {
@@ -141,6 +141,11 @@ var Anchor = /** @class */ (function (_super) {
141
141
  _this.sourceRuleResults.clear();
142
142
  _this.targetRuleResults.clear();
143
143
  var _b = _this.props, graphModel = _b.graphModel, nodeModel = _b.nodeModel, anchorData = _b.anchorData;
144
+ // 拖拽结束清理:取消悬浮态
145
+ if (_this.preTargetNode) {
146
+ _this.preTargetNode.setHovered(false);
147
+ _this.preTargetNode = undefined;
148
+ }
144
149
  graphModel.eventCenter.emit(constant_1.EventType.ANCHOR_DRAGEND, {
145
150
  data: anchorData,
146
151
  e: event,
@@ -244,9 +249,8 @@ var Anchor = /** @class */ (function (_super) {
244
249
  enumerable: false,
245
250
  configurable: true
246
251
  });
247
- Anchor.prototype.moveAnchorEnd = function (endX, endY) {
248
- var _a, _b;
249
- var _c = this.props, graphModel = _c.graphModel, nodeModel = _c.nodeModel, anchorData = _c.anchorData;
252
+ Anchor.prototype.moveAnchorEnd = function (endX, endY, event) {
253
+ var _a = this.props, graphModel = _a.graphModel, nodeModel = _a.nodeModel, anchorData = _a.anchorData;
250
254
  var info = (0, util_1.targetNodeInfo)({
251
255
  x: endX,
252
256
  y: endY,
@@ -262,30 +266,61 @@ var Anchor = /** @class */ (function (_super) {
262
266
  return;
263
267
  }
264
268
  this.preTargetNode = targetNode;
265
- // 支持节点的每个锚点单独设置是否可连接,因此规则key去nodeId + anchorId作为唯一值
266
- var targetInfoId = "".concat(nodeModel.id, "_").concat(targetNode.id, "_").concat(anchorId, "_").concat(anchorData.id);
267
- // 查看鼠标是否进入过target,若有检验结果,表示进入过, 就不重复计算了。
268
- if (!this.targetRuleResults.has(targetInfoId)) {
269
- var targetAnchor = info.anchor;
270
- var sourceRuleResult = nodeModel.isAllowConnectedAsSource(targetNode, anchorData, targetAnchor);
271
- var targetRuleResult = targetNode.isAllowConnectedAsTarget(nodeModel, anchorData, targetAnchor);
272
- this.sourceRuleResults.set(targetInfoId, (0, util_1.formatAnchorConnectValidateData)(sourceRuleResult));
273
- this.targetRuleResults.set(targetInfoId, (0, util_1.formatAnchorConnectValidateData)(targetRuleResult));
269
+ var anchorDist = (0, util_1.distance)(endX, endY, info.anchor.x, info.anchor.y);
270
+ var validateDistance = 10;
271
+ var editConfigModel = graphModel.editConfigModel;
272
+ if (!editConfigModel.anchorProximityValidate ||
273
+ anchorDist <= validateDistance) {
274
+ this.validateAndSetState(targetNode, anchorId, info.anchor, nodeModel, anchorData);
274
275
  }
275
- var isSourcePass = ((_a = this.sourceRuleResults.get(targetInfoId)) !== null && _a !== void 0 ? _a : {}).isAllPass;
276
- var isTargetPass = ((_b = this.targetRuleResults.get(targetInfoId)) !== null && _b !== void 0 ? _b : {}).isAllPass;
277
- // 实时提示出即将链接的锚点
278
- if (isSourcePass && isTargetPass) {
279
- targetNode.setElementState(constant_1.ElementState.ALLOW_CONNECT);
280
- }
281
- else {
282
- targetNode.setElementState(constant_1.ElementState.NOT_ALLOW_CONNECT);
276
+ // 人工触发进入目标节点事件,同步设置 hovered 以驱动锚点显隐和样式
277
+ if (!targetNode.isHovered) {
278
+ var nodeData = targetNode.getData();
279
+ if (event) {
280
+ graphModel.eventCenter.emit(constant_1.EventType.NODE_MOUSEENTER, {
281
+ data: nodeData,
282
+ e: event,
283
+ });
284
+ }
285
+ targetNode.setHovered(true);
283
286
  }
284
287
  }
285
288
  else if (this.preTargetNode &&
286
289
  this.preTargetNode.state !== constant_1.ElementState.DEFAULT) {
287
290
  // 为了保证鼠标离开的时候,将上一个节点状态重置为正常状态。
288
291
  this.preTargetNode.setElementState(constant_1.ElementState.DEFAULT);
292
+ // 未命中任何节点:人工派发离开事件并取消悬浮,避免状态残留
293
+ var prevData = this.preTargetNode.getData();
294
+ if (event) {
295
+ graphModel.eventCenter.emit(constant_1.EventType.NODE_MOUSELEAVE, {
296
+ data: prevData,
297
+ e: event,
298
+ });
299
+ }
300
+ this.preTargetNode.setHovered(false);
301
+ this.preTargetNode = undefined;
302
+ }
303
+ };
304
+ // 校验 source/target 连接规则并设置目标节点状态
305
+ Anchor.prototype.validateAndSetState = function (targetNode, anchorId, targetAnchor, nodeModel, anchorData) {
306
+ var _a, _b;
307
+ var targetInfoId = "".concat(nodeModel.id, "_").concat(targetNode.id, "_").concat(anchorId, "_").concat(anchorData.id);
308
+ if (!this.targetRuleResults.has(targetInfoId)) {
309
+ // 首次计算并缓存源/目标两侧的规则校验结果
310
+ var sourceRuleResult = nodeModel.isAllowConnectedAsSource(targetNode, anchorData, targetAnchor);
311
+ var targetRuleResult = targetNode.isAllowConnectedAsTarget(nodeModel, anchorData, targetAnchor);
312
+ this.sourceRuleResults.set(targetInfoId, (0, util_1.formatAnchorConnectValidateData)(sourceRuleResult));
313
+ this.targetRuleResults.set(targetInfoId, (0, util_1.formatAnchorConnectValidateData)(targetRuleResult));
314
+ }
315
+ // 读取缓存的校验结果
316
+ var isSourcePass = ((_a = this.sourceRuleResults.get(targetInfoId)) !== null && _a !== void 0 ? _a : {}).isAllPass;
317
+ var isTargetPass = ((_b = this.targetRuleResults.get(targetInfoId)) !== null && _b !== void 0 ? _b : {}).isAllPass;
318
+ // 两侧都通过则允许连接,否则标记为不允许连接
319
+ if (isSourcePass && isTargetPass) {
320
+ targetNode.setElementState(constant_1.ElementState.ALLOW_CONNECT);
321
+ }
322
+ else {
323
+ targetNode.setElementState(constant_1.ElementState.NOT_ALLOW_CONNECT);
289
324
  }
290
325
  };
291
326
  Anchor.prototype.isShowLine = function () {
@@ -307,7 +342,7 @@ var Anchor = /** @class */ (function (_super) {
307
342
  e: ev,
308
343
  nodeModel: nodeModel,
309
344
  });
310
- }, onMouseDown: function (ev) {
345
+ }, onPointerDown: function (ev) {
311
346
  graphModel.eventCenter.emit(constant_1.EventType.ANCHOR_MOUSEDOWN, {
312
347
  data: anchorData,
313
348
  e: ev,