@logicflow/core 2.0.16 → 2.1.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 (42) hide show
  1. package/.turbo/turbo-build$colon$dev.log +2 -2
  2. package/.turbo/turbo-build.log +5 -5
  3. package/CHANGELOG.md +22 -0
  4. package/dist/index.min.js +1 -1
  5. package/dist/index.min.js.map +1 -1
  6. package/es/LogicFlow.js +4 -1
  7. package/es/constant/index.d.ts +3 -1
  8. package/es/constant/index.js +2 -0
  9. package/es/keyboard/shortcut.js +7 -0
  10. package/es/model/GraphModel.js +2 -0
  11. package/es/model/SnaplineModel.d.ts +2 -1
  12. package/es/model/SnaplineModel.js +26 -11
  13. package/es/options.d.ts +1 -0
  14. package/es/util/resize.d.ts +12 -10
  15. package/es/util/resize.js +160 -81
  16. package/es/view/Control.d.ts +5 -1
  17. package/es/view/Control.js +23 -2
  18. package/es/view/behavior/dnd.js +3 -0
  19. package/lib/LogicFlow.js +4 -1
  20. package/lib/constant/index.d.ts +3 -1
  21. package/lib/constant/index.js +2 -0
  22. package/lib/keyboard/shortcut.js +7 -0
  23. package/lib/model/GraphModel.js +2 -0
  24. package/lib/model/SnaplineModel.d.ts +2 -1
  25. package/lib/model/SnaplineModel.js +26 -11
  26. package/lib/options.d.ts +1 -0
  27. package/lib/util/resize.d.ts +12 -10
  28. package/lib/util/resize.js +162 -83
  29. package/lib/view/Control.d.ts +5 -1
  30. package/lib/view/Control.js +22 -1
  31. package/lib/view/behavior/dnd.js +3 -0
  32. package/package.json +1 -1
  33. package/src/LogicFlow.tsx +7 -2
  34. package/src/constant/index.ts +2 -0
  35. package/src/keyboard/shortcut.ts +6 -0
  36. package/src/model/GraphModel.ts +2 -0
  37. package/src/model/SnaplineModel.ts +29 -11
  38. package/src/options.ts +1 -0
  39. package/src/util/resize.ts +200 -112
  40. package/src/view/Control.tsx +29 -5
  41. package/src/view/behavior/dnd.ts +3 -0
  42. package/stats.html +1 -1
package/es/LogicFlow.js CHANGED
@@ -83,7 +83,7 @@ var LogicFlow = /** @class */ (function () {
83
83
  keyboard: initOptions.keyboard,
84
84
  });
85
85
  if (initOptions.snapline !== false) {
86
- this.snaplineModel = new SnaplineModel(this.graphModel);
86
+ this.snaplineModel = new SnaplineModel(this.graphModel, initOptions.snaplineEpsilon);
87
87
  snapline(eventCenter, this.snaplineModel);
88
88
  }
89
89
  if (!initOptions.isSilentMode) {
@@ -796,6 +796,9 @@ var LogicFlow = /** @class */ (function () {
796
796
  var _b = this.graphModel.grid.size, size = _b === void 0 ? 1 : _b;
797
797
  this.graphModel.updateGridSize(config.snapGrid ? size : 1);
798
798
  }
799
+ this.emit(EventType.EDIT_CONFIG_CHANGED, {
800
+ data: editConfigModel.getConfig(),
801
+ });
799
802
  };
800
803
  /**
801
804
  * 获取流程图当前编辑相关设置
@@ -82,6 +82,7 @@ export declare enum EventType {
82
82
  BLANK_DRAG = "blank:drag",
83
83
  BLANK_DROP = "blank:drop",
84
84
  BLANK_MOUSEMOVE = "blank:mousemove",
85
+ BLANK_CANVAS_MOUSEMOVE = "blank:canvas-mousemove",
85
86
  BLANK_MOUSEUP = "blank:mouseup",
86
87
  BLANK_CLICK = "blank:click",
87
88
  BLANK_CONTEXTMENU = "blank:contextmenu",
@@ -129,7 +130,8 @@ export declare enum EventType {
129
130
  HISTORY_CHANGE = "history:change",
130
131
  GRAPH_TRANSFORM = "graph:transform",
131
132
  GRAPH_RENDERED = "graph:rendered",
132
- GRAPH_UPDATED = "graph:updated"
133
+ GRAPH_UPDATED = "graph:updated",
134
+ EDIT_CONFIG_CHANGED = "editConfig:changed"
133
135
  }
134
136
  export declare enum OverlapMode {
135
137
  DEFAULT = 0,// 默认
@@ -92,6 +92,7 @@ export var EventType;
92
92
  EventType["BLANK_DRAG"] = "blank:drag";
93
93
  EventType["BLANK_DROP"] = "blank:drop";
94
94
  EventType["BLANK_MOUSEMOVE"] = "blank:mousemove";
95
+ EventType["BLANK_CANVAS_MOUSEMOVE"] = "blank:canvas-mousemove";
95
96
  EventType["BLANK_MOUSEUP"] = "blank:mouseup";
96
97
  EventType["BLANK_CLICK"] = "blank:click";
97
98
  EventType["BLANK_CONTEXTMENU"] = "blank:contextmenu";
@@ -144,6 +145,7 @@ export var EventType;
144
145
  EventType["GRAPH_TRANSFORM"] = "graph:transform";
145
146
  EventType["GRAPH_RENDERED"] = "graph:rendered";
146
147
  EventType["GRAPH_UPDATED"] = "graph:updated";
148
+ EventType["EDIT_CONFIG_CHANGED"] = "editConfig:changed";
147
149
  })(EventType || (EventType = {}));
148
150
  export var OverlapMode;
149
151
  (function (OverlapMode) {
@@ -24,12 +24,19 @@ import { isEmpty } from 'lodash-es';
24
24
  import { map } from 'lodash-es';
25
25
  var selected = null;
26
26
  export function translateNodeData(nodeData, distance) {
27
+ var _a, _b;
27
28
  nodeData.x += distance;
28
29
  nodeData.y += distance;
29
30
  if (!isEmpty(nodeData.text)) {
30
31
  nodeData.text.x += distance;
31
32
  nodeData.text.y += distance;
32
33
  }
34
+ if (!isEmpty((_a = nodeData.properties) === null || _a === void 0 ? void 0 : _a._label)) {
35
+ (_b = nodeData.properties) === null || _b === void 0 ? void 0 : _b._label.forEach(function (label) {
36
+ label.x += distance;
37
+ label.y += distance;
38
+ });
39
+ }
33
40
  return nodeData;
34
41
  }
35
42
  export function translateEdgeData(edgeData, distance) {
@@ -869,6 +869,8 @@ var GraphModel = /** @class */ (function () {
869
869
  }
870
870
  if (edgeOriginData.id && this.edgesMap[edgeOriginData.id]) {
871
871
  delete edgeOriginData.id;
872
+ delete edgeOriginData.sourceAnchorId;
873
+ delete edgeOriginData.targetAnchorId;
872
874
  }
873
875
  var Model = this.getModel(type);
874
876
  if (!Model) {
@@ -12,7 +12,8 @@ export declare class SnaplineModel {
12
12
  isShowHorizontal: boolean;
13
13
  isShowVertical: boolean;
14
14
  position: Position;
15
- constructor(graphModel: GraphModel);
15
+ epsilon: number;
16
+ constructor(graphModel: GraphModel, epsilon?: number);
16
17
  getStyle(): {
17
18
  [x: string]: unknown;
18
19
  fill?: string | undefined;
@@ -18,7 +18,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
18
18
  import { action, observable } from 'mobx';
19
19
  import { getNodeBBox } from '../util';
20
20
  var SnaplineModel = /** @class */ (function () {
21
- function SnaplineModel(graphModel) {
21
+ function SnaplineModel(graphModel, epsilon) {
22
+ if (epsilon === void 0) { epsilon = 1; }
22
23
  this.isShowHorizontal = false;
23
24
  this.isShowVertical = false;
24
25
  this.position = {
@@ -26,6 +27,7 @@ var SnaplineModel = /** @class */ (function () {
26
27
  y: 0,
27
28
  };
28
29
  this.graphModel = graphModel;
30
+ this.epsilon = epsilon;
29
31
  }
30
32
  SnaplineModel.prototype.getStyle = function () {
31
33
  return __assign({}, this.graphModel.theme.snapline);
@@ -39,10 +41,10 @@ var SnaplineModel = /** @class */ (function () {
39
41
  var item = nodes[i];
40
42
  // 排除当前节点
41
43
  if (item.id !== draggingNode.id) {
42
- if (x === item.x) {
44
+ if (equal(x, item.x, this.epsilon)) {
43
45
  isShowVertical = true;
44
46
  }
45
- if (y === item.y) {
47
+ if (equal(y, item.y, this.epsilon)) {
46
48
  isShowHorizontal = true;
47
49
  }
48
50
  // 如果水平垂直都显示,则停止循环。减少不必要的遍历
@@ -84,15 +86,15 @@ var SnaplineModel = /** @class */ (function () {
84
86
  if (item.id !== draggingNode.id) {
85
87
  var itemData = getNodeBBox(item);
86
88
  // 如果节点的最大最小Y轴坐标与节点的最大最小Y轴坐标相等,展示水平线
87
- if (itemData.minY === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.minY) ||
88
- itemData.maxY === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.minY)) {
89
+ if (equal(itemData.minY, draggingData === null || draggingData === void 0 ? void 0 : draggingData.minY, this.epsilon) ||
90
+ equal(itemData.maxY, draggingData === null || draggingData === void 0 ? void 0 : draggingData.minY, this.epsilon)) {
89
91
  // 找到则停止循环。减少不必要的遍历
90
92
  isShowHorizontal = true;
91
93
  horizontalY = draggingData.minY;
92
94
  break;
93
95
  }
94
- if (itemData.minY === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxY) ||
95
- itemData.maxY === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxY)) {
96
+ if (equal(itemData.minY, draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxY, this.epsilon) ||
97
+ equal(itemData.maxY, draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxY, this.epsilon)) {
96
98
  isShowHorizontal = true;
97
99
  horizontalY = draggingData.maxY;
98
100
  break;
@@ -129,15 +131,20 @@ var SnaplineModel = /** @class */ (function () {
129
131
  if (item.id !== draggingNode.id) {
130
132
  var itemData = getNodeBBox(item);
131
133
  // 如果节点的最大最小X轴坐标与节点的最大最小X轴坐标相等,展示垂直线
132
- if (itemData.minX === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.minX) ||
133
- itemData.maxX === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.minX)) {
134
+ if (equal(itemData.minX, draggingData === null || draggingData === void 0 ? void 0 : draggingData.minX, this.epsilon)) {
135
+ isShowVertical = true;
136
+ verticalX = draggingData.minX;
137
+ break;
138
+ }
139
+ if (equal(itemData.minX, draggingData === null || draggingData === void 0 ? void 0 : draggingData.minX, this.epsilon) ||
140
+ equal(itemData.maxX, draggingData === null || draggingData === void 0 ? void 0 : draggingData.minX, this.epsilon)) {
134
141
  // 找到则停止循环。减少不必要的遍历
135
142
  isShowVertical = true;
136
143
  verticalX = draggingData.minX;
137
144
  break;
138
145
  }
139
- if (itemData.minX === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxX) ||
140
- itemData.maxX === (draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxX)) {
146
+ if (equal(itemData.minX, draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxX, this.epsilon) ||
147
+ equal(itemData.maxX, draggingData === null || draggingData === void 0 ? void 0 : draggingData.maxX, this.epsilon)) {
141
148
  isShowVertical = true;
142
149
  verticalX = draggingData.maxX;
143
150
  break;
@@ -213,4 +220,12 @@ var SnaplineModel = /** @class */ (function () {
213
220
  return SnaplineModel;
214
221
  }());
215
222
  export { SnaplineModel };
223
+ function equal(num1, num2, epsilon) {
224
+ if (Math.abs(num1 - num2) <= epsilon) {
225
+ return true;
226
+ }
227
+ else {
228
+ return false;
229
+ }
230
+ }
216
231
  export default SnaplineModel;
package/es/options.d.ts CHANGED
@@ -56,6 +56,7 @@ export declare namespace Options {
56
56
  history?: boolean;
57
57
  outline?: boolean;
58
58
  snapline?: boolean;
59
+ snaplineEpsilon?: number;
59
60
  textEdit?: boolean;
60
61
  guards?: GuardsConfig;
61
62
  overlapMode?: OverlapMode;
@@ -3,6 +3,14 @@ import { BaseNodeModel, GraphModel } from '../model';
3
3
  import ResizeInfo = ResizeControl.ResizeInfo;
4
4
  import ResizeNodeData = ResizeControl.ResizeNodeData;
5
5
  import type { SimplePoint } from '../algorithm/rotate';
6
+ export declare function calculateWidthAndHeight(startRotatedTouchControlPoint: SimplePoint, endRotatedTouchControlPoint: SimplePoint, oldCenter: SimplePoint, angle: number, freezeWidth: boolean | undefined, freezeHeight: boolean | undefined, oldWidth: number, oldHeight: number): {
7
+ width: number;
8
+ height: number;
9
+ center: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ };
6
14
  /**
7
15
  * 计算 Control 拖动后,节点的高度信息
8
16
  * @param index
@@ -11,7 +19,7 @@ import type { SimplePoint } from '../algorithm/rotate';
11
19
  * @param freezeWidth
12
20
  * @param freezeHeight
13
21
  */
14
- export declare const recalcResizeInfo: (index: ResizeControlIndex, resizeInfo: ResizeInfo, pct: number | undefined, freezeWidth: boolean | undefined, freezeHeight: boolean | undefined, rotate: number | undefined, controlX: number | undefined, controlY: number | undefined, oldCenterX: number, oldCenterY: number) => ResizeInfo;
22
+ export declare const recalcResizeInfo: (index: ResizeControlIndex, resizeInfo: ResizeInfo, pct: number | undefined, freezeWidth: boolean | undefined, freezeHeight: boolean | undefined, rotate: number | undefined, controlX: number | undefined, controlY: number | undefined, oldCenterX: number, oldCenterY: number, forceProportional?: boolean) => ResizeInfo;
15
23
  export declare const updateEdgePointByAnchors: (nodeModel: BaseNodeModel, graphModel: GraphModel) => void;
16
24
  export declare const triggerResizeEvent: (preNodeData: ResizeNodeData, curNodeData: ResizeNodeData, deltaX: number, deltaY: number, index: number, nodeModel: BaseNodeModel, graphModel: GraphModel) => void;
17
25
  export type IHandleResizeParams = {
@@ -23,6 +31,7 @@ export type IHandleResizeParams = {
23
31
  nodeModel: BaseNodeModel;
24
32
  graphModel: GraphModel;
25
33
  cancelCallback?: () => void;
34
+ forceProportional?: boolean;
26
35
  };
27
36
  /**
28
37
  * 处理节点的 resize 事件,提出来放到 utils 中,方便在外面(extension)中使用
@@ -34,13 +43,6 @@ export type IHandleResizeParams = {
34
43
  * @param nodeModel
35
44
  * @param graphModel
36
45
  * @param cancelCallback
46
+ * @param forceProportional
37
47
  */
38
- export declare const handleResize: ({ x, y, deltaX, deltaY, index, nodeModel, graphModel, cancelCallback, }: IHandleResizeParams) => void;
39
- export declare function calculateWidthAndHeight(startRotatedTouchControlPoint: SimplePoint, endRotatedTouchControlPoint: SimplePoint, oldCenter: SimplePoint, angle: number, freezeWidth: boolean | undefined, freezeHeight: boolean | undefined, oldWidth: number, oldHeight: number): {
40
- width: number;
41
- height: number;
42
- center: {
43
- x: number;
44
- y: number;
45
- };
46
- };
48
+ export declare const handleResize: ({ x, y, deltaX, deltaY, index, nodeModel, graphModel, cancelCallback, forceProportional, }: IHandleResizeParams) => void;
package/es/util/resize.js CHANGED
@@ -2,6 +2,83 @@ import { ResizeControlIndex } from '../view/Control';
2
2
  import { cloneDeep, find, forEach } from 'lodash-es';
3
3
  import { EventType } from '../constant';
4
4
  import { calculatePointAfterRotateAngle, getNewCenter, radianToAngle, } from '../algorithm/rotate';
5
+ export function calculateWidthAndHeight(startRotatedTouchControlPoint, endRotatedTouchControlPoint, oldCenter, angle, freezeWidth, freezeHeight, oldWidth, oldHeight) {
6
+ if (freezeWidth === void 0) { freezeWidth = false; }
7
+ if (freezeHeight === void 0) { freezeHeight = false; }
8
+ // 假设目前触摸的是右下角的control点
9
+ // 计算出来左上角的control坐标,resize过程左上角的control坐标保持不变
10
+ var freezePoint = {
11
+ x: oldCenter.x - (startRotatedTouchControlPoint.x - oldCenter.x),
12
+ y: oldCenter.y - (startRotatedTouchControlPoint.y - oldCenter.y),
13
+ };
14
+ // 【touchEndPoint】右下角 + freezePoint左上角 计算出新的中心点
15
+ var newCenter = getNewCenter(freezePoint, endRotatedTouchControlPoint);
16
+ // 得到【touchEndPoint】右下角-没有transform的坐标
17
+ var endZeroTouchControlPoint = calculatePointAfterRotateAngle(endRotatedTouchControlPoint, newCenter, -angle);
18
+ // ---------- 使用transform之前的坐标计算出新的width和height ----------
19
+ // 得到左上角---没有transform的坐标
20
+ var zeroFreezePoint = calculatePointAfterRotateAngle(freezePoint, newCenter, -angle);
21
+ if (freezeWidth) {
22
+ // 如果固定width,那么不能单纯使用endZeroTouchControlPoint.x=startZeroTouchControlPoint.x
23
+ // 因为去掉transform的左上角不一定是重合的,我们要保证的是transform后的左上角重合
24
+ var newWidth = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x);
25
+ var widthDx = newWidth - oldWidth;
26
+ // 点击的是左边锚点,是+widthDx/2,点击是右边锚点,是-widthDx/2
27
+ if (newCenter.x > endZeroTouchControlPoint.x) {
28
+ // 当前触摸的是左边锚点
29
+ newCenter.x = newCenter.x + widthDx / 2;
30
+ }
31
+ else {
32
+ // 当前触摸的是右边锚点
33
+ newCenter.x = newCenter.x - widthDx / 2;
34
+ }
35
+ }
36
+ if (freezeHeight) {
37
+ var newHeight = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y);
38
+ var heightDy = newHeight - oldHeight;
39
+ if (newCenter.y > endZeroTouchControlPoint.y) {
40
+ // 当前触摸的是上边锚点
41
+ newCenter.y = newCenter.y + heightDy / 2;
42
+ }
43
+ else {
44
+ newCenter.y = newCenter.y - heightDy / 2;
45
+ }
46
+ }
47
+ if (freezeWidth || freezeHeight) {
48
+ // 如果调整过transform之前的坐标,那么transform后的坐标也会改变,那么算出来的newCenter也得调整
49
+ // 由于无论如何rotate,中心点都是不变的,因此我们可以使用transform之前的坐标算出新的中心点
50
+ var nowFreezePoint = calculatePointAfterRotateAngle(zeroFreezePoint, newCenter, angle);
51
+ // 得到当前新rect的左上角与实际上transform后的左上角的偏移量
52
+ var dx = nowFreezePoint.x - freezePoint.x;
53
+ var dy = nowFreezePoint.y - freezePoint.y;
54
+ // 修正不使用transform的坐标: 左上角、右下角、center
55
+ newCenter.x = newCenter.x - dx;
56
+ newCenter.y = newCenter.y - dy;
57
+ zeroFreezePoint = calculatePointAfterRotateAngle(freezePoint, newCenter, -angle);
58
+ endZeroTouchControlPoint = {
59
+ x: newCenter.x - (zeroFreezePoint.x - newCenter.x),
60
+ y: newCenter.y - (zeroFreezePoint.y - newCenter.y),
61
+ };
62
+ }
63
+ // transform之前的坐标的左上角+右下角计算出宽度和高度
64
+ var width = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x);
65
+ var height = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y);
66
+ // ---------- 使用transform之前的坐标计算出新的width和height ----------
67
+ if (freezeWidth) {
68
+ // 理论计算出来的width应该等于oldWidth
69
+ // 但是有误差,比如oldWidth = 100; newWidth=100.000000000001
70
+ // 会在handleResize()限制放大缩小的最大最小范围中被阻止滑动
71
+ width = oldWidth;
72
+ }
73
+ if (freezeHeight) {
74
+ height = oldHeight;
75
+ }
76
+ return {
77
+ width: width,
78
+ height: height,
79
+ center: newCenter,
80
+ };
81
+ }
5
82
  function recalcRotatedResizeInfo(pct, resizeInfo, rotate, controlX, controlY, oldCenterX, oldCenterY, freezeWidth, freezeHeight) {
6
83
  if (freezeWidth === void 0) { freezeWidth = false; }
7
84
  if (freezeHeight === void 0) { freezeHeight = false; }
@@ -39,11 +116,12 @@ function recalcRotatedResizeInfo(pct, resizeInfo, rotate, controlX, controlY, ol
39
116
  * @param freezeWidth
40
117
  * @param freezeHeight
41
118
  */
42
- export var recalcResizeInfo = function (index, resizeInfo, pct, freezeWidth, freezeHeight, rotate, controlX, controlY, oldCenterX, oldCenterY) {
119
+ export var recalcResizeInfo = function (index, resizeInfo, pct, freezeWidth, freezeHeight, rotate, controlX, controlY, oldCenterX, oldCenterY, forceProportional) {
43
120
  if (pct === void 0) { pct = 1; }
44
121
  if (freezeWidth === void 0) { freezeWidth = false; }
45
122
  if (freezeHeight === void 0) { freezeHeight = false; }
46
123
  if (rotate === void 0) { rotate = 0; }
124
+ if (forceProportional === void 0) { forceProportional = false; }
47
125
  var nextResizeInfo = cloneDeep(resizeInfo);
48
126
  var deltaX = nextResizeInfo.deltaX, deltaY = nextResizeInfo.deltaY;
49
127
  var width = nextResizeInfo.width, height = nextResizeInfo.height, PCTResizeInfo = nextResizeInfo.PCTResizeInfo;
@@ -109,7 +187,84 @@ export var recalcResizeInfo = function (index, resizeInfo, pct, freezeWidth, fre
109
187
  // 角度rotate不为0得到的resizeInfo.deltaX仅仅代表中心点的变化,而不是宽度的变化
110
188
  return recalcRotatedResizeInfo(pct, nextResizeInfo, rotate, controlX, controlY, oldCenterX, oldCenterY, freezeWidth, freezeHeight);
111
189
  }
112
- // 如果限制了宽/高不变,对应的 width/height 保持一致
190
+ //Shift键等比缩放逻辑
191
+ if (forceProportional) {
192
+ // 计算当前的宽高比
193
+ var aspectRatio = width / height;
194
+ // 根据拖拽方向确定主要的缩放参考
195
+ var primaryDelta = 0;
196
+ var newWidth = width;
197
+ var newHeight = height;
198
+ switch (index) {
199
+ case ResizeControlIndex.LEFT_TOP:
200
+ // 取绝对值较大的delta作为主要缩放参考
201
+ primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? -deltaX : -deltaY;
202
+ if (aspectRatio >= 1) {
203
+ // 宽度大于等于高度,以宽度为基准
204
+ newWidth = width + primaryDelta;
205
+ newHeight = newWidth / aspectRatio;
206
+ }
207
+ else {
208
+ // 高度大于宽度,以高度为基准
209
+ newHeight = height + primaryDelta;
210
+ newWidth = newHeight * aspectRatio;
211
+ }
212
+ nextResizeInfo.width = newWidth;
213
+ nextResizeInfo.height = newHeight;
214
+ nextResizeInfo.deltaX = width - newWidth;
215
+ nextResizeInfo.deltaY = height - newHeight;
216
+ break;
217
+ case ResizeControlIndex.RIGHT_TOP:
218
+ primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : -deltaY;
219
+ if (aspectRatio >= 1) {
220
+ newWidth = width + primaryDelta;
221
+ newHeight = newWidth / aspectRatio;
222
+ }
223
+ else {
224
+ newHeight = height - primaryDelta;
225
+ newWidth = newHeight * aspectRatio;
226
+ }
227
+ nextResizeInfo.width = newWidth;
228
+ nextResizeInfo.height = newHeight;
229
+ nextResizeInfo.deltaX = newWidth - width;
230
+ nextResizeInfo.deltaY = height - newHeight;
231
+ break;
232
+ case ResizeControlIndex.RIGHT_BOTTOM:
233
+ primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY;
234
+ if (aspectRatio >= 1) {
235
+ newWidth = width + primaryDelta;
236
+ newHeight = newWidth / aspectRatio;
237
+ }
238
+ else {
239
+ newHeight = height + primaryDelta;
240
+ newWidth = newHeight * aspectRatio;
241
+ }
242
+ nextResizeInfo.width = newWidth;
243
+ nextResizeInfo.height = newHeight;
244
+ nextResizeInfo.deltaX = newWidth - width;
245
+ nextResizeInfo.deltaY = newHeight - height;
246
+ break;
247
+ case ResizeControlIndex.LEFT_BOTTOM:
248
+ primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? -deltaX : deltaY;
249
+ if (aspectRatio >= 1) {
250
+ newWidth = width - primaryDelta;
251
+ newHeight = newWidth / aspectRatio;
252
+ }
253
+ else {
254
+ newHeight = height + primaryDelta;
255
+ newWidth = newHeight * aspectRatio;
256
+ }
257
+ nextResizeInfo.width = newWidth;
258
+ nextResizeInfo.height = newHeight;
259
+ nextResizeInfo.deltaX = width - newWidth;
260
+ nextResizeInfo.deltaY = newHeight - height;
261
+ break;
262
+ default:
263
+ break;
264
+ }
265
+ return nextResizeInfo;
266
+ }
267
+ // 原有的非等比缩放逻辑保持不变
113
268
  switch (index) {
114
269
  case ResizeControlIndex.LEFT_TOP:
115
270
  nextResizeInfo.width = freezeWidth ? width : width - deltaX * pct;
@@ -189,9 +344,10 @@ export var triggerResizeEvent = function (preNodeData, curNodeData, deltaX, delt
189
344
  * @param nodeModel
190
345
  * @param graphModel
191
346
  * @param cancelCallback
347
+ * @param forceProportional
192
348
  */
193
349
  export var handleResize = function (_a) {
194
- var x = _a.x, y = _a.y, deltaX = _a.deltaX, deltaY = _a.deltaY, index = _a.index, nodeModel = _a.nodeModel, graphModel = _a.graphModel, cancelCallback = _a.cancelCallback;
350
+ var x = _a.x, y = _a.y, deltaX = _a.deltaX, deltaY = _a.deltaY, index = _a.index, nodeModel = _a.nodeModel, graphModel = _a.graphModel, cancelCallback = _a.cancelCallback, _b = _a.forceProportional, forceProportional = _b === void 0 ? false : _b;
195
351
  var r = nodeModel.r, // circle
196
352
  rx = nodeModel.rx, // ellipse/diamond
197
353
  ry = nodeModel.ry, width = nodeModel.width, // rect/html
@@ -208,7 +364,7 @@ export var handleResize = function (_a) {
208
364
  var pct = r || (rx && ry) ? 1 / 2 : 1;
209
365
  var controlX = x;
210
366
  var controlY = y;
211
- var nextSize = recalcResizeInfo(index, resizeInfo, pct, isFreezeWidth, isFreezeHeight, rotate, controlX, controlY, oldCenterX, oldCenterY);
367
+ var nextSize = recalcResizeInfo(index, resizeInfo, pct, isFreezeWidth, isFreezeHeight, rotate, controlX, controlY, oldCenterX, oldCenterY, forceProportional);
212
368
  // 限制放大缩小的最大最小范围
213
369
  if (nextSize.width < minWidth ||
214
370
  nextSize.width > maxWidth ||
@@ -240,80 +396,3 @@ export var handleResize = function (_a) {
240
396
  // 触发 resize 事件
241
397
  triggerResizeEvent(preNodeData, curNodeData, deltaX, deltaY, index, nodeModel, graphModel);
242
398
  };
243
- export function calculateWidthAndHeight(startRotatedTouchControlPoint, endRotatedTouchControlPoint, oldCenter, angle, freezeWidth, freezeHeight, oldWidth, oldHeight) {
244
- if (freezeWidth === void 0) { freezeWidth = false; }
245
- if (freezeHeight === void 0) { freezeHeight = false; }
246
- // 假设目前触摸的是右下角的control点
247
- // 计算出来左上角的control坐标,resize过程左上角的control坐标保持不变
248
- var freezePoint = {
249
- x: oldCenter.x - (startRotatedTouchControlPoint.x - oldCenter.x),
250
- y: oldCenter.y - (startRotatedTouchControlPoint.y - oldCenter.y),
251
- };
252
- // 【touchEndPoint】右下角 + freezePoint左上角 计算出新的中心点
253
- var newCenter = getNewCenter(freezePoint, endRotatedTouchControlPoint);
254
- // 得到【touchEndPoint】右下角-没有transform的坐标
255
- var endZeroTouchControlPoint = calculatePointAfterRotateAngle(endRotatedTouchControlPoint, newCenter, -angle);
256
- // ---------- 使用transform之前的坐标计算出新的width和height ----------
257
- // 得到左上角---没有transform的坐标
258
- var zeroFreezePoint = calculatePointAfterRotateAngle(freezePoint, newCenter, -angle);
259
- if (freezeWidth) {
260
- // 如果固定width,那么不能单纯使用endZeroTouchControlPoint.x=startZeroTouchControlPoint.x
261
- // 因为去掉transform的左上角不一定是重合的,我们要保证的是transform后的左上角重合
262
- var newWidth = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x);
263
- var widthDx = newWidth - oldWidth;
264
- // 点击的是左边锚点,是+widthDx/2,点击是右边锚点,是-widthDx/2
265
- if (newCenter.x > endZeroTouchControlPoint.x) {
266
- // 当前触摸的是左边锚点
267
- newCenter.x = newCenter.x + widthDx / 2;
268
- }
269
- else {
270
- // 当前触摸的是右边锚点
271
- newCenter.x = newCenter.x - widthDx / 2;
272
- }
273
- }
274
- if (freezeHeight) {
275
- var newHeight = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y);
276
- var heightDy = newHeight - oldHeight;
277
- if (newCenter.y > endZeroTouchControlPoint.y) {
278
- // 当前触摸的是上边锚点
279
- newCenter.y = newCenter.y + heightDy / 2;
280
- }
281
- else {
282
- newCenter.y = newCenter.y - heightDy / 2;
283
- }
284
- }
285
- if (freezeWidth || freezeHeight) {
286
- // 如果调整过transform之前的坐标,那么transform后的坐标也会改变,那么算出来的newCenter也得调整
287
- // 由于无论如何rotate,中心点都是不变的,因此我们可以使用transform之前的坐标算出新的中心点
288
- var nowFreezePoint = calculatePointAfterRotateAngle(zeroFreezePoint, newCenter, angle);
289
- // 得到当前新rect的左上角与实际上transform后的左上角的偏移量
290
- var dx = nowFreezePoint.x - freezePoint.x;
291
- var dy = nowFreezePoint.y - freezePoint.y;
292
- // 修正不使用transform的坐标: 左上角、右下角、center
293
- newCenter.x = newCenter.x - dx;
294
- newCenter.y = newCenter.y - dy;
295
- zeroFreezePoint = calculatePointAfterRotateAngle(freezePoint, newCenter, -angle);
296
- endZeroTouchControlPoint = {
297
- x: newCenter.x - (zeroFreezePoint.x - newCenter.x),
298
- y: newCenter.y - (zeroFreezePoint.y - newCenter.y),
299
- };
300
- }
301
- // transform之前的坐标的左上角+右下角计算出宽度和高度
302
- var width = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x);
303
- var height = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y);
304
- // ---------- 使用transform之前的坐标计算出新的width和height ----------
305
- if (freezeWidth) {
306
- // 理论计算出来的width应该等于oldWidth
307
- // 但是有误差,比如oldWidth = 100; newWidth=100.000000000001
308
- // 会在handleResize()限制放大缩小的最大最小范围中被阻止滑动
309
- width = oldWidth;
310
- }
311
- if (freezeHeight) {
312
- height = oldHeight;
313
- }
314
- return {
315
- width: width,
316
- height: height,
317
- center: newCenter,
318
- };
319
- }
@@ -4,8 +4,8 @@ import { IDragParams, StepDrag } from '../util';
4
4
  import { BaseNodeModel, GraphModel } from '../model';
5
5
  import NodeData = LogicFlow.NodeData;
6
6
  import VectorData = LogicFlow.VectorData;
7
- import ResizeInfo = ResizeControl.ResizeInfo;
8
7
  import ResizeNodeData = ResizeControl.ResizeNodeData;
8
+ import ResizeInfo = ResizeControl.ResizeInfo;
9
9
  import ControlItemProps = ResizeControl.ControlItemProps;
10
10
  export declare enum ResizeControlIndex {
11
11
  LEFT_TOP = 0,
@@ -29,7 +29,11 @@ export declare class ResizeControl extends Component<IResizeControlProps, IResiz
29
29
  readonly nodeModel: BaseNodeModel;
30
30
  readonly graphModel: GraphModel;
31
31
  readonly dragHandler: StepDrag;
32
+ private isShiftPressed;
32
33
  constructor(props: IResizeControlProps);
34
+ bindKeyboardEvents: () => void;
35
+ handleKeyDown: (event: KeyboardEvent) => void;
36
+ handleKeyUp: (event: KeyboardEvent) => void;
33
37
  componentWillUnmount(): void;
34
38
  updateEdgePointByAnchors: () => void;
35
39
  triggerResizeEvent: (preNodeData: ResizeNodeData, curNodeData: ResizeNodeData, deltaX: any, deltaY: any, index: any, nodeModel: BaseNodeModel) => void;
@@ -53,7 +53,7 @@ var __read = (this && this.__read) || function (o, n) {
53
53
  };
54
54
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
55
55
  import { Component } from 'preact/compat';
56
- import { cloneDeep, find, forEach, map } from 'lodash-es';
56
+ import { find, forEach, map, cloneDeep } from 'lodash-es';
57
57
  import { Rect } from './shape';
58
58
  import { getNodeBBox, StepDrag, handleResize } from '../util';
59
59
  import { EventType } from '../constant';
@@ -68,6 +68,24 @@ var ResizeControl = /** @class */ (function (_super) {
68
68
  __extends(ResizeControl, _super);
69
69
  function ResizeControl(props) {
70
70
  var _this = _super.call(this) || this;
71
+ //判断Shift键状态
72
+ _this.isShiftPressed = false;
73
+ //绑定键盘事件监听
74
+ _this.bindKeyboardEvents = function () {
75
+ document.addEventListener('keydown', _this.handleKeyDown);
76
+ document.addEventListener('keyup', _this.handleKeyUp);
77
+ };
78
+ //处理键盘按下事件
79
+ _this.handleKeyDown = function (event) {
80
+ if (event.key === 'Shift') {
81
+ _this.isShiftPressed = true;
82
+ }
83
+ };
84
+ _this.handleKeyUp = function (event) {
85
+ if (event.key === 'Shift') {
86
+ _this.isShiftPressed = false;
87
+ }
88
+ };
71
89
  _this.updateEdgePointByAnchors = function () {
72
90
  // https://github.com/didi/LogicFlow/issues/807
73
91
  // https://github.com/didi/LogicFlow/issues/875
@@ -220,6 +238,7 @@ var ResizeControl = /** @class */ (function (_super) {
220
238
  index: index,
221
239
  nodeModel: model,
222
240
  graphModel: graphModel,
241
+ forceProportional: _this.isShiftPressed,
223
242
  cancelCallback: function () {
224
243
  _this.dragHandler.cancelDrag();
225
244
  },
@@ -310,17 +329,19 @@ var ResizeControl = /** @class */ (function (_super) {
310
329
  _this.index = index;
311
330
  _this.nodeModel = model;
312
331
  _this.graphModel = graphModel;
313
- // 初始化拖拽工具
314
332
  _this.dragHandler = new StepDrag({
315
333
  onDragStart: _this.onDragStart,
316
334
  onDragging: _this.onDragging,
317
335
  onDragEnd: _this.onDragEnd,
318
336
  step: graphModel.gridSize,
319
337
  });
338
+ _this.bindKeyboardEvents();
320
339
  return _this;
321
340
  }
322
341
  ResizeControl.prototype.componentWillUnmount = function () {
323
342
  this.dragHandler.destroy();
343
+ document.removeEventListener('keydown', this.handleKeyDown);
344
+ document.removeEventListener('keyup', this.handleKeyUp);
324
345
  };
325
346
  ResizeControl.prototype.render = function () {
326
347
  var _a = this.props, x = _a.x, y = _a.y, direction = _a.direction, model = _a.model;
@@ -30,6 +30,9 @@ var Dnd = /** @class */ (function () {
30
30
  })));
31
31
  };
32
32
  this.onDragOver = function (e) {
33
+ _this.lf.graphModel.eventCenter.emit(EventType.BLANK_CANVAS_MOUSEMOVE, {
34
+ e: e,
35
+ });
33
36
  e.preventDefault();
34
37
  if (_this.fakeNode) {
35
38
  var _a = _this.clientToLocalPoint({
package/lib/LogicFlow.js CHANGED
@@ -112,7 +112,7 @@ var LogicFlow = /** @class */ (function () {
112
112
  keyboard: initOptions.keyboard,
113
113
  });
114
114
  if (initOptions.snapline !== false) {
115
- this.snaplineModel = new model_1.SnaplineModel(this.graphModel);
115
+ this.snaplineModel = new model_1.SnaplineModel(this.graphModel, initOptions.snaplineEpsilon);
116
116
  (0, behavior_1.snapline)(eventCenter, this.snaplineModel);
117
117
  }
118
118
  if (!initOptions.isSilentMode) {
@@ -825,6 +825,9 @@ var LogicFlow = /** @class */ (function () {
825
825
  var _b = this.graphModel.grid.size, size = _b === void 0 ? 1 : _b;
826
826
  this.graphModel.updateGridSize(config.snapGrid ? size : 1);
827
827
  }
828
+ this.emit(constant_1.EventType.EDIT_CONFIG_CHANGED, {
829
+ data: editConfigModel.getConfig(),
830
+ });
828
831
  };
829
832
  /**
830
833
  * 获取流程图当前编辑相关设置
@@ -82,6 +82,7 @@ export declare enum EventType {
82
82
  BLANK_DRAG = "blank:drag",
83
83
  BLANK_DROP = "blank:drop",
84
84
  BLANK_MOUSEMOVE = "blank:mousemove",
85
+ BLANK_CANVAS_MOUSEMOVE = "blank:canvas-mousemove",
85
86
  BLANK_MOUSEUP = "blank:mouseup",
86
87
  BLANK_CLICK = "blank:click",
87
88
  BLANK_CONTEXTMENU = "blank:contextmenu",
@@ -129,7 +130,8 @@ export declare enum EventType {
129
130
  HISTORY_CHANGE = "history:change",
130
131
  GRAPH_TRANSFORM = "graph:transform",
131
132
  GRAPH_RENDERED = "graph:rendered",
132
- GRAPH_UPDATED = "graph:updated"
133
+ GRAPH_UPDATED = "graph:updated",
134
+ EDIT_CONFIG_CHANGED = "editConfig:changed"
133
135
  }
134
136
  export declare enum OverlapMode {
135
137
  DEFAULT = 0,// 默认