Fix jiggly arrows

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs
2025-08-31 11:49:20 +02:00
parent 57b7f8bd42
commit 493e6c2961
2 changed files with 85 additions and 105 deletions

View File

@@ -193,82 +193,49 @@ export const getStartGlobalEndLocalPointsForSimpleArrowBinding = (
arrow: NonDeleted<ExcalidrawArrowElement>,
start: BindingStrategy,
end: BindingStrategy,
startPoint: GlobalPoint,
endPoint: LocalPoint,
elementsMap: ElementsMap,
): [GlobalPoint, LocalPoint] => {
let startGlobalPoint = startPoint;
let endLocalPoint = endPoint;
): [GlobalPoint, GlobalPoint] => {
let startGlobalPoint = pointFrom<GlobalPoint>(arrow.x, arrow.y);
let endGlobalPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
arrow,
-1,
elementsMap,
);
if (end.mode) {
const newEndLocalPoint = updateBoundPoint(
arrow,
"endBinding",
end.mode
? {
...calculateFixedPointForNonElbowArrowBinding(
arrow,
end.element,
"end",
elementsMap,
end.focusPoint,
),
elementId: end.element.id,
mode: end.mode,
}
: null,
end.element,
elementsMap,
);
endLocalPoint = newEndLocalPoint ?? endLocalPoint;
if (end.focusPoint[0] === 0.5001 && end.focusPoint[1] === 0.5001) {
endLocalPoint = LinearElementEditor.pointFromAbsoluteCoords(
arrow,
elementCenterPoint(arrow, elementsMap),
elementsMap,
);
}
if (start.focusPoint) {
startGlobalPoint = start.focusPoint;
}
if (end.focusPoint) {
endGlobalPoint = end.focusPoint;
}
if (start.mode) {
const newStartLocalPoint = updateBoundPoint(
arrow,
"startBinding",
start.mode
? {
...calculateFixedPointForNonElbowArrowBinding(
arrow,
start.element,
"start",
elementsMap,
start.focusPoint,
),
elementId: start.element.id,
mode: start.mode,
}
: null,
start.element,
elementsMap,
);
startGlobalPoint = newStartLocalPoint
? LinearElementEditor.getPointGlobalCoordinates(
arrow,
newStartLocalPoint,
elementsMap,
)
: startGlobalPoint;
if (start.focusPoint[0] === 0.5001 && start.focusPoint[1] === 0.5001) {
startGlobalPoint = elementCenterPoint(arrow, elementsMap);
}
startGlobalPoint =
start.mode === "orbit"
? bindPointToSnapToElementOutline(
arrow,
start.element,
"start",
elementsMap,
lineSegment(startGlobalPoint, endGlobalPoint),
)
: startGlobalPoint;
}
return [
startGlobalPoint,
pointFrom<LocalPoint>(
endLocalPoint[0] - (startGlobalPoint[0] - arrow.x),
endLocalPoint[1] - (startGlobalPoint[1] - arrow.y),
),
];
if (end.mode) {
endGlobalPoint =
end.mode === "orbit"
? bindPointToSnapToElementOutline(
arrow,
end.element,
"end",
elementsMap,
lineSegment(startGlobalPoint, endGlobalPoint),
)
: endGlobalPoint;
}
return [startGlobalPoint, endGlobalPoint];
};
const bindingStrategyForNewSimpleArrowEndpointDragging = (

View File

@@ -2073,9 +2073,49 @@ const pointDraggingUpdates = (
};
}
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
const s = startIsDragged
? pointFrom<GlobalPoint>(element.x + deltaX, element.y + deltaY)
: pointFrom<GlobalPoint>(element.x, element.y);
const preE = LinearElementEditor.getPointAtIndexGlobalCoordinates(
element,
naiveDraggingPoints,
-1,
elementsMap,
);
const e = endIsDragged
? pointFrom<GlobalPoint>(preE[0] + deltaX, preE[1] + deltaY)
: preE;
const nextArrow = {
...element,
x: s[0],
y: s[1],
points: [
...element.points
.slice(0, -1)
.map((p) =>
pointFrom<LocalPoint>(
p[0] + (s[0] - element.x),
p[1] + (s[1] - element.y),
),
),
pointFrom<LocalPoint>(e[0] - s[0], e[1] - s[1]),
],
};
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
nextArrow,
new Map(
Array.from(naiveDraggingPoints).map(([idx, { point }]) => [
idx,
{
point: pointFrom<LocalPoint>(
point[0] + (s[0] - element.x),
point[1] + (s[1] - element.y),
),
isDragging: true,
},
]),
),
elementsMap,
elements,
app.state,
@@ -2084,39 +2124,11 @@ const pointDraggingUpdates = (
},
);
const originalStartGlobalPoint =
LinearElementEditor.getPointGlobalCoordinates(
element,
element.points[0],
elementsMap,
);
const originalEndGlobalPoint = LinearElementEditor.getPointGlobalCoordinates(
element,
element.points[element.points.length - 1],
elementsMap,
);
const offsetStartGlobalPoint = startIsDragged
? pointFrom<GlobalPoint>(
originalStartGlobalPoint[0] + deltaX,
originalStartGlobalPoint[1] + deltaY,
)
: originalStartGlobalPoint;
const offsetEndGlobalPoint = pointFrom<GlobalPoint>(
originalEndGlobalPoint[0] + deltaX,
originalEndGlobalPoint[1] + deltaY,
);
const offsetEndLocalPoint = pointFrom<LocalPoint>(
offsetEndGlobalPoint[0] - offsetStartGlobalPoint[0],
offsetEndGlobalPoint[1] - offsetStartGlobalPoint[1],
);
const [startGlobalPoint, endLocalPoint] =
const [startGlobalPoint, endGlobalPoint] =
getStartGlobalEndLocalPointsForSimpleArrowBinding(
element,
nextArrow,
start,
end,
offsetStartGlobalPoint,
offsetEndLocalPoint,
elementsMap,
);
const startLocalPoint = LinearElementEditor.pointFromAbsoluteCoords(
@@ -2124,9 +2136,10 @@ const pointDraggingUpdates = (
startGlobalPoint,
elementsMap,
);
const finalEndLocalPoint = pointFrom<LocalPoint>(
endLocalPoint[0] + (startGlobalPoint[0] - element.x),
endLocalPoint[1] + (startGlobalPoint[1] - element.y),
const endLocalPoint = LinearElementEditor.pointFromAbsoluteCoords(
element,
endGlobalPoint,
elementsMap,
);
const indices = Array.from(
@@ -2170,7 +2183,7 @@ const pointDraggingUpdates = (
idx === 0
? { point: startLocalPoint, isDragging: true }
: idx === element.points.length - 1
? { point: finalEndLocalPoint, isDragging: true }
? { point: endLocalPoint, isDragging: true }
: naiveDraggingPoints.get(idx)!,
];
}),