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>, arrow: NonDeleted<ExcalidrawArrowElement>,
start: BindingStrategy, start: BindingStrategy,
end: BindingStrategy, end: BindingStrategy,
startPoint: GlobalPoint,
endPoint: LocalPoint,
elementsMap: ElementsMap, elementsMap: ElementsMap,
): [GlobalPoint, LocalPoint] => { ): [GlobalPoint, GlobalPoint] => {
let startGlobalPoint = startPoint; let startGlobalPoint = pointFrom<GlobalPoint>(arrow.x, arrow.y);
let endLocalPoint = endPoint; let endGlobalPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
arrow,
-1,
elementsMap,
);
if (end.mode) { if (start.focusPoint) {
const newEndLocalPoint = updateBoundPoint( startGlobalPoint = start.focusPoint;
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 (end.focusPoint) {
endGlobalPoint = end.focusPoint;
} }
if (start.mode) { if (start.mode) {
const newStartLocalPoint = updateBoundPoint( startGlobalPoint =
arrow, start.mode === "orbit"
"startBinding", ? bindPointToSnapToElementOutline(
start.mode
? {
...calculateFixedPointForNonElbowArrowBinding(
arrow, arrow,
start.element, start.element,
"start", "start",
elementsMap, elementsMap,
start.focusPoint, lineSegment(startGlobalPoint, endGlobalPoint),
),
elementId: start.element.id,
mode: start.mode,
}
: null,
start.element,
elementsMap,
);
startGlobalPoint = newStartLocalPoint
? LinearElementEditor.getPointGlobalCoordinates(
arrow,
newStartLocalPoint,
elementsMap,
) )
: startGlobalPoint; : startGlobalPoint;
if (start.focusPoint[0] === 0.5001 && start.focusPoint[1] === 0.5001) {
startGlobalPoint = elementCenterPoint(arrow, elementsMap);
}
} }
return [ if (end.mode) {
startGlobalPoint, endGlobalPoint =
pointFrom<LocalPoint>( end.mode === "orbit"
endLocalPoint[0] - (startGlobalPoint[0] - arrow.x), ? bindPointToSnapToElementOutline(
endLocalPoint[1] - (startGlobalPoint[1] - arrow.y), arrow,
), end.element,
]; "end",
elementsMap,
lineSegment(startGlobalPoint, endGlobalPoint),
)
: endGlobalPoint;
}
return [startGlobalPoint, endGlobalPoint];
}; };
const bindingStrategyForNewSimpleArrowEndpointDragging = ( 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, 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, elementsMap,
elements, elements,
app.state, app.state,
@@ -2084,39 +2124,11 @@ const pointDraggingUpdates = (
}, },
); );
const originalStartGlobalPoint = const [startGlobalPoint, endGlobalPoint] =
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] =
getStartGlobalEndLocalPointsForSimpleArrowBinding( getStartGlobalEndLocalPointsForSimpleArrowBinding(
element, nextArrow,
start, start,
end, end,
offsetStartGlobalPoint,
offsetEndLocalPoint,
elementsMap, elementsMap,
); );
const startLocalPoint = LinearElementEditor.pointFromAbsoluteCoords( const startLocalPoint = LinearElementEditor.pointFromAbsoluteCoords(
@@ -2124,9 +2136,10 @@ const pointDraggingUpdates = (
startGlobalPoint, startGlobalPoint,
elementsMap, elementsMap,
); );
const finalEndLocalPoint = pointFrom<LocalPoint>( const endLocalPoint = LinearElementEditor.pointFromAbsoluteCoords(
endLocalPoint[0] + (startGlobalPoint[0] - element.x), element,
endLocalPoint[1] + (startGlobalPoint[1] - element.y), endGlobalPoint,
elementsMap,
); );
const indices = Array.from( const indices = Array.from(
@@ -2170,7 +2183,7 @@ const pointDraggingUpdates = (
idx === 0 idx === 0
? { point: startLocalPoint, isDragging: true } ? { point: startLocalPoint, isDragging: true }
: idx === element.points.length - 1 : idx === element.points.length - 1
? { point: finalEndLocalPoint, isDragging: true } ? { point: endLocalPoint, isDragging: true }
: naiveDraggingPoints.get(idx)!, : naiveDraggingPoints.get(idx)!,
]; ];
}), }),