chore: Refactor binding gap calc

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs
2026-05-10 12:12:06 +00:00
parent 60f29dc188
commit 73c940bcf6
10 changed files with 255 additions and 300 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ export const isFocusPointVisible = (
element: bindableElement,
elementsMap,
point: focusPoint,
threshold: getBindingGap(bindableElement, arrow),
threshold: getBindingGap(bindableElement),
overrideShouldTestInside: true,
})
);
+7 -12
View File
@@ -111,18 +111,13 @@ export type BindingStrategy =
* IMPORTANT: currently must be > 0 (this also applies to the computed gap)
*/
export const BASE_BINDING_GAP = 5;
export const BASE_BINDING_GAP_ELBOW = 5;
export const BASE_ARROW_MIN_LENGTH = 10;
export const FOCUS_POINT_SIZE = 10 / 1.5;
export const getBindingGap = (
bindTarget: ExcalidrawBindableElement,
opts: Pick<ExcalidrawArrowElement, "elbowed">,
): number => {
return (
(opts.elbowed ? BASE_BINDING_GAP_ELBOW : BASE_BINDING_GAP) +
bindTarget.strokeWidth / 2
);
return BASE_BINDING_GAP + bindTarget.strokeWidth / 2;
};
export const maxBindingDistance_simple = (zoom?: AppState["zoom"]): number => {
@@ -1416,7 +1411,7 @@ export const bindPointToSnapToElementOutline = (
startOrEnd === "start" ? 1 : -2,
elementsMap,
);
const bindingGap = getBindingGap(bindableElement, arrowElement);
const bindingGap = getBindingGap(bindableElement);
const aabb = aabbForElement(bindableElement, elementsMap);
const bindableCenter = getCenterForBounds(aabb);
@@ -1477,7 +1472,7 @@ export const bindPointToSnapToElementOutline = (
bindableElement,
elementsMap,
anotherIntersector,
BASE_BINDING_GAP_ELBOW,
BASE_BINDING_GAP,
).sort(pointDistanceSq)[0];
}
} else {
@@ -1536,7 +1531,7 @@ export const avoidRectangularCorner = (
-bindTarget.angle as Radians,
);
const bindingGap = getBindingGap(bindTarget, arrowElement);
const bindingGap = getBindingGap(bindTarget);
if (nonRotatedPoint[0] < bindTarget.x && nonRotatedPoint[1] < bindTarget.y) {
// Top left
@@ -1714,7 +1709,7 @@ export const updateBoundPoint = (
otherBindable,
elementsMap,
intersector,
getBindingGap(otherBindable, arrow),
getBindingGap(otherBindable),
).sort(
(a, b) => pointDistanceSq(a, focusPoint) - pointDistanceSq(b, focusPoint),
)[0];
@@ -1724,7 +1719,7 @@ export const updateBoundPoint = (
bindableElement,
elementsMap,
intersector,
getBindingGap(bindableElement, arrow),
getBindingGap(bindableElement),
).sort(
(a, b) =>
pointDistanceSq(a, otherFocusPointOrArrowPoint) -
@@ -1752,7 +1747,7 @@ export const updateBoundPoint = (
element: otherBindable,
point: outlinePoint,
elementsMap,
threshold: getBindingGap(otherBindable, arrow),
threshold: getBindingGap(otherBindable),
overrideShouldTestInside: true,
})
) {
+1 -1
View File
@@ -316,7 +316,7 @@ export const getAllHoveredElementAtPoint = (
element,
point,
elementsMap,
threshold: tolerance ?? getBindingGap(element, arrow),
threshold: tolerance ?? getBindingGap(element),
overrideShouldTestInside: true,
})
) {
+9 -9
View File
@@ -30,7 +30,7 @@ import {
getHeadingForElbowArrowSnap,
getGlobalFixedPointForBindableElement,
getBindingGap,
BASE_BINDING_GAP_ELBOW,
BASE_BINDING_GAP,
} from "./binding";
import { distanceToElement } from "./distance";
import {
@@ -1311,8 +1311,8 @@ const getElbowArrowData = (
offsetFromHeading(
startHeading,
arrow.startArrowhead
? getBindingGap(hoveredStartElement, { elbowed: true }) * 6
: getBindingGap(hoveredStartElement, { elbowed: true }) * 2,
? getBindingGap(hoveredStartElement) * 6
: getBindingGap(hoveredStartElement) * 2,
1,
),
)
@@ -1324,8 +1324,8 @@ const getElbowArrowData = (
offsetFromHeading(
endHeading,
arrow.endArrowhead
? getBindingGap(hoveredEndElement, { elbowed: true }) * 6
: getBindingGap(hoveredEndElement, { elbowed: true }) * 2,
? getBindingGap(hoveredEndElement) * 6
: getBindingGap(hoveredEndElement) * 2,
1,
),
)
@@ -1372,8 +1372,8 @@ const getElbowArrowData = (
? 0
: BASE_PADDING -
(arrow.startArrowhead
? BASE_BINDING_GAP_ELBOW * 6
: BASE_BINDING_GAP_ELBOW * 2),
? BASE_BINDING_GAP * 6
: BASE_BINDING_GAP * 2),
BASE_PADDING,
),
boundsOverlap
@@ -1388,8 +1388,8 @@ const getElbowArrowData = (
? 0
: BASE_PADDING -
(arrow.endArrowhead
? BASE_BINDING_GAP_ELBOW * 6
: BASE_BINDING_GAP_ELBOW * 2),
? BASE_BINDING_GAP * 6
: BASE_BINDING_GAP * 2),
BASE_PADDING,
),
boundsOverlap,
+137 -133
View File
@@ -588,104 +588,101 @@ const getDiagonalsForBindableElement = (
return [diagonalOne, diagonalTwo];
};
export const getHighlightedMidpointIndex = (
point: GlobalPoint,
const getSnappedMidpointIndexForElbowArrow = (
element: ExcalidrawBindableElement,
elementsMap: ElementsMap,
zoom: AppState["zoom"],
arrow: { elbowed: boolean },
): number => {
const center = elementCenterPoint(element, elementsMap);
const TOLERANCE = 0.05;
const maxDistance = maxBindingDistance_simple(zoom) + element.strokeWidth / 2;
point: GlobalPoint,
center: GlobalPoint,
horizontalThreshold: number,
verticalThreshold: number,
) => {
const { x, y, width, height, angle } = element;
const nonRotated = pointRotateRads(point, center, -angle as Radians);
// snap-to-center point is adaptive to element size, but we don't want to go
// above and below certain px distance
const verticalThreshold = clamp(TOLERANCE * height, 5, maxDistance);
const horizontalThreshold = clamp(TOLERANCE * width, 5, maxDistance);
if (arrow.elbowed) {
const nonRotated = pointRotateRads(point, center, -angle as Radians);
const bindingGap = getBindingGap(element, arrow);
if (pointDistance(center, nonRotated) < bindingGap) {
return -1;
}
if (
nonRotated[0] <= x + width / 2 &&
nonRotated[1] > center[1] - verticalThreshold &&
nonRotated[1] < center[1] + verticalThreshold
) {
return 2;
} else if (
nonRotated[1] <= y + height / 2 &&
nonRotated[0] > center[0] - horizontalThreshold &&
nonRotated[0] < center[0] + horizontalThreshold
) {
return 3;
} else if (
nonRotated[0] >= x + width / 2 &&
nonRotated[1] > center[1] - verticalThreshold &&
nonRotated[1] < center[1] + verticalThreshold
) {
return 0;
} else if (
nonRotated[1] >= y + height / 2 &&
nonRotated[0] > center[0] - horizontalThreshold &&
nonRotated[0] < center[0] + horizontalThreshold
) {
return 1;
} else if (element.type === "diamond") {
const distance = bindingGap;
const topLeft = pointFrom<GlobalPoint>(
x + width / 4 - distance,
y + height / 4 - distance,
);
const topRight = pointFrom<GlobalPoint>(
x + (3 * width) / 4 + distance,
y + height / 4 - distance,
);
const bottomLeft = pointFrom<GlobalPoint>(
x + width / 4 - distance,
y + (3 * height) / 4 + distance,
);
const bottomRight = pointFrom<GlobalPoint>(
x + (3 * width) / 4 + distance,
y + (3 * height) / 4 + distance,
);
if (
pointDistance(bottomLeft, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 1;
}
if (
pointDistance(bottomRight, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 0;
}
if (
pointDistance(topLeft, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 2;
}
if (
pointDistance(topRight, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 3;
}
}
const bindingGap = getBindingGap(element);
if (pointDistance(center, nonRotated) < bindingGap) {
return -1;
}
if (
nonRotated[0] <= x + width / 2 &&
nonRotated[1] > center[1] - verticalThreshold &&
nonRotated[1] < center[1] + verticalThreshold
) {
return 2;
} else if (
nonRotated[1] <= y + height / 2 &&
nonRotated[0] > center[0] - horizontalThreshold &&
nonRotated[0] < center[0] + horizontalThreshold
) {
return 3;
} else if (
nonRotated[0] >= x + width / 2 &&
nonRotated[1] > center[1] - verticalThreshold &&
nonRotated[1] < center[1] + verticalThreshold
) {
return 0;
} else if (
nonRotated[1] >= y + height / 2 &&
nonRotated[0] > center[0] - horizontalThreshold &&
nonRotated[0] < center[0] + horizontalThreshold
) {
return 1;
} else if (element.type === "diamond") {
const distance = bindingGap;
const topLeft = pointFrom<GlobalPoint>(
x + width / 4 - distance,
y + height / 4 - distance,
);
const topRight = pointFrom<GlobalPoint>(
x + (3 * width) / 4 + distance,
y + height / 4 - distance,
);
const bottomLeft = pointFrom<GlobalPoint>(
x + width / 4 - distance,
y + (3 * height) / 4 + distance,
);
const bottomRight = pointFrom<GlobalPoint>(
x + (3 * width) / 4 + distance,
y + (3 * height) / 4 + distance,
);
if (
pointDistance(bottomLeft, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 1;
}
if (
pointDistance(bottomRight, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 0;
}
if (
pointDistance(topLeft, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 2;
}
if (
pointDistance(topRight, nonRotated) <
Math.max(horizontalThreshold, verticalThreshold)
) {
return 3;
}
}
return -1;
};
const getSnappedMidpointIndexForSimpleArrow = (
element: ExcalidrawBindableElement,
point: GlobalPoint,
elementsMap: ElementsMap,
horizontalThreshold: number,
verticalThreshold: number,
) => {
const baseMidpoints = getAllMidpoints(element, elementsMap);
for (let i = 0; i < baseMidpoints.length; i++) {
@@ -708,41 +705,6 @@ export const getHighlightedMidpointIndex = (
return -1;
};
export const getSnapOutlineMidPoint = (
point: GlobalPoint,
element: ExcalidrawBindableElement,
elementsMap: ElementsMap,
zoom: AppState["zoom"],
arrow: { elbowed: boolean },
): GlobalPoint | undefined => {
const center = elementCenterPoint(element, elementsMap);
const baseMidpoints = getAllMidpoints(element, elementsMap);
const sideMidpoints =
element.type === "diamond"
? baseMidpoints.map((midpoint) => {
return pointFrom<GlobalPoint>(
midpoint[0] + (midpoint[0] - center[0]) * 0.1,
midpoint[1] + (midpoint[1] - center[1]) * 0.1,
);
})
: baseMidpoints;
const idx = getHighlightedMidpointIndex(
point,
element,
elementsMap,
zoom,
arrow,
);
if (idx === -1) {
return undefined;
}
return sideMidpoints[idx];
};
export const getAllMidpoints = (
element: ExcalidrawBindableElement,
elementsMap: ElementsMap,
@@ -750,10 +712,9 @@ export const getAllMidpoints = (
const center = elementCenterPoint(element, elementsMap);
if (element.type === "diamond") {
return getDiamondBaseCorners(element).map((curve) => {
const point = bezierEquation(curve, 0.5);
return pointRotateRads(point, center, element.angle);
});
return getDiamondBaseCorners(element).map((curve) =>
pointRotateRads(bezierEquation(curve, 0.5), center, element.angle),
);
}
return [
@@ -770,6 +731,52 @@ export const getAllMidpoints = (
);
};
export const getSnapOutlineMidPoint = (
point: GlobalPoint,
element: ExcalidrawBindableElement,
elementsMap: ElementsMap,
zoom: AppState["zoom"],
arrow: { elbowed: boolean },
): GlobalPoint | undefined => {
const center = elementCenterPoint(element, elementsMap);
const baseMidpoints = getAllMidpoints(element, elementsMap);
const sideMidpoints =
element.type === "diamond"
? baseMidpoints.map((midpoint) => {
return pointFrom<GlobalPoint>(
midpoint[0] + (midpoint[0] - center[0]) * 0.1,
midpoint[1] + (midpoint[1] - center[1]) * 0.1,
);
})
: baseMidpoints;
const TOLERANCE = 0.05;
const maxDistance = maxBindingDistance_simple(zoom) + element.strokeWidth / 2;
const verticalThreshold = clamp(TOLERANCE * element.height, 5, maxDistance);
const horizontalThreshold = clamp(TOLERANCE * element.width, 5, maxDistance);
const idx = arrow.elbowed
? getSnappedMidpointIndexForElbowArrow(
element,
point,
center,
horizontalThreshold,
verticalThreshold,
)
: getSnappedMidpointIndexForSimpleArrow(
element,
point,
elementsMap,
horizontalThreshold,
verticalThreshold,
);
if (idx === -1) {
return undefined;
}
return sideMidpoints[idx];
};
export const projectFixedPointOntoDiagonal = (
arrow: ExcalidrawArrowElement,
point: GlobalPoint,
@@ -780,9 +787,6 @@ export const projectFixedPointOntoDiagonal = (
isMidpointSnappingEnabled: boolean = true,
): GlobalPoint | null => {
invariant(arrow.points.length >= 2, "Arrow must have at least two points");
if (arrow.width < 3 && arrow.height < 3) {
return null;
}
if (isMidpointSnappingEnabled) {
const sideMidPoint = getSnapOutlineMidPoint(
@@ -24,13 +24,11 @@ import {
deconstructRectanguloidElement,
elementCenterPoint,
getAllMidpoints,
getHighlightedMidpointIndex,
FOCUS_POINT_SIZE,
getOmitSidesForEditorInterface,
getTransformHandles,
getTransformHandlesFromCoords,
hasBoundingBox,
hitElementItself,
isArrowElement,
isBindableElement,
isElbowArrow,
@@ -412,74 +410,42 @@ const renderBindingHighlightForBindableElement_simple = (
break;
}
// Draw midpoint indicators
if (
appState.isMidpointSnappingEnabled &&
(isFrameLikeElement(suggestedBinding.element) ||
isBindableElement(suggestedBinding.element))
) {
// Draw midpoint indicators
const linearElement = appState.selectedLinearElement;
const arrow =
linearElement?.elementId &&
LinearElementEditor.getElement(linearElement?.elementId, elementsMap);
const cursorIsInsideBindable =
pointerCoords &&
hitElementItself({
point: pointerCoords,
element: suggestedBinding.element,
elementsMap,
threshold: 0,
overrideShouldTestInside: true,
});
context.save();
const isElbow =
(arrow && isElbowArrow(arrow)) ||
(appState.activeTool.type === "arrow" &&
appState.currentItemArrowType === "elbow");
const midpointRadius = 4 / appState.zoom.value;
if (!cursorIsInsideBindable || isElbow) {
context.save();
const midpoints = getAllMidpoints(suggestedBinding.element, elementsMap);
const highlightedIdx = pointerCoords
? getHighlightedMidpointIndex(
pointerCoords,
suggestedBinding.element,
elementsMap,
appState.zoom,
{ elbowed: isElbow },
)
: -1;
const midpointRadius = 4 / appState.zoom.value;
midpoints.forEach((midpoint, idx) => {
const isHighlighted =
highlightedIdx === idx && (!cursorIsInsideBindable || isElbow);
if (isHighlighted) {
context.fillStyle =
appState.theme === THEME.DARK
? `rgba(3, 93, 161, 1)`
: `rgba(106, 189, 252, 1)`;
context.beginPath();
context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI);
context.fill();
} else {
context.fillStyle =
appState.theme === THEME.DARK
? `rgba(0, 0, 0, 0.8)`
: `rgba(65, 65, 65, 0.5)`;
context.beginPath();
context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI);
context.fill();
}
});
context.restore();
// Render base midpoints
const midpoints = getAllMidpoints(suggestedBinding.element, elementsMap);
for (const midpoint of midpoints) {
context.fillStyle =
appState.theme === THEME.DARK
? `rgba(0, 0, 0, 0.8)`
: `rgba(65, 65, 65, 0.5)`;
context.beginPath();
context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI);
context.fill();
}
// Render the highlighted midpoint if any
const midpoint = appState.suggestedBinding?.midPoint;
if (midpoint) {
context.fillStyle =
appState.theme === THEME.DARK
? `rgba(3, 93, 161, 1)`
: `rgba(106, 189, 252, 1)`;
context.beginPath();
context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI);
context.fill();
}
context.restore();
}
};
@@ -16703,7 +16703,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -16718,7 +16718,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -16729,8 +16729,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -16742,7 +16742,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 10,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
}
`;
@@ -16787,8 +16787,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -16807,8 +16807,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -17121,7 +17121,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"index": "a3",
"isDeleted": false,
"link": null,
@@ -17134,7 +17134,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -17145,8 +17145,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -17157,7 +17157,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 7,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
},
"inserted": {
"isDeleted": true,
@@ -17451,7 +17451,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -17466,7 +17466,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -17477,8 +17477,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -17490,7 +17490,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 10,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
}
`;
@@ -17759,7 +17759,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"index": "a3",
"isDeleted": false,
"link": null,
@@ -17772,7 +17772,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -17783,8 +17783,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -17795,7 +17795,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 10,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
},
"inserted": {
"isDeleted": true,
@@ -18097,7 +18097,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -18112,7 +18112,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -18123,8 +18123,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -18136,7 +18136,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 10,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
}
`;
@@ -18405,7 +18405,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"index": "a3",
"isDeleted": false,
"link": null,
@@ -18418,7 +18418,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -18429,8 +18429,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -18441,7 +18441,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 10,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
},
"inserted": {
"isDeleted": true,
@@ -18741,7 +18741,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -18756,7 +18756,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -18767,8 +18767,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -18780,7 +18780,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 10,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
}
`;
@@ -18841,8 +18841,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -19135,7 +19135,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"index": "a3",
"isDeleted": false,
"link": null,
@@ -19148,7 +19148,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -19159,8 +19159,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -19171,7 +19171,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 7,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
},
"inserted": {
"isDeleted": true,
@@ -19493,7 +19493,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"id": "id13",
"index": "a3",
"isDeleted": false,
@@ -19508,7 +19508,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -19519,8 +19519,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -19532,7 +19532,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 11,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
}
`;
@@ -19604,8 +19604,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -19883,7 +19883,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "0.00661",
"height": 0,
"index": "a3",
"isDeleted": false,
"link": null,
@@ -19896,7 +19896,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
],
[
"88.00000",
"-0.00661",
0,
],
],
"roughness": 1,
@@ -19907,8 +19907,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"startBinding": {
"elementId": "id0",
"fixedPoint": [
"0.50021",
"0.50021",
1,
"0.50010",
],
"mode": "orbit",
},
@@ -19919,7 +19919,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"version": 7,
"width": "88.00000",
"x": 6,
"y": "0.01706",
"y": "0.01000",
},
"inserted": {
"isDeleted": true,
@@ -182,14 +182,14 @@ exports[`move element > rectangles with binding arrow 7`] = `
"elementId": "id3",
"fixedPoint": [
"-0.02000",
"0.47928",
"0.48010",
],
"mode": "orbit",
},
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": "93.60377",
"height": "90.01760",
"id": "id6",
"index": "a2",
"isDeleted": false,
@@ -204,7 +204,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
],
[
89,
"93.60377",
"90.01760",
],
],
"roughness": 1,
@@ -217,7 +217,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
"elementId": "id0",
"fixedPoint": [
"1.06000",
"0.52181",
"0.56011",
],
"mode": "orbit",
},
@@ -230,6 +230,6 @@ exports[`move element > rectangles with binding arrow 7`] = `
"versionNonce": 271613161,
"width": 89,
"x": 106,
"y": "52.18052",
"y": "56.01120",
}
`;
+5 -15
View File
@@ -1590,9 +1590,7 @@ describe("history", () => {
expect(API.getUndoStack().length).toBe(5);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5002127206977238, 0.5002127206977238,
]),
fixedPoint: expect.arrayContaining([1, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1615,9 +1613,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(1);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5002127206977238, 0.5002127206977238,
]),
fixedPoint: expect.arrayContaining([1, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1640,9 +1636,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(0);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5002127206977238, 0.5002127206977238,
]),
fixedPoint: expect.arrayContaining([1, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1673,9 +1667,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(0);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5002127206977238, 0.5002127206977238,
]),
fixedPoint: expect.arrayContaining([1, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
@@ -1698,9 +1690,7 @@ describe("history", () => {
expect(API.getRedoStack().length).toBe(1);
expect(arrow.startBinding).toEqual({
elementId: rect1.id,
fixedPoint: expect.arrayContaining([
0.5002127206977238, 0.5002127206977238,
]),
fixedPoint: expect.arrayContaining([1, 0.5001]),
mode: "orbit",
});
expect(arrow.endBinding).toEqual({
+4 -4
View File
@@ -115,11 +115,11 @@ describe("move element", () => {
expect([rectA.x, rectA.y]).toEqual([0, 0]);
expect([rectB.x, rectB.y]).toEqual([200, 0]);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints(
[[106, 52.18052313249668]],
[[106, 56.011199999998695]],
0,
);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints(
[[88, 91.60376557808824]],
[[88, 88.01760000000121]],
0,
);
@@ -140,11 +140,11 @@ describe("move element", () => {
expect([rectA.x, rectA.y]).toEqual([0, 0]);
expect([rectB.x, rectB.y]).toEqual([201, 2]);
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints(
[[106, 52.18052313249668]],
[[106, 56.011199999998695]],
0,
);
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints(
[[89, 93.60376557808823]],
[[89, 90.01760000000121]],
0,
);