-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgeometry.js
More file actions
107 lines (95 loc) · 2.98 KB
/
geometry.js
File metadata and controls
107 lines (95 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
* Compute the overlapping dimensions of two rectangles.
* Along the moving axis, the size becomes the overlap.
* Along the other axis, the size remains constrained.
*
* @returns { width, height } or null if there is no overlap
*/
const computeOverlapSize = (
movingAxis,
topRectangleSize,
belowRectangleSize,
topRectanglePosition,
belowRectanglePosition
) => {
const constrainedWidth = Math.min(topRectangleSize.width, belowRectangleSize.width);
const constrainedHeight = Math.min(topRectangleSize.height, belowRectangleSize.height);
const sizeAlongAxis =
movingAxis === "x" ? constrainedWidth : constrainedHeight;
const gap = Math.abs(topRectanglePosition - belowRectanglePosition);
const overlap = Math.max(0, sizeAlongAxis - gap);
const width = movingAxis === "x" ? Math.round(overlap) : constrainedWidth;
const height = movingAxis === "y" ? Math.round(overlap) : constrainedHeight;
if (width <= 0 || height <= 0) {
return null;
}
return { width, height };
};
/**
* Compute the center of the overlap along the moving axis.
* The perpendicular coordinate is preserved.
*
* @returns { ox, oy } overlap center
*/
const computeOverlapCenter = (
movingAxis,
topRectangleSize,
belowRectangleSize,
topRectanglePosition,
belowRectanglePosition,
belowPerpPosition
) => {
const topAxisSize =
movingAxis === "x" ? topRectangleSize.width : topRectangleSize.height;
const belowAxisSize =
movingAxis === "x" ? belowRectangleSize.width : belowRectangleSize.height;
const topStart = topRectanglePosition - topAxisSize / 2;
const topEnd = topRectanglePosition + topAxisSize / 2;
const belowStart = belowRectanglePosition - belowAxisSize / 2;
const belowEnd = belowRectanglePosition + belowAxisSize / 2;
const overlapStart = Math.max(topStart, belowStart);
const overlapEnd = Math.min(topEnd, belowEnd);
const center = Math.round((overlapStart + overlapEnd) / 2);
const perpOffset = Math.round(belowPerpPosition);
return {
ox: movingAxis === "x" ? center : perpOffset,
oy: movingAxis === "y" ? center : perpOffset,
};
};
/**
* Returns the size along the given axis.
*/
const axisLength = (axis, size) => {
return axis === "x" ? size.width : size.height;
};
/**
* If topRectanglePosition is within snapPercent of belowRectanglePosition on the moving axis,
* snap the result to match the below block exactly.
*
* @returns { size: Size, origin: Point, snapped: boolean }
*/
const snapOverlapIfClose = ({
axis,
topRectanglePosition,
belowRectanglePosition,
belowRectangleSize,
belowRectangleOrigin,
overlapSize,
overlapOrigin,
snapPercentage,
}) => {
const delta = topRectanglePosition - belowRectanglePosition;
const threshold = axisLength(axis, belowRectangleSize) * snapPercentage;
if (Math.abs(delta) <= threshold) {
return {
size: belowRectangleSize,
origin: belowRectangleOrigin,
snapped: true,
};
}
return {
size: overlapSize,
origin: overlapOrigin,
snapped: false,
};
}