feat: Elbow arrow segment fixing & positioning (#8952)

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
Márk Tolmács
2025-01-17 18:07:03 +01:00
committed by GitHub
co-authored by dwelle
parent 8551823da9
commit 91ebf8b0ea
33 changed files with 3282 additions and 1716 deletions
+52 -7
View File
@@ -10,6 +10,7 @@ import type {
ExcalidrawImageElement,
ElementsMap,
SceneElementsMap,
ExcalidrawElbowArrowElement,
} from "./types";
import type { Mutable } from "../utility-types";
import {
@@ -53,7 +54,6 @@ import {
import { wrapText } from "./textWrapping";
import { LinearElementEditor } from "./linearElementEditor";
import { isInGroup } from "../groups";
import { mutateElbowArrow } from "./routing";
import type { GlobalPoint } from "../../math";
import {
pointCenter,
@@ -177,10 +177,10 @@ export const transformElements = (
elementsMap,
transformHandleType,
scene,
originalElements,
{
shouldResizeFromCenter,
shouldMaintainAspectRatio,
originalElementsMap: originalElements,
flipByX,
flipByY,
nextWidth,
@@ -531,8 +531,10 @@ const rotateMultipleElements = (
);
if (isElbowArrow(element)) {
const points = getArrowLocalFixedPoints(element, elementsMap);
mutateElbowArrow(element, elementsMap, points);
// Needed to re-route the arrow
mutateElement(element, {
points: getArrowLocalFixedPoints(element, elementsMap),
});
} else {
mutateElement(
element,
@@ -1201,6 +1203,7 @@ export const resizeMultipleElements = (
elementsMap: ElementsMap,
handleDirection: TransformHandleDirection,
scene: Scene,
originalElementsMap: ElementsMap,
{
shouldMaintainAspectRatio = false,
shouldResizeFromCenter = false,
@@ -1208,7 +1211,6 @@ export const resizeMultipleElements = (
flipByY = false,
nextHeight,
nextWidth,
originalElementsMap,
originalBoundingBox,
}: {
nextWidth?: number;
@@ -1217,7 +1219,6 @@ export const resizeMultipleElements = (
shouldResizeFromCenter?: boolean;
flipByX?: boolean;
flipByY?: boolean;
originalElementsMap?: ElementsMap;
// added to improve performance
originalBoundingBox?: BoundingBox;
} = {},
@@ -1387,6 +1388,9 @@ export const resizeMultipleElements = (
fontSize?: ExcalidrawTextElement["fontSize"];
scale?: ExcalidrawImageElement["scale"];
boundTextFontSize?: ExcalidrawTextElement["fontSize"];
startBinding?: ExcalidrawElbowArrowElement["startBinding"];
endBinding?: ExcalidrawElbowArrowElement["endBinding"];
fixedSegments?: ExcalidrawElbowArrowElement["fixedSegments"];
};
}[] = [];
@@ -1427,6 +1431,44 @@ export const resizeMultipleElements = (
...rescaledPoints,
};
if (isElbowArrow(orig)) {
// Mirror fixed point binding for elbow arrows
// when resize goes into the negative direction
if (orig.startBinding) {
update.startBinding = {
...orig.startBinding,
fixedPoint: [
flipByX
? -orig.startBinding.fixedPoint[0] + 1
: orig.startBinding.fixedPoint[0],
flipByY
? -orig.startBinding.fixedPoint[1] + 1
: orig.startBinding.fixedPoint[1],
],
};
}
if (orig.endBinding) {
update.endBinding = {
...orig.endBinding,
fixedPoint: [
flipByX
? -orig.endBinding.fixedPoint[0] + 1
: orig.endBinding.fixedPoint[0],
flipByY
? -orig.endBinding.fixedPoint[1] + 1
: orig.endBinding.fixedPoint[1],
],
};
}
if (orig.fixedSegments && rescaledPoints.points) {
update.fixedSegments = orig.fixedSegments.map((segment) => ({
...segment,
start: rescaledPoints.points[segment.index - 1],
end: rescaledPoints.points[segment.index],
}));
}
}
if (isImageElement(orig)) {
update.scale = [
orig.scale[0] * flipFactorX,
@@ -1472,7 +1514,10 @@ export const resizeMultipleElements = (
} of elementsAndUpdates) {
const { width, height, angle } = update;
mutateElement(element, update, false);
mutateElement(element, update, false, {
// needed for the fixed binding point udpate to take effect
isDragging: true,
});
updateBoundElements(element, elementsMap as SceneElementsMap, {
simultaneouslyUpdated: elementsToUpdate,