mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-11-23 06:05:37 +01:00
fix: Working outline avoidance
This commit is contained in:
@@ -139,7 +139,7 @@ export const debugDrawPoints = (
|
||||
}: {
|
||||
x: number;
|
||||
y: number;
|
||||
points: LocalPoint[];
|
||||
points: readonly LocalPoint[];
|
||||
},
|
||||
options?: any,
|
||||
) => {
|
||||
|
||||
@@ -31,6 +31,7 @@ import type { MapEntry, Mutable } from "@excalidraw/common/utility-types";
|
||||
import {
|
||||
doBoundsIntersect,
|
||||
getCenterForBounds,
|
||||
getElementAbsoluteCoords,
|
||||
getElementBounds,
|
||||
} from "./bounds";
|
||||
import {
|
||||
@@ -1201,13 +1202,33 @@ export const bindPointToSnapToElementOutline = (
|
||||
startOrEnd: "start" | "end",
|
||||
elementsMap: ElementsMap,
|
||||
customIntersector?: LineSegment<GlobalPoint>,
|
||||
originalArrow?: ExcalidrawArrowElement,
|
||||
): GlobalPoint => {
|
||||
const aabb = aabbForElement(bindableElement, elementsMap);
|
||||
const point = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
arrowElement,
|
||||
startOrEnd === "start" ? 0 : -1,
|
||||
// const point = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
// arrowElement,
|
||||
// startOrEnd === "start" ? 0 : -1,
|
||||
// elementsMap,
|
||||
// );
|
||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(
|
||||
originalArrow ?? arrowElement,
|
||||
elementsMap,
|
||||
);
|
||||
const arrowCenter = pointFrom<GlobalPoint>((x1 + x2) / 2, (y1 + y2) / 2);
|
||||
const point = pointRotateRads(
|
||||
pointFrom<GlobalPoint>(
|
||||
arrowElement.x +
|
||||
arrowElement.points[
|
||||
startOrEnd === "start" ? 0 : arrowElement.points.length - 1
|
||||
][0],
|
||||
arrowElement.y +
|
||||
arrowElement.points[
|
||||
startOrEnd === "start" ? 0 : arrowElement.points.length - 1
|
||||
][1],
|
||||
),
|
||||
arrowCenter,
|
||||
arrowElement.angle as Radians,
|
||||
);
|
||||
|
||||
if (arrowElement.points.length < 2) {
|
||||
// New arrow creation, so no snapping
|
||||
@@ -1219,11 +1240,25 @@ export const bindPointToSnapToElementOutline = (
|
||||
: point;
|
||||
const elbowed = isElbowArrow(arrowElement);
|
||||
const center = getCenterForBounds(aabb);
|
||||
const adjacentPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
arrowElement,
|
||||
startOrEnd === "start" ? 1 : -2,
|
||||
elementsMap,
|
||||
const adjacentPoint = pointRotateRads(
|
||||
pointFrom<GlobalPoint>(
|
||||
arrowElement.x +
|
||||
arrowElement.points[
|
||||
startOrEnd === "start" ? 1 : arrowElement.points.length - 2
|
||||
][0],
|
||||
arrowElement.y +
|
||||
arrowElement.points[
|
||||
startOrEnd === "start" ? 1 : arrowElement.points.length - 2
|
||||
][1],
|
||||
),
|
||||
arrowCenter,
|
||||
arrowElement.angle as Radians,
|
||||
);
|
||||
// const adjacentPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
// arrowElement,
|
||||
// startOrEnd === "start" ? 1 : -2,
|
||||
// elementsMap,
|
||||
// );
|
||||
const bindingGap = getBindingGap(bindableElement, arrowElement);
|
||||
|
||||
let intersection: GlobalPoint | null = null;
|
||||
@@ -1536,6 +1571,7 @@ export const updateBoundPoint = (
|
||||
bindableElement: ExcalidrawBindableElement,
|
||||
elementsMap: ElementsMap,
|
||||
customIntersector?: LineSegment<GlobalPoint>,
|
||||
originalArrow?: ExcalidrawArrowElement,
|
||||
): LocalPoint | null => {
|
||||
if (
|
||||
binding == null ||
|
||||
@@ -1615,54 +1651,50 @@ export const updateBoundPoint = (
|
||||
|
||||
const isNested = (arrowTooShort || isOverlapping) && isLargerThanOther;
|
||||
|
||||
const rotatedGlobal = pointRotateRads(
|
||||
global,
|
||||
elementCenterPoint(arrow, elementsMap),
|
||||
-arrow.angle as Radians,
|
||||
);
|
||||
|
||||
const maybeOutlineGlobal =
|
||||
binding.mode === "orbit" && bindableElement
|
||||
? isNested
|
||||
? rotatedGlobal
|
||||
? global
|
||||
: bindPointToSnapToElementOutline(
|
||||
{
|
||||
...arrow,
|
||||
id: randomId(),
|
||||
x: pointIndex === 0 ? rotatedGlobal[0] : arrow.x,
|
||||
y: pointIndex === 0 ? rotatedGlobal[1] : arrow.y,
|
||||
points:
|
||||
points: [
|
||||
pointIndex === 0
|
||||
? [
|
||||
pointFrom<LocalPoint>(0, 0),
|
||||
...arrow.points
|
||||
.slice(1)
|
||||
.map((p) =>
|
||||
pointFrom<LocalPoint>(
|
||||
p[0] - (rotatedGlobal[0] - arrow.x),
|
||||
p[1] - (rotatedGlobal[1] - arrow.y),
|
||||
),
|
||||
),
|
||||
]
|
||||
: [
|
||||
...arrow.points.slice(0, -1),
|
||||
pointFrom<LocalPoint>(
|
||||
rotatedGlobal[0] - arrow.x,
|
||||
rotatedGlobal[1] - arrow.y,
|
||||
),
|
||||
],
|
||||
? LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
global[0],
|
||||
global[1],
|
||||
null,
|
||||
)
|
||||
: arrow.points[0],
|
||||
...arrow.points.slice(1, -1),
|
||||
pointIndex === arrow.points.length - 1
|
||||
? LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
elementsMap,
|
||||
global[0],
|
||||
global[1],
|
||||
null,
|
||||
)
|
||||
: arrow.points[arrow.points.length - 1],
|
||||
],
|
||||
},
|
||||
bindableElement,
|
||||
pointIndex === 0 ? "start" : "end",
|
||||
elementsMap,
|
||||
customIntersector,
|
||||
originalArrow,
|
||||
)
|
||||
: global;
|
||||
|
||||
return LinearElementEditor.pointFromAbsoluteCoords(
|
||||
return LinearElementEditor.createPointAt(
|
||||
arrow,
|
||||
maybeOutlineGlobal,
|
||||
elementsMap,
|
||||
maybeOutlineGlobal[0],
|
||||
maybeOutlineGlobal[1],
|
||||
null,
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
invariant,
|
||||
isShallowEqual,
|
||||
getFeatureFlag,
|
||||
randomId,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import {
|
||||
@@ -1955,36 +1956,40 @@ export class LinearElementEditor {
|
||||
let y1;
|
||||
let x2;
|
||||
let y2;
|
||||
if (element.points.length < 2 || !ShapeCache.get(element)) {
|
||||
// XXX this is just a poor estimate and not very useful
|
||||
const { minX, minY, maxX, maxY } = element.points.reduce(
|
||||
(limits, [x, y]) => {
|
||||
limits.minY = Math.min(limits.minY, y);
|
||||
limits.minX = Math.min(limits.minX, x);
|
||||
// if (element.points.length < 2 || !ShapeCache.get(element)) {
|
||||
// // XXX this is just a poor estimate and not very useful
|
||||
// const { minX, minY, maxX, maxY } = element.points.reduce(
|
||||
// (limits, [x, y]) => {
|
||||
// limits.minY = Math.min(limits.minY, y);
|
||||
// limits.minX = Math.min(limits.minX, x);
|
||||
|
||||
limits.maxX = Math.max(limits.maxX, x);
|
||||
limits.maxY = Math.max(limits.maxY, y);
|
||||
// limits.maxX = Math.max(limits.maxX, x);
|
||||
// limits.maxY = Math.max(limits.maxY, y);
|
||||
|
||||
return limits;
|
||||
},
|
||||
{ minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity },
|
||||
);
|
||||
x1 = minX + element.x;
|
||||
y1 = minY + element.y;
|
||||
x2 = maxX + element.x;
|
||||
y2 = maxY + element.y;
|
||||
} else {
|
||||
const shape = ShapeCache.generateElementShape(element, null);
|
||||
// return limits;
|
||||
// },
|
||||
// { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity },
|
||||
// );
|
||||
// x1 = minX + element.x;
|
||||
// y1 = minY + element.y;
|
||||
// x2 = maxX + element.x;
|
||||
// y2 = maxY + element.y;
|
||||
// } else {
|
||||
const shape = ShapeCache.generateElementShape(element, {
|
||||
isExporting: true,
|
||||
canvasBackgroundColor: "traansparent",
|
||||
embedsValidationStatus: new Map(),
|
||||
});
|
||||
|
||||
// first element is always the curve
|
||||
const ops = getCurvePathOps(shape[0]);
|
||||
// first element is always the curve
|
||||
const ops = getCurvePathOps(shape[0]);
|
||||
|
||||
const [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps(ops);
|
||||
x1 = minX + element.x;
|
||||
y1 = minY + element.y;
|
||||
x2 = maxX + element.x;
|
||||
y2 = maxY + element.y;
|
||||
}
|
||||
const [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps(ops);
|
||||
x1 = minX + element.x;
|
||||
y1 = minY + element.y;
|
||||
x2 = maxX + element.x;
|
||||
y2 = maxY + element.y;
|
||||
// }
|
||||
const cx = (x1 + x2) / 2;
|
||||
const cy = (y1 + y2) / 2;
|
||||
coords = [x1, y1, x2, y2, cx, cy];
|
||||
@@ -2257,16 +2262,10 @@ const pointDraggingUpdates = (
|
||||
: element.points[element.points.length - 1];
|
||||
const nextArrow = {
|
||||
...element,
|
||||
id: randomId(),
|
||||
points: [
|
||||
offsetStartLocalPoint,
|
||||
...element.points
|
||||
.slice(1, -1)
|
||||
.map((p) =>
|
||||
pointFrom<LocalPoint>(
|
||||
p[0] - offsetStartLocalPoint[0],
|
||||
p[1] - offsetStartLocalPoint[1],
|
||||
),
|
||||
),
|
||||
...element.points.slice(1, -1),
|
||||
offsetEndLocalPoint,
|
||||
],
|
||||
startBinding:
|
||||
@@ -2321,12 +2320,13 @@ const pointDraggingUpdates = (
|
||||
? nextArrow.points[0]
|
||||
: endBindable
|
||||
? updateBoundPoint(
|
||||
nextArrow,
|
||||
element,
|
||||
"endBinding",
|
||||
nextArrow.endBinding,
|
||||
endBindable,
|
||||
elementsMap,
|
||||
customIntersector,
|
||||
element,
|
||||
) || nextArrow.points[nextArrow.points.length - 1]
|
||||
: nextArrow.points[nextArrow.points.length - 1];
|
||||
|
||||
@@ -2352,12 +2352,13 @@ const pointDraggingUpdates = (
|
||||
? nextArrow.points[nextArrow.points.length - 1]
|
||||
: startBindable
|
||||
? updateBoundPoint(
|
||||
nextArrow,
|
||||
element,
|
||||
"startBinding",
|
||||
nextArrow.startBinding,
|
||||
startBindable,
|
||||
elementsMap,
|
||||
customIntersector,
|
||||
element,
|
||||
) || nextArrow.points[0]
|
||||
: nextArrow.points[0];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user