@logicflow/core 2.0.16 → 2.1.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 +7 -7
- package/CHANGELOG.md +16 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/es/LogicFlow.js +1 -1
- package/es/keyboard/shortcut.js +7 -0
- package/es/model/GraphModel.js +2 -0
- package/es/model/SnaplineModel.d.ts +2 -1
- package/es/model/SnaplineModel.js +26 -11
- package/es/options.d.ts +1 -0
- package/es/util/resize.d.ts +12 -10
- package/es/util/resize.js +160 -81
- package/es/view/Control.d.ts +5 -1
- package/es/view/Control.js +23 -2
- package/es/view/node/BaseNode.js +1 -0
- package/lib/LogicFlow.js +1 -1
- package/lib/keyboard/shortcut.js +7 -0
- package/lib/model/GraphModel.js +2 -0
- package/lib/model/SnaplineModel.d.ts +2 -1
- package/lib/model/SnaplineModel.js +26 -11
- package/lib/options.d.ts +1 -0
- package/lib/util/resize.d.ts +12 -10
- package/lib/util/resize.js +162 -83
- package/lib/view/Control.d.ts +5 -1
- package/lib/view/Control.js +22 -1
- package/lib/view/node/BaseNode.js +1 -0
- package/package.json +1 -1
- package/src/LogicFlow.tsx +7 -2
- package/src/constant/index.ts +2 -0
- package/src/keyboard/shortcut.ts +6 -0
- package/src/model/GraphModel.ts +2 -0
- package/src/model/SnaplineModel.ts +29 -11
- package/src/options.ts +1 -0
- package/src/util/resize.ts +200 -112
- package/src/view/Control.tsx +29 -5
- package/src/view/behavior/dnd.ts +3 -0
- package/src/view/node/BaseNode.tsx +1 -0
- package/stats.html +1 -1
|
@@ -19,8 +19,10 @@ export class SnaplineModel {
|
|
|
19
19
|
@observable isShowVertical: boolean
|
|
20
20
|
// 对齐线的中心位置,目前仅展示中心对齐的情况,后面可以考虑多种对齐策略
|
|
21
21
|
@observable position: Position
|
|
22
|
+
// 对齐线显示的阈值距离
|
|
23
|
+
epsilon: number
|
|
22
24
|
|
|
23
|
-
constructor(graphModel: GraphModel) {
|
|
25
|
+
constructor(graphModel: GraphModel, epsilon: number = 1) {
|
|
24
26
|
this.isShowHorizontal = false
|
|
25
27
|
this.isShowVertical = false
|
|
26
28
|
this.position = {
|
|
@@ -28,6 +30,7 @@ export class SnaplineModel {
|
|
|
28
30
|
y: 0,
|
|
29
31
|
}
|
|
30
32
|
this.graphModel = graphModel
|
|
33
|
+
this.epsilon = epsilon
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
getStyle() {
|
|
@@ -48,10 +51,10 @@ export class SnaplineModel {
|
|
|
48
51
|
const item = nodes[i]
|
|
49
52
|
// 排除当前节点
|
|
50
53
|
if (item.id !== draggingNode.id) {
|
|
51
|
-
if (x
|
|
54
|
+
if (equal(x, item.x, this.epsilon)) {
|
|
52
55
|
isShowVertical = true
|
|
53
56
|
}
|
|
54
|
-
if (y
|
|
57
|
+
if (equal(y, item.y, this.epsilon)) {
|
|
55
58
|
isShowHorizontal = true
|
|
56
59
|
}
|
|
57
60
|
// 如果水平垂直都显示,则停止循环。减少不必要的遍历
|
|
@@ -95,10 +98,11 @@ export class SnaplineModel {
|
|
|
95
98
|
// 排除当前节点
|
|
96
99
|
if (item.id !== draggingNode.id) {
|
|
97
100
|
const itemData = getNodeBBox(item)
|
|
101
|
+
|
|
98
102
|
// 如果节点的最大最小Y轴坐标与节点的最大最小Y轴坐标相等,展示水平线
|
|
99
103
|
if (
|
|
100
|
-
itemData.minY
|
|
101
|
-
itemData.maxY
|
|
104
|
+
equal(itemData.minY, draggingData?.minY, this.epsilon) ||
|
|
105
|
+
equal(itemData.maxY, draggingData?.minY, this.epsilon)
|
|
102
106
|
) {
|
|
103
107
|
// 找到则停止循环。减少不必要的遍历
|
|
104
108
|
isShowHorizontal = true
|
|
@@ -106,8 +110,8 @@ export class SnaplineModel {
|
|
|
106
110
|
break
|
|
107
111
|
}
|
|
108
112
|
if (
|
|
109
|
-
itemData.minY
|
|
110
|
-
itemData.maxY
|
|
113
|
+
equal(itemData.minY, draggingData?.maxY, this.epsilon) ||
|
|
114
|
+
equal(itemData.maxY, draggingData?.maxY, this.epsilon)
|
|
111
115
|
) {
|
|
112
116
|
isShowHorizontal = true
|
|
113
117
|
horizontalY = draggingData.maxY
|
|
@@ -145,15 +149,21 @@ export class SnaplineModel {
|
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
151
|
}
|
|
152
|
+
|
|
148
153
|
for (let i = 0; i < nodes.length; i++) {
|
|
149
154
|
const item = nodes[i]
|
|
150
155
|
// 排除当前节点
|
|
151
156
|
if (item.id !== draggingNode.id) {
|
|
152
157
|
const itemData = getNodeBBox(item)
|
|
153
158
|
// 如果节点的最大最小X轴坐标与节点的最大最小X轴坐标相等,展示垂直线
|
|
159
|
+
if (equal(itemData.minX, draggingData?.minX, this.epsilon)) {
|
|
160
|
+
isShowVertical = true
|
|
161
|
+
verticalX = draggingData.minX
|
|
162
|
+
break
|
|
163
|
+
}
|
|
154
164
|
if (
|
|
155
|
-
itemData.minX
|
|
156
|
-
itemData.maxX
|
|
165
|
+
equal(itemData.minX, draggingData?.minX, this.epsilon) ||
|
|
166
|
+
equal(itemData.maxX, draggingData?.minX, this.epsilon)
|
|
157
167
|
) {
|
|
158
168
|
// 找到则停止循环。减少不必要的遍历
|
|
159
169
|
isShowVertical = true
|
|
@@ -161,8 +171,8 @@ export class SnaplineModel {
|
|
|
161
171
|
break
|
|
162
172
|
}
|
|
163
173
|
if (
|
|
164
|
-
itemData.minX
|
|
165
|
-
itemData.maxX
|
|
174
|
+
equal(itemData.minX, draggingData?.maxX, this.epsilon) ||
|
|
175
|
+
equal(itemData.maxX, draggingData?.maxX, this.epsilon)
|
|
166
176
|
) {
|
|
167
177
|
isShowVertical = true
|
|
168
178
|
verticalX = draggingData.maxX
|
|
@@ -235,4 +245,12 @@ export class SnaplineModel {
|
|
|
235
245
|
}
|
|
236
246
|
}
|
|
237
247
|
|
|
248
|
+
function equal(num1: number, num2: number, epsilon: number) {
|
|
249
|
+
if (Math.abs(num1 - num2) <= epsilon) {
|
|
250
|
+
return true
|
|
251
|
+
} else {
|
|
252
|
+
return false
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
238
256
|
export default SnaplineModel
|
package/src/options.ts
CHANGED
package/src/util/resize.ts
CHANGED
|
@@ -12,6 +12,117 @@ import {
|
|
|
12
12
|
} from '../algorithm/rotate'
|
|
13
13
|
import type { SimplePoint } from '../algorithm/rotate'
|
|
14
14
|
|
|
15
|
+
export function calculateWidthAndHeight(
|
|
16
|
+
startRotatedTouchControlPoint: SimplePoint,
|
|
17
|
+
endRotatedTouchControlPoint: SimplePoint,
|
|
18
|
+
oldCenter: SimplePoint,
|
|
19
|
+
angle: number,
|
|
20
|
+
freezeWidth = false,
|
|
21
|
+
freezeHeight = false,
|
|
22
|
+
oldWidth: number,
|
|
23
|
+
oldHeight: number,
|
|
24
|
+
) {
|
|
25
|
+
// 假设目前触摸的是右下角的control点
|
|
26
|
+
// 计算出来左上角的control坐标,resize过程左上角的control坐标保持不变
|
|
27
|
+
const freezePoint: SimplePoint = {
|
|
28
|
+
x: oldCenter.x - (startRotatedTouchControlPoint.x - oldCenter.x),
|
|
29
|
+
y: oldCenter.y - (startRotatedTouchControlPoint.y - oldCenter.y),
|
|
30
|
+
}
|
|
31
|
+
// 【touchEndPoint】右下角 + freezePoint左上角 计算出新的中心点
|
|
32
|
+
const newCenter = getNewCenter(freezePoint, endRotatedTouchControlPoint)
|
|
33
|
+
|
|
34
|
+
// 得到【touchEndPoint】右下角-没有transform的坐标
|
|
35
|
+
let endZeroTouchControlPoint: SimplePoint = calculatePointAfterRotateAngle(
|
|
36
|
+
endRotatedTouchControlPoint,
|
|
37
|
+
newCenter,
|
|
38
|
+
-angle,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
// ---------- 使用transform之前的坐标计算出新的width和height ----------
|
|
42
|
+
|
|
43
|
+
// 得到左上角---没有transform的坐标
|
|
44
|
+
let zeroFreezePoint: SimplePoint = calculatePointAfterRotateAngle(
|
|
45
|
+
freezePoint,
|
|
46
|
+
newCenter,
|
|
47
|
+
-angle,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if (freezeWidth) {
|
|
51
|
+
// 如果固定width,那么不能单纯使用endZeroTouchControlPoint.x=startZeroTouchControlPoint.x
|
|
52
|
+
// 因为去掉transform的左上角不一定是重合的,我们要保证的是transform后的左上角重合
|
|
53
|
+
const newWidth = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x)
|
|
54
|
+
const widthDx = newWidth - oldWidth
|
|
55
|
+
|
|
56
|
+
// 点击的是左边锚点,是+widthDx/2,点击是右边锚点,是-widthDx/2
|
|
57
|
+
if (newCenter.x > endZeroTouchControlPoint.x) {
|
|
58
|
+
// 当前触摸的是左边锚点
|
|
59
|
+
newCenter.x = newCenter.x + widthDx / 2
|
|
60
|
+
} else {
|
|
61
|
+
// 当前触摸的是右边锚点
|
|
62
|
+
newCenter.x = newCenter.x - widthDx / 2
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (freezeHeight) {
|
|
66
|
+
const newHeight = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y)
|
|
67
|
+
const heightDy = newHeight - oldHeight
|
|
68
|
+
if (newCenter.y > endZeroTouchControlPoint.y) {
|
|
69
|
+
// 当前触摸的是上边锚点
|
|
70
|
+
newCenter.y = newCenter.y + heightDy / 2
|
|
71
|
+
} else {
|
|
72
|
+
newCenter.y = newCenter.y - heightDy / 2
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (freezeWidth || freezeHeight) {
|
|
77
|
+
// 如果调整过transform之前的坐标,那么transform后的坐标也会改变,那么算出来的newCenter也得调整
|
|
78
|
+
// 由于无论如何rotate,中心点都是不变的,因此我们可以使用transform之前的坐标算出新的中心点
|
|
79
|
+
const nowFreezePoint = calculatePointAfterRotateAngle(
|
|
80
|
+
zeroFreezePoint,
|
|
81
|
+
newCenter,
|
|
82
|
+
angle,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
// 得到当前新rect的左上角与实际上transform后的左上角的偏移量
|
|
86
|
+
const dx = nowFreezePoint.x - freezePoint.x
|
|
87
|
+
const dy = nowFreezePoint.y - freezePoint.y
|
|
88
|
+
|
|
89
|
+
// 修正不使用transform的坐标: 左上角、右下角、center
|
|
90
|
+
newCenter.x = newCenter.x - dx
|
|
91
|
+
newCenter.y = newCenter.y - dy
|
|
92
|
+
zeroFreezePoint = calculatePointAfterRotateAngle(
|
|
93
|
+
freezePoint,
|
|
94
|
+
newCenter,
|
|
95
|
+
-angle,
|
|
96
|
+
)
|
|
97
|
+
endZeroTouchControlPoint = {
|
|
98
|
+
x: newCenter.x - (zeroFreezePoint.x - newCenter.x),
|
|
99
|
+
y: newCenter.y - (zeroFreezePoint.y - newCenter.y),
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// transform之前的坐标的左上角+右下角计算出宽度和高度
|
|
104
|
+
let width = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x)
|
|
105
|
+
let height = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y)
|
|
106
|
+
|
|
107
|
+
// ---------- 使用transform之前的坐标计算出新的width和height ----------
|
|
108
|
+
|
|
109
|
+
if (freezeWidth) {
|
|
110
|
+
// 理论计算出来的width应该等于oldWidth
|
|
111
|
+
// 但是有误差,比如oldWidth = 100; newWidth=100.000000000001
|
|
112
|
+
// 会在handleResize()限制放大缩小的最大最小范围中被阻止滑动
|
|
113
|
+
width = oldWidth
|
|
114
|
+
}
|
|
115
|
+
if (freezeHeight) {
|
|
116
|
+
height = oldHeight
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
width,
|
|
121
|
+
height,
|
|
122
|
+
center: newCenter,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
15
126
|
function recalcRotatedResizeInfo(
|
|
16
127
|
pct: number,
|
|
17
128
|
resizeInfo: ResizeInfo,
|
|
@@ -89,10 +200,12 @@ export const recalcResizeInfo = (
|
|
|
89
200
|
controlY: number | undefined,
|
|
90
201
|
oldCenterX: number,
|
|
91
202
|
oldCenterY: number,
|
|
203
|
+
forceProportional = false,
|
|
92
204
|
): ResizeInfo => {
|
|
93
205
|
const nextResizeInfo = cloneDeep(resizeInfo)
|
|
94
206
|
let { deltaX, deltaY } = nextResizeInfo
|
|
95
207
|
const { width, height, PCTResizeInfo } = nextResizeInfo
|
|
208
|
+
|
|
96
209
|
if (PCTResizeInfo) {
|
|
97
210
|
const sensitivity = 4 // 越低越灵敏
|
|
98
211
|
let deltaScale = 0
|
|
@@ -190,7 +303,88 @@ export const recalcResizeInfo = (
|
|
|
190
303
|
)
|
|
191
304
|
}
|
|
192
305
|
|
|
193
|
-
//
|
|
306
|
+
//Shift键等比缩放逻辑
|
|
307
|
+
if (forceProportional) {
|
|
308
|
+
// 计算当前的宽高比
|
|
309
|
+
const aspectRatio = width / height
|
|
310
|
+
|
|
311
|
+
// 根据拖拽方向确定主要的缩放参考
|
|
312
|
+
let primaryDelta = 0
|
|
313
|
+
let newWidth = width
|
|
314
|
+
let newHeight = height
|
|
315
|
+
|
|
316
|
+
switch (index) {
|
|
317
|
+
case ResizeControlIndex.LEFT_TOP:
|
|
318
|
+
// 取绝对值较大的delta作为主要缩放参考
|
|
319
|
+
primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? -deltaX : -deltaY
|
|
320
|
+
if (aspectRatio >= 1) {
|
|
321
|
+
// 宽度大于等于高度,以宽度为基准
|
|
322
|
+
newWidth = width + primaryDelta
|
|
323
|
+
newHeight = newWidth / aspectRatio
|
|
324
|
+
} else {
|
|
325
|
+
// 高度大于宽度,以高度为基准
|
|
326
|
+
newHeight = height + primaryDelta
|
|
327
|
+
newWidth = newHeight * aspectRatio
|
|
328
|
+
}
|
|
329
|
+
nextResizeInfo.width = newWidth
|
|
330
|
+
nextResizeInfo.height = newHeight
|
|
331
|
+
nextResizeInfo.deltaX = width - newWidth
|
|
332
|
+
nextResizeInfo.deltaY = height - newHeight
|
|
333
|
+
break
|
|
334
|
+
|
|
335
|
+
case ResizeControlIndex.RIGHT_TOP:
|
|
336
|
+
primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : -deltaY
|
|
337
|
+
if (aspectRatio >= 1) {
|
|
338
|
+
newWidth = width + primaryDelta
|
|
339
|
+
newHeight = newWidth / aspectRatio
|
|
340
|
+
} else {
|
|
341
|
+
newHeight = height - primaryDelta
|
|
342
|
+
newWidth = newHeight * aspectRatio
|
|
343
|
+
}
|
|
344
|
+
nextResizeInfo.width = newWidth
|
|
345
|
+
nextResizeInfo.height = newHeight
|
|
346
|
+
nextResizeInfo.deltaX = newWidth - width
|
|
347
|
+
nextResizeInfo.deltaY = height - newHeight
|
|
348
|
+
break
|
|
349
|
+
|
|
350
|
+
case ResizeControlIndex.RIGHT_BOTTOM:
|
|
351
|
+
primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY
|
|
352
|
+
if (aspectRatio >= 1) {
|
|
353
|
+
newWidth = width + primaryDelta
|
|
354
|
+
newHeight = newWidth / aspectRatio
|
|
355
|
+
} else {
|
|
356
|
+
newHeight = height + primaryDelta
|
|
357
|
+
newWidth = newHeight * aspectRatio
|
|
358
|
+
}
|
|
359
|
+
nextResizeInfo.width = newWidth
|
|
360
|
+
nextResizeInfo.height = newHeight
|
|
361
|
+
nextResizeInfo.deltaX = newWidth - width
|
|
362
|
+
nextResizeInfo.deltaY = newHeight - height
|
|
363
|
+
break
|
|
364
|
+
|
|
365
|
+
case ResizeControlIndex.LEFT_BOTTOM:
|
|
366
|
+
primaryDelta = Math.abs(deltaX) > Math.abs(deltaY) ? -deltaX : deltaY
|
|
367
|
+
if (aspectRatio >= 1) {
|
|
368
|
+
newWidth = width - primaryDelta
|
|
369
|
+
newHeight = newWidth / aspectRatio
|
|
370
|
+
} else {
|
|
371
|
+
newHeight = height + primaryDelta
|
|
372
|
+
newWidth = newHeight * aspectRatio
|
|
373
|
+
}
|
|
374
|
+
nextResizeInfo.width = newWidth
|
|
375
|
+
nextResizeInfo.height = newHeight
|
|
376
|
+
nextResizeInfo.deltaX = width - newWidth
|
|
377
|
+
nextResizeInfo.deltaY = newHeight - height
|
|
378
|
+
break
|
|
379
|
+
|
|
380
|
+
default:
|
|
381
|
+
break
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return nextResizeInfo
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// 原有的非等比缩放逻辑保持不变
|
|
194
388
|
switch (index) {
|
|
195
389
|
case ResizeControlIndex.LEFT_TOP:
|
|
196
390
|
nextResizeInfo.width = freezeWidth ? width : width - deltaX * pct
|
|
@@ -292,6 +486,7 @@ export type IHandleResizeParams = {
|
|
|
292
486
|
nodeModel: BaseNodeModel
|
|
293
487
|
graphModel: GraphModel
|
|
294
488
|
cancelCallback?: () => void
|
|
489
|
+
forceProportional?: boolean
|
|
295
490
|
}
|
|
296
491
|
|
|
297
492
|
/**
|
|
@@ -304,6 +499,7 @@ export type IHandleResizeParams = {
|
|
|
304
499
|
* @param nodeModel
|
|
305
500
|
* @param graphModel
|
|
306
501
|
* @param cancelCallback
|
|
502
|
+
* @param forceProportional
|
|
307
503
|
*/
|
|
308
504
|
export const handleResize = ({
|
|
309
505
|
x,
|
|
@@ -314,6 +510,7 @@ export const handleResize = ({
|
|
|
314
510
|
nodeModel,
|
|
315
511
|
graphModel,
|
|
316
512
|
cancelCallback,
|
|
513
|
+
forceProportional = false,
|
|
317
514
|
}: IHandleResizeParams) => {
|
|
318
515
|
const {
|
|
319
516
|
r, // circle
|
|
@@ -331,6 +528,7 @@ export const handleResize = ({
|
|
|
331
528
|
x: oldCenterX,
|
|
332
529
|
y: oldCenterY,
|
|
333
530
|
} = nodeModel
|
|
531
|
+
|
|
334
532
|
const isFreezeWidth = minWidth === maxWidth
|
|
335
533
|
const isFreezeHeight = minHeight === maxHeight
|
|
336
534
|
|
|
@@ -356,6 +554,7 @@ export const handleResize = ({
|
|
|
356
554
|
controlY,
|
|
357
555
|
oldCenterX,
|
|
358
556
|
oldCenterY,
|
|
557
|
+
forceProportional,
|
|
359
558
|
)
|
|
360
559
|
|
|
361
560
|
// 限制放大缩小的最大最小范围
|
|
@@ -405,114 +604,3 @@ export const handleResize = ({
|
|
|
405
604
|
graphModel,
|
|
406
605
|
)
|
|
407
606
|
}
|
|
408
|
-
|
|
409
|
-
export function calculateWidthAndHeight(
|
|
410
|
-
startRotatedTouchControlPoint: SimplePoint,
|
|
411
|
-
endRotatedTouchControlPoint: SimplePoint,
|
|
412
|
-
oldCenter: SimplePoint,
|
|
413
|
-
angle: number,
|
|
414
|
-
freezeWidth = false,
|
|
415
|
-
freezeHeight = false,
|
|
416
|
-
oldWidth: number,
|
|
417
|
-
oldHeight: number,
|
|
418
|
-
) {
|
|
419
|
-
// 假设目前触摸的是右下角的control点
|
|
420
|
-
// 计算出来左上角的control坐标,resize过程左上角的control坐标保持不变
|
|
421
|
-
const freezePoint: SimplePoint = {
|
|
422
|
-
x: oldCenter.x - (startRotatedTouchControlPoint.x - oldCenter.x),
|
|
423
|
-
y: oldCenter.y - (startRotatedTouchControlPoint.y - oldCenter.y),
|
|
424
|
-
}
|
|
425
|
-
// 【touchEndPoint】右下角 + freezePoint左上角 计算出新的中心点
|
|
426
|
-
const newCenter = getNewCenter(freezePoint, endRotatedTouchControlPoint)
|
|
427
|
-
|
|
428
|
-
// 得到【touchEndPoint】右下角-没有transform的坐标
|
|
429
|
-
let endZeroTouchControlPoint: SimplePoint = calculatePointAfterRotateAngle(
|
|
430
|
-
endRotatedTouchControlPoint,
|
|
431
|
-
newCenter,
|
|
432
|
-
-angle,
|
|
433
|
-
)
|
|
434
|
-
|
|
435
|
-
// ---------- 使用transform之前的坐标计算出新的width和height ----------
|
|
436
|
-
|
|
437
|
-
// 得到左上角---没有transform的坐标
|
|
438
|
-
let zeroFreezePoint: SimplePoint = calculatePointAfterRotateAngle(
|
|
439
|
-
freezePoint,
|
|
440
|
-
newCenter,
|
|
441
|
-
-angle,
|
|
442
|
-
)
|
|
443
|
-
|
|
444
|
-
if (freezeWidth) {
|
|
445
|
-
// 如果固定width,那么不能单纯使用endZeroTouchControlPoint.x=startZeroTouchControlPoint.x
|
|
446
|
-
// 因为去掉transform的左上角不一定是重合的,我们要保证的是transform后的左上角重合
|
|
447
|
-
const newWidth = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x)
|
|
448
|
-
const widthDx = newWidth - oldWidth
|
|
449
|
-
|
|
450
|
-
// 点击的是左边锚点,是+widthDx/2,点击是右边锚点,是-widthDx/2
|
|
451
|
-
if (newCenter.x > endZeroTouchControlPoint.x) {
|
|
452
|
-
// 当前触摸的是左边锚点
|
|
453
|
-
newCenter.x = newCenter.x + widthDx / 2
|
|
454
|
-
} else {
|
|
455
|
-
// 当前触摸的是右边锚点
|
|
456
|
-
newCenter.x = newCenter.x - widthDx / 2
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
if (freezeHeight) {
|
|
460
|
-
const newHeight = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y)
|
|
461
|
-
const heightDy = newHeight - oldHeight
|
|
462
|
-
if (newCenter.y > endZeroTouchControlPoint.y) {
|
|
463
|
-
// 当前触摸的是上边锚点
|
|
464
|
-
newCenter.y = newCenter.y + heightDy / 2
|
|
465
|
-
} else {
|
|
466
|
-
newCenter.y = newCenter.y - heightDy / 2
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (freezeWidth || freezeHeight) {
|
|
471
|
-
// 如果调整过transform之前的坐标,那么transform后的坐标也会改变,那么算出来的newCenter也得调整
|
|
472
|
-
// 由于无论如何rotate,中心点都是不变的,因此我们可以使用transform之前的坐标算出新的中心点
|
|
473
|
-
const nowFreezePoint = calculatePointAfterRotateAngle(
|
|
474
|
-
zeroFreezePoint,
|
|
475
|
-
newCenter,
|
|
476
|
-
angle,
|
|
477
|
-
)
|
|
478
|
-
|
|
479
|
-
// 得到当前新rect的左上角与实际上transform后的左上角的偏移量
|
|
480
|
-
const dx = nowFreezePoint.x - freezePoint.x
|
|
481
|
-
const dy = nowFreezePoint.y - freezePoint.y
|
|
482
|
-
|
|
483
|
-
// 修正不使用transform的坐标: 左上角、右下角、center
|
|
484
|
-
newCenter.x = newCenter.x - dx
|
|
485
|
-
newCenter.y = newCenter.y - dy
|
|
486
|
-
zeroFreezePoint = calculatePointAfterRotateAngle(
|
|
487
|
-
freezePoint,
|
|
488
|
-
newCenter,
|
|
489
|
-
-angle,
|
|
490
|
-
)
|
|
491
|
-
endZeroTouchControlPoint = {
|
|
492
|
-
x: newCenter.x - (zeroFreezePoint.x - newCenter.x),
|
|
493
|
-
y: newCenter.y - (zeroFreezePoint.y - newCenter.y),
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// transform之前的坐标的左上角+右下角计算出宽度和高度
|
|
498
|
-
let width = Math.abs(endZeroTouchControlPoint.x - zeroFreezePoint.x)
|
|
499
|
-
let height = Math.abs(endZeroTouchControlPoint.y - zeroFreezePoint.y)
|
|
500
|
-
|
|
501
|
-
// ---------- 使用transform之前的坐标计算出新的width和height ----------
|
|
502
|
-
|
|
503
|
-
if (freezeWidth) {
|
|
504
|
-
// 理论计算出来的width应该等于oldWidth
|
|
505
|
-
// 但是有误差,比如oldWidth = 100; newWidth=100.000000000001
|
|
506
|
-
// 会在handleResize()限制放大缩小的最大最小范围中被阻止滑动
|
|
507
|
-
width = oldWidth
|
|
508
|
-
}
|
|
509
|
-
if (freezeHeight) {
|
|
510
|
-
height = oldHeight
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
return {
|
|
514
|
-
width,
|
|
515
|
-
height,
|
|
516
|
-
center: newCenter,
|
|
517
|
-
}
|
|
518
|
-
}
|
package/src/view/Control.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement as h, Component } from 'preact/compat'
|
|
2
|
-
import {
|
|
2
|
+
import { find, forEach, map, cloneDeep } from 'lodash-es'
|
|
3
3
|
import { Rect } from './shape'
|
|
4
4
|
import LogicFlow from '../LogicFlow'
|
|
5
5
|
import { getNodeBBox, IDragParams, StepDrag, handleResize } from '../util'
|
|
@@ -8,8 +8,8 @@ import { BaseNodeModel, GraphModel } from '../model'
|
|
|
8
8
|
import NodeData = LogicFlow.NodeData
|
|
9
9
|
import VectorData = LogicFlow.VectorData
|
|
10
10
|
import { EventType } from '../constant'
|
|
11
|
-
import ResizeInfo = ResizeControl.ResizeInfo
|
|
12
11
|
import ResizeNodeData = ResizeControl.ResizeNodeData
|
|
12
|
+
import ResizeInfo = ResizeControl.ResizeInfo
|
|
13
13
|
import ControlItemProps = ResizeControl.ControlItemProps
|
|
14
14
|
|
|
15
15
|
export enum ResizeControlIndex {
|
|
@@ -41,6 +41,9 @@ export class ResizeControl extends Component<
|
|
|
41
41
|
readonly graphModel: GraphModel
|
|
42
42
|
readonly dragHandler: StepDrag
|
|
43
43
|
|
|
44
|
+
//判断Shift键状态
|
|
45
|
+
private isShiftPressed = false
|
|
46
|
+
|
|
44
47
|
constructor(props: IResizeControlProps) {
|
|
45
48
|
super()
|
|
46
49
|
const { index, model, graphModel } = props
|
|
@@ -48,17 +51,39 @@ export class ResizeControl extends Component<
|
|
|
48
51
|
this.nodeModel = model
|
|
49
52
|
this.graphModel = graphModel
|
|
50
53
|
|
|
51
|
-
// 初始化拖拽工具
|
|
52
54
|
this.dragHandler = new StepDrag({
|
|
53
55
|
onDragStart: this.onDragStart,
|
|
54
56
|
onDragging: this.onDragging,
|
|
55
57
|
onDragEnd: this.onDragEnd,
|
|
56
58
|
step: graphModel.gridSize,
|
|
57
59
|
})
|
|
60
|
+
|
|
61
|
+
this.bindKeyboardEvents()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//绑定键盘事件监听
|
|
65
|
+
bindKeyboardEvents = () => {
|
|
66
|
+
document.addEventListener('keydown', this.handleKeyDown)
|
|
67
|
+
document.addEventListener('keyup', this.handleKeyUp)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//处理键盘按下事件
|
|
71
|
+
handleKeyDown = (event: KeyboardEvent) => {
|
|
72
|
+
if (event.key === 'Shift') {
|
|
73
|
+
this.isShiftPressed = true
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
handleKeyUp = (event: KeyboardEvent) => {
|
|
78
|
+
if (event.key === 'Shift') {
|
|
79
|
+
this.isShiftPressed = false
|
|
80
|
+
}
|
|
58
81
|
}
|
|
59
82
|
|
|
60
83
|
componentWillUnmount() {
|
|
61
84
|
this.dragHandler.destroy()
|
|
85
|
+
document.removeEventListener('keydown', this.handleKeyDown)
|
|
86
|
+
document.removeEventListener('keyup', this.handleKeyUp)
|
|
62
87
|
}
|
|
63
88
|
|
|
64
89
|
updateEdgePointByAnchors = () => {
|
|
@@ -247,7 +272,6 @@ export class ResizeControl extends Component<
|
|
|
247
272
|
resizeNode = ({ deltaX, deltaY }: VectorData) => {
|
|
248
273
|
const { index } = this
|
|
249
274
|
const { model, graphModel, x, y } = this.props
|
|
250
|
-
|
|
251
275
|
// DONE: 调用每个节点中更新缩放时的方法 updateNode 函数,用来各节点缩放的方法
|
|
252
276
|
handleResize({
|
|
253
277
|
x,
|
|
@@ -257,6 +281,7 @@ export class ResizeControl extends Component<
|
|
|
257
281
|
index,
|
|
258
282
|
nodeModel: model,
|
|
259
283
|
graphModel,
|
|
284
|
+
forceProportional: this.isShiftPressed,
|
|
260
285
|
cancelCallback: () => {
|
|
261
286
|
this.dragHandler.cancelDrag()
|
|
262
287
|
},
|
|
@@ -325,7 +350,6 @@ export class ResizeControl extends Component<
|
|
|
325
350
|
onDragging = ({ deltaX, deltaY }: IDragParams) => {
|
|
326
351
|
const { transformModel } = this.graphModel
|
|
327
352
|
const [dx, dy] = transformModel.fixDeltaXY(deltaX, deltaY)
|
|
328
|
-
|
|
329
353
|
this.resizeNode({
|
|
330
354
|
deltaX: dx,
|
|
331
355
|
deltaY: dy,
|
package/src/view/behavior/dnd.ts
CHANGED
|
@@ -427,6 +427,7 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
|
|
|
427
427
|
const { model, graphModel } = this.props
|
|
428
428
|
this.startTime = new Date().getTime()
|
|
429
429
|
const { editConfigModel } = graphModel
|
|
430
|
+
model.setSelected(true)
|
|
430
431
|
if (editConfigModel.adjustNodePosition && model.draggable) {
|
|
431
432
|
this.stepDrag && this.stepDrag.handleMouseDown(ev)
|
|
432
433
|
}
|