mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-11-15 02:04:21 +01:00
feat: Diagonal binding point
Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
KEYS,
|
KEYS,
|
||||||
arrayToMap,
|
arrayToMap,
|
||||||
|
debugDrawLine,
|
||||||
|
debugDrawPoint,
|
||||||
getFeatureFlag,
|
getFeatureFlag,
|
||||||
invariant,
|
invariant,
|
||||||
isTransparent,
|
isTransparent,
|
||||||
@@ -19,6 +21,7 @@ import {
|
|||||||
vectorScale,
|
vectorScale,
|
||||||
vectorNormalize,
|
vectorNormalize,
|
||||||
PRECISION,
|
PRECISION,
|
||||||
|
lineSegmentIntersectionPoints,
|
||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
|
|
||||||
import type { LineSegment, LocalPoint, Radians } from "@excalidraw/math";
|
import type { LineSegment, LocalPoint, Radians } from "@excalidraw/math";
|
||||||
@@ -54,6 +57,7 @@ import {
|
|||||||
isBindableElement,
|
isBindableElement,
|
||||||
isBoundToContainer,
|
isBoundToContainer,
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
|
isRectangularElement,
|
||||||
isRectanguloidElement,
|
isRectanguloidElement,
|
||||||
isTextElement,
|
isTextElement,
|
||||||
} from "./typeChecks";
|
} from "./typeChecks";
|
||||||
@@ -685,13 +689,14 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
|||||||
: {
|
: {
|
||||||
mode: "orbit",
|
mode: "orbit",
|
||||||
element: hit,
|
element: hit,
|
||||||
focusPoint: opts?.finalize
|
focusPoint:
|
||||||
? LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
projectFixedPointOntoDiagonal(
|
||||||
arrow,
|
arrow,
|
||||||
startDragged ? 0 : -1,
|
globalPoint,
|
||||||
elementsMap,
|
hit,
|
||||||
)
|
startDragged ? "start" : "end",
|
||||||
: globalPoint,
|
elementsMap,
|
||||||
|
) || globalPoint,
|
||||||
}
|
}
|
||||||
: { mode: null };
|
: { mode: null };
|
||||||
|
|
||||||
@@ -701,6 +706,105 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const projectFixedPointOntoDiagonal = (
|
||||||
|
arrow: ExcalidrawArrowElement,
|
||||||
|
point: GlobalPoint,
|
||||||
|
element: ExcalidrawElement,
|
||||||
|
startOrEnd: "start" | "end",
|
||||||
|
elementsMap: ElementsMap,
|
||||||
|
) => {
|
||||||
|
const center = elementCenterPoint(element, elementsMap);
|
||||||
|
const diagonalOne = isRectangularElement(element)
|
||||||
|
? lineSegment<GlobalPoint>(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(element.x, element.y),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
element.x + element.width,
|
||||||
|
element.y + element.height,
|
||||||
|
),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: lineSegment<GlobalPoint>(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(element.x + element.width / 2, element.y),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
element.x + element.width / 2,
|
||||||
|
element.y + element.height,
|
||||||
|
),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const diagonalTwo = isRectangularElement(element)
|
||||||
|
? lineSegment<GlobalPoint>(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(element.x + element.width, element.y),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(element.x, element.y + element.height),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: lineSegment<GlobalPoint>(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(element.x, element.y + element.height / 2),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
element.x + element.width,
|
||||||
|
element.y + element.height / 2,
|
||||||
|
),
|
||||||
|
center,
|
||||||
|
element.angle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
invariant(arrow.points.length >= 2, "Arrow must have at least two points");
|
||||||
|
|
||||||
|
const a = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||||
|
arrow,
|
||||||
|
startOrEnd === "start" ? 1 : arrow.points.length - 2,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
const b = pointFromVector<GlobalPoint>(
|
||||||
|
vectorScale(
|
||||||
|
vectorFromPoint(point, a),
|
||||||
|
2 * pointDistance(a, point) +
|
||||||
|
Math.max(
|
||||||
|
pointDistance(diagonalOne[0], diagonalOne[1]),
|
||||||
|
pointDistance(diagonalTwo[0], diagonalTwo[1]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
a,
|
||||||
|
);
|
||||||
|
const intersector = lineSegment<GlobalPoint>(a, b);
|
||||||
|
const p1 = lineSegmentIntersectionPoints(diagonalOne, intersector);
|
||||||
|
const p2 = lineSegmentIntersectionPoints(diagonalTwo, intersector);
|
||||||
|
const d1 = p1 && pointDistance(a, p1);
|
||||||
|
const d2 = p2 && pointDistance(a, p2);
|
||||||
|
|
||||||
|
if (d1 != null && d2 != null) {
|
||||||
|
return d1 < d2 ? p1 : p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p1 || p2 || null;
|
||||||
|
};
|
||||||
|
|
||||||
const getBindingStrategyForDraggingBindingElementEndpoints_complex = (
|
const getBindingStrategyForDraggingBindingElementEndpoints_complex = (
|
||||||
arrow: NonDeleted<ExcalidrawArrowElement>,
|
arrow: NonDeleted<ExcalidrawArrowElement>,
|
||||||
draggingPoints: PointsPositionUpdates,
|
draggingPoints: PointsPositionUpdates,
|
||||||
|
|||||||
Reference in New Issue
Block a user