Unfinished simple arrow avoidance
This commit is contained in:
parent
898499777f
commit
6efe4c6f38
@ -3,9 +3,6 @@ import {
|
|||||||
arrayToMap,
|
arrayToMap,
|
||||||
isBindingFallthroughEnabled,
|
isBindingFallthroughEnabled,
|
||||||
tupleToCoors,
|
tupleToCoors,
|
||||||
invariant,
|
|
||||||
isDevEnv,
|
|
||||||
isTestEnv,
|
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -399,10 +396,15 @@ export const maybeSuggestBindingsForLinearElementAtCoords = (
|
|||||||
}[],
|
}[],
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
zoom: AppState["zoom"],
|
zoom: AppState["zoom"],
|
||||||
|
elementsMap: ElementsMap,
|
||||||
|
// During line creation the start binding hasn't been written yet
|
||||||
|
// into `linearElement`
|
||||||
|
oppositeBindingBoundElement?: ExcalidrawBindableElement | null,
|
||||||
): ExcalidrawBindableElement[] =>
|
): ExcalidrawBindableElement[] =>
|
||||||
Array.from(
|
Array.from(
|
||||||
pointerCoords.reduce(
|
pointerCoords.reduce(
|
||||||
(acc: Set<NonDeleted<ExcalidrawBindableElement>>, coords) => {
|
(acc: Set<NonDeleted<ExcalidrawBindableElement>>, coords) => {
|
||||||
|
const p = pointFrom<GlobalPoint>(coords.x, coords.y);
|
||||||
const hoveredBindableElement = getHoveredElementForBinding(
|
const hoveredBindableElement = getHoveredElementForBinding(
|
||||||
coords,
|
coords,
|
||||||
scene.getNonDeletedElements(),
|
scene.getNonDeletedElements(),
|
||||||
@ -411,8 +413,20 @@ export const maybeSuggestBindingsForLinearElementAtCoords = (
|
|||||||
isElbowArrow(linearElement),
|
isElbowArrow(linearElement),
|
||||||
isElbowArrow(linearElement),
|
isElbowArrow(linearElement),
|
||||||
);
|
);
|
||||||
|
const pointIsInside =
|
||||||
|
hoveredBindableElement != null &&
|
||||||
|
isPointInElement(p, hoveredBindableElement, elementsMap);
|
||||||
|
|
||||||
if (hoveredBindableElement != null) {
|
if (
|
||||||
|
hoveredBindableElement != null &&
|
||||||
|
((pointIsInside &&
|
||||||
|
oppositeBindingBoundElement?.id === hoveredBindableElement.id) ||
|
||||||
|
!isLinearElementSimpleAndAlreadyBound(
|
||||||
|
linearElement,
|
||||||
|
oppositeBindingBoundElement?.id,
|
||||||
|
hoveredBindableElement,
|
||||||
|
))
|
||||||
|
) {
|
||||||
acc.add(hoveredBindableElement);
|
acc.add(hoveredBindableElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,35 +1010,40 @@ const getDistanceForBinding = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const bindPointToSnapToElementOutline = (
|
export const bindPointToSnapToElementOutline = (
|
||||||
arrow: ExcalidrawElbowArrowElement,
|
linearElement: ExcalidrawLinearElement,
|
||||||
bindableElement: ExcalidrawBindableElement,
|
bindableElement: ExcalidrawBindableElement,
|
||||||
startOrEnd: "start" | "end",
|
startOrEnd: "start" | "end",
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
): GlobalPoint => {
|
): GlobalPoint => {
|
||||||
if (isDevEnv() || isTestEnv()) {
|
|
||||||
invariant(arrow.points.length > 1, "Arrow should have at least 2 points");
|
|
||||||
}
|
|
||||||
|
|
||||||
const aabb = aabbForElement(bindableElement, elementsMap);
|
const aabb = aabbForElement(bindableElement, elementsMap);
|
||||||
const localP =
|
const localP =
|
||||||
arrow.points[startOrEnd === "start" ? 0 : arrow.points.length - 1];
|
linearElement.points[
|
||||||
|
startOrEnd === "start" ? 0 : linearElement.points.length - 1
|
||||||
|
];
|
||||||
const globalP = pointFrom<GlobalPoint>(
|
const globalP = pointFrom<GlobalPoint>(
|
||||||
arrow.x + localP[0],
|
linearElement.x + localP[0],
|
||||||
arrow.y + localP[1],
|
linearElement.y + localP[1],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (linearElement.points.length < 2) {
|
||||||
|
// New arrow creation, so no snapping
|
||||||
|
return globalP;
|
||||||
|
}
|
||||||
|
|
||||||
const edgePoint = isRectanguloidElement(bindableElement)
|
const edgePoint = isRectanguloidElement(bindableElement)
|
||||||
? avoidRectangularCorner(bindableElement, elementsMap, globalP)
|
? avoidRectangularCorner(bindableElement, elementsMap, globalP)
|
||||||
: globalP;
|
: globalP;
|
||||||
const elbowed = isElbowArrow(arrow);
|
const elbowed = isElbowArrow(linearElement);
|
||||||
const center = getCenterForBounds(aabb);
|
const center = getCenterForBounds(aabb);
|
||||||
const adjacentPointIdx = startOrEnd === "start" ? 1 : arrow.points.length - 2;
|
const adjacentPointIdx =
|
||||||
|
startOrEnd === "start" ? 1 : linearElement.points.length - 2;
|
||||||
const adjacentPoint = pointRotateRads(
|
const adjacentPoint = pointRotateRads(
|
||||||
pointFrom<GlobalPoint>(
|
pointFrom<GlobalPoint>(
|
||||||
arrow.x + arrow.points[adjacentPointIdx][0],
|
linearElement.x + linearElement.points[adjacentPointIdx][0],
|
||||||
arrow.y + arrow.points[adjacentPointIdx][1],
|
linearElement.y + linearElement.points[adjacentPointIdx][1],
|
||||||
),
|
),
|
||||||
center,
|
center,
|
||||||
arrow.angle ?? 0,
|
linearElement.angle ?? 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let intersection: GlobalPoint | null = null;
|
let intersection: GlobalPoint | null = null;
|
||||||
@ -1083,7 +1102,35 @@ export const bindPointToSnapToElementOutline = (
|
|||||||
return edgePoint;
|
return edgePoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
return elbowed ? intersection : edgePoint;
|
return intersection;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getOutlineAvoidingPoint = (
|
||||||
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
|
hoveredElement: ExcalidrawBindableElement | null,
|
||||||
|
coords: GlobalPoint,
|
||||||
|
pointIndex: number,
|
||||||
|
elementsMap: ElementsMap,
|
||||||
|
): GlobalPoint => {
|
||||||
|
if (hoveredElement) {
|
||||||
|
const newPoints = Array.from(element.points);
|
||||||
|
newPoints[pointIndex] = pointFrom<LocalPoint>(
|
||||||
|
coords[0] - element.x,
|
||||||
|
coords[1] - element.y,
|
||||||
|
);
|
||||||
|
|
||||||
|
return bindPointToSnapToElementOutline(
|
||||||
|
{
|
||||||
|
...element,
|
||||||
|
points: newPoints,
|
||||||
|
},
|
||||||
|
hoveredElement,
|
||||||
|
pointIndex === 0 ? "start" : "end",
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return coords;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const avoidRectangularCorner = (
|
export const avoidRectangularCorner = (
|
||||||
|
@ -45,6 +45,7 @@ import type { Mutable } from "@excalidraw/common/utility-types";
|
|||||||
import {
|
import {
|
||||||
bindOrUnbindLinearElement,
|
bindOrUnbindLinearElement,
|
||||||
getHoveredElementForBinding,
|
getHoveredElementForBinding,
|
||||||
|
getOutlineAvoidingPoint,
|
||||||
isBindingEnabled,
|
isBindingEnabled,
|
||||||
maybeSuggestBindingsForLinearElementAtCoords,
|
maybeSuggestBindingsForLinearElementAtCoords,
|
||||||
} from "./binding";
|
} from "./binding";
|
||||||
@ -58,6 +59,7 @@ import { headingIsHorizontal, vectorToHeading } from "./heading";
|
|||||||
import { mutateElement } from "./mutateElement";
|
import { mutateElement } from "./mutateElement";
|
||||||
import { getBoundTextElement, handleBindTextResize } from "./textElement";
|
import { getBoundTextElement, handleBindTextResize } from "./textElement";
|
||||||
import {
|
import {
|
||||||
|
isArrowElement,
|
||||||
isBindingElement,
|
isBindingElement,
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
isFixedPointBinding,
|
isFixedPointBinding,
|
||||||
@ -290,15 +292,17 @@ export class LinearElementEditor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const elbowed = isElbowArrow(element);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isElbowArrow(element) &&
|
elbowed &&
|
||||||
!linearElementEditor.pointerDownState.lastClickedIsEndPoint &&
|
!linearElementEditor.pointerDownState.lastClickedIsEndPoint &&
|
||||||
linearElementEditor.pointerDownState.lastClickedPoint !== 0
|
linearElementEditor.pointerDownState.lastClickedPoint !== 0
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedPointsIndices = isElbowArrow(element)
|
const selectedPointsIndices = elbowed
|
||||||
? [
|
? [
|
||||||
!!linearElementEditor.selectedPointsIndices?.includes(0)
|
!!linearElementEditor.selectedPointsIndices?.includes(0)
|
||||||
? 0
|
? 0
|
||||||
@ -308,7 +312,7 @@ export class LinearElementEditor {
|
|||||||
: undefined,
|
: undefined,
|
||||||
].filter((idx): idx is number => idx !== undefined)
|
].filter((idx): idx is number => idx !== undefined)
|
||||||
: linearElementEditor.selectedPointsIndices;
|
: linearElementEditor.selectedPointsIndices;
|
||||||
const lastClickedPoint = isElbowArrow(element)
|
const lastClickedPoint = elbowed
|
||||||
? linearElementEditor.pointerDownState.lastClickedPoint > 0
|
? linearElementEditor.pointerDownState.lastClickedPoint > 0
|
||||||
? element.points.length - 1
|
? element.points.length - 1
|
||||||
: 0
|
: 0
|
||||||
@ -375,7 +379,7 @@ export class LinearElementEditor {
|
|||||||
app.scene,
|
app.scene,
|
||||||
new Map(
|
new Map(
|
||||||
selectedPointsIndices.map((pointIndex) => {
|
selectedPointsIndices.map((pointIndex) => {
|
||||||
const newPointPosition: LocalPoint =
|
let newPointPosition: LocalPoint =
|
||||||
pointIndex === lastClickedPoint
|
pointIndex === lastClickedPoint
|
||||||
? LinearElementEditor.createPointAt(
|
? LinearElementEditor.createPointAt(
|
||||||
element,
|
element,
|
||||||
@ -390,6 +394,67 @@ export class LinearElementEditor {
|
|||||||
element.points[pointIndex][0] + deltaX,
|
element.points[pointIndex][0] + deltaX,
|
||||||
element.points[pointIndex][1] + deltaY,
|
element.points[pointIndex][1] + deltaY,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
pointIndex === 0 ||
|
||||||
|
pointIndex === element.points.length - 1
|
||||||
|
) {
|
||||||
|
const [, , , , cx, cy] = getElementAbsoluteCoords(
|
||||||
|
element,
|
||||||
|
elementsMap,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
let newGlobalPointPosition = pointRotateRads(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
element.x + newPointPosition[0],
|
||||||
|
element.y + newPointPosition[1],
|
||||||
|
),
|
||||||
|
pointFrom<GlobalPoint>(cx, cy),
|
||||||
|
element.angle,
|
||||||
|
);
|
||||||
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
|
{
|
||||||
|
x: newGlobalPointPosition[0],
|
||||||
|
y: newGlobalPointPosition[1],
|
||||||
|
},
|
||||||
|
app.scene.getNonDeletedElements(),
|
||||||
|
elementsMap,
|
||||||
|
app.state.zoom,
|
||||||
|
true,
|
||||||
|
isElbowArrow(element),
|
||||||
|
);
|
||||||
|
|
||||||
|
const otherBinding =
|
||||||
|
element[pointIndex === 0 ? "endBinding" : "startBinding"];
|
||||||
|
|
||||||
|
// Allow binding inside the element if both ends are inside
|
||||||
|
if (
|
||||||
|
isArrowElement(element) &&
|
||||||
|
!(
|
||||||
|
hoveredElement?.id === otherBinding?.elementId &&
|
||||||
|
hoveredElement != null
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
newGlobalPointPosition = getOutlineAvoidingPoint(
|
||||||
|
element,
|
||||||
|
hoveredElement,
|
||||||
|
newGlobalPointPosition,
|
||||||
|
pointIndex,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
newPointPosition = LinearElementEditor.createPointAt(
|
||||||
|
element,
|
||||||
|
elementsMap,
|
||||||
|
newGlobalPointPosition[0] -
|
||||||
|
linearElementEditor.pointerOffset.x,
|
||||||
|
newGlobalPointPosition[1] -
|
||||||
|
linearElementEditor.pointerOffset.y,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
pointIndex,
|
pointIndex,
|
||||||
{
|
{
|
||||||
@ -452,6 +517,7 @@ export class LinearElementEditor {
|
|||||||
coords,
|
coords,
|
||||||
app.scene,
|
app.scene,
|
||||||
app.state.zoom,
|
app.state.zoom,
|
||||||
|
elementsMap,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,7 @@ export const getDefaultAppState = (): Omit<
|
|||||||
searchMatches: null,
|
searchMatches: null,
|
||||||
lockedMultiSelections: {},
|
lockedMultiSelections: {},
|
||||||
activeLockedId: null,
|
activeLockedId: null,
|
||||||
|
arrowOriginalEndpoint: null,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -249,6 +250,7 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
searchMatches: { browser: false, export: false, server: false },
|
searchMatches: { browser: false, export: false, server: false },
|
||||||
lockedMultiSelections: { browser: true, export: true, server: true },
|
lockedMultiSelections: { browser: true, export: true, server: true },
|
||||||
activeLockedId: { browser: false, export: false, server: false },
|
activeLockedId: { browser: false, export: false, server: false },
|
||||||
|
arrowOriginalEndpoint: { browser: false, export: false, server: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const _clearAppStateForStorage = <
|
const _clearAppStateForStorage = <
|
||||||
|
@ -232,9 +232,11 @@ import {
|
|||||||
hitElementBoundingBox,
|
hitElementBoundingBox,
|
||||||
isLineElement,
|
isLineElement,
|
||||||
isSimpleArrow,
|
isSimpleArrow,
|
||||||
|
getOutlineAvoidingPoint,
|
||||||
|
mutateElement,
|
||||||
} from "@excalidraw/element";
|
} from "@excalidraw/element";
|
||||||
|
|
||||||
import type { LocalPoint, Radians } from "@excalidraw/math";
|
import type { GlobalPoint, LocalPoint, Radians } from "@excalidraw/math";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
@ -5888,6 +5890,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
[scenePointer],
|
[scenePointer],
|
||||||
this.scene,
|
this.scene,
|
||||||
this.state.zoom,
|
this.state.zoom,
|
||||||
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
//this.state.startBoundElement,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -5897,9 +5901,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
if (this.state.multiElement) {
|
if (this.state.multiElement) {
|
||||||
const { multiElement } = this.state;
|
const { multiElement } = this.state;
|
||||||
const { x: rx, y: ry } = multiElement;
|
const { x: rx, y: ry, points, lastCommittedPoint } = multiElement;
|
||||||
|
|
||||||
const { points, lastCommittedPoint } = multiElement;
|
|
||||||
const lastPoint = points[points.length - 1];
|
const lastPoint = points[points.length - 1];
|
||||||
|
|
||||||
setCursorForShape(this.interactiveCanvas, this.state);
|
setCursorForShape(this.interactiveCanvas, this.state);
|
||||||
@ -7757,7 +7759,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
elementType === "arrow"
|
elementType === "arrow"
|
||||||
? [currentItemStartArrowhead, currentItemEndArrowhead]
|
? [currentItemStartArrowhead, currentItemEndArrowhead]
|
||||||
: [null, null];
|
: [null, null];
|
||||||
|
|
||||||
const element =
|
const element =
|
||||||
elementType === "arrow"
|
elementType === "arrow"
|
||||||
? newArrowElement({
|
? newArrowElement({
|
||||||
@ -7805,6 +7806,28 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
locked: false,
|
locked: false,
|
||||||
frameId: topLayerFrame ? topLayerFrame.id : null,
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
||||||
});
|
});
|
||||||
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
|
{
|
||||||
|
x: gridX,
|
||||||
|
y: gridY,
|
||||||
|
},
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hoveredElement) {
|
||||||
|
mutateElement(element, this.scene.getNonDeletedElementsMap(), {
|
||||||
|
startBinding: {
|
||||||
|
elementId: hoveredElement.id,
|
||||||
|
focus: 0,
|
||||||
|
gap: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
const nextSelectedElementIds = {
|
const nextSelectedElementIds = {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
@ -8671,8 +8694,67 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
} else if (isLinearElement(newElement)) {
|
} else if (isLinearElement(newElement)) {
|
||||||
pointerDownState.drag.hasOccurred = true;
|
pointerDownState.drag.hasOccurred = true;
|
||||||
const points = newElement.points;
|
const points = newElement.points;
|
||||||
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
|
{ x: gridX, y: gridY },
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
|
isElbowArrow(newElement),
|
||||||
|
isElbowArrow(newElement),
|
||||||
|
);
|
||||||
|
const arrowIsInsideTheSameElement =
|
||||||
|
newElement.startBinding &&
|
||||||
|
hoveredElement?.id === newElement.startBinding.elementId;
|
||||||
|
|
||||||
let dx = gridX - newElement.x;
|
let dx = gridX - newElement.x;
|
||||||
let dy = gridY - newElement.y;
|
let dy = gridY - newElement.y;
|
||||||
|
let firstPointX = newElement.x + newElement.points[0][0];
|
||||||
|
let firstPointY = newElement.y + newElement.points[0][1];
|
||||||
|
|
||||||
|
if (isBindingElement(newElement, false)) {
|
||||||
|
if (!arrowIsInsideTheSameElement) {
|
||||||
|
const [outlinePointX, outlinePointY] = getOutlineAvoidingPoint(
|
||||||
|
newElement,
|
||||||
|
hoveredElement,
|
||||||
|
pointFrom(gridX, gridY),
|
||||||
|
newElement.points.length - 1,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
dx = outlinePointX - newElement.x;
|
||||||
|
dy = outlinePointY - newElement.y;
|
||||||
|
|
||||||
|
if (!this.state.arrowOriginalEndpoint) {
|
||||||
|
this.setState({
|
||||||
|
arrowOriginalEndpoint: pointFrom<GlobalPoint>(
|
||||||
|
firstPointX,
|
||||||
|
firstPointY,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const otherHoveredElement = getHoveredElementForBinding(
|
||||||
|
{ x: firstPointX, y: firstPointY },
|
||||||
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.scene.getNonDeletedElementsMap(),
|
||||||
|
this.state.zoom,
|
||||||
|
isElbowArrow(newElement),
|
||||||
|
isElbowArrow(newElement),
|
||||||
|
);
|
||||||
|
[firstPointX, firstPointY] = getOutlineAvoidingPoint(
|
||||||
|
newElement,
|
||||||
|
otherHoveredElement,
|
||||||
|
pointFrom(firstPointX, firstPointY),
|
||||||
|
0,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
firstPointX =
|
||||||
|
this.state.arrowOriginalEndpoint?.[0] ?? firstPointX;
|
||||||
|
firstPointY =
|
||||||
|
this.state.arrowOriginalEndpoint?.[1] ?? firstPointY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldRotateWithDiscreteAngle(event) && points.length === 2) {
|
if (shouldRotateWithDiscreteAngle(event) && points.length === 2) {
|
||||||
({ width: dx, height: dy } = getLockedLinearCursorAlignSize(
|
({ width: dx, height: dy } = getLockedLinearCursorAlignSize(
|
||||||
@ -8687,6 +8769,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scene.mutateElement(
|
this.scene.mutateElement(
|
||||||
newElement,
|
newElement,
|
||||||
{
|
{
|
||||||
|
x: firstPointX,
|
||||||
|
y: firstPointY,
|
||||||
points: [...points, pointFrom<LocalPoint>(dx, dy)],
|
points: [...points, pointFrom<LocalPoint>(dx, dy)],
|
||||||
},
|
},
|
||||||
{ informMutation: false, isDragging: false },
|
{ informMutation: false, isDragging: false },
|
||||||
@ -8698,6 +8782,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scene.mutateElement(
|
this.scene.mutateElement(
|
||||||
newElement,
|
newElement,
|
||||||
{
|
{
|
||||||
|
x: firstPointX,
|
||||||
|
y: firstPointY,
|
||||||
points: [...points.slice(0, -1), pointFrom<LocalPoint>(dx, dy)],
|
points: [...points.slice(0, -1), pointFrom<LocalPoint>(dx, dy)],
|
||||||
},
|
},
|
||||||
{ isDragging: true, informMutation: false },
|
{ isDragging: true, informMutation: false },
|
||||||
@ -8716,6 +8802,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
[pointerCoords],
|
[pointerCoords],
|
||||||
this.scene,
|
this.scene,
|
||||||
this.state.zoom,
|
this.state.zoom,
|
||||||
|
elementsMap,
|
||||||
|
this.state.startBoundElement,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -8953,6 +9041,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementsAreBeingDragged: false,
|
selectedElementsAreBeingDragged: false,
|
||||||
|
arrowOriginalEndpoint: null,
|
||||||
});
|
});
|
||||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ import type {
|
|||||||
DurableIncrement,
|
DurableIncrement,
|
||||||
EphemeralIncrement,
|
EphemeralIncrement,
|
||||||
} from "@excalidraw/element";
|
} from "@excalidraw/element";
|
||||||
|
import type { GlobalPoint } from "@excalidraw/math";
|
||||||
|
|
||||||
import type { Action } from "./actions/types";
|
import type { Action } from "./actions/types";
|
||||||
import type { Spreadsheet } from "./charts";
|
import type { Spreadsheet } from "./charts";
|
||||||
@ -444,6 +445,7 @@ export interface AppState {
|
|||||||
// as elements are unlocked, we remove the groupId from the elements
|
// as elements are unlocked, we remove the groupId from the elements
|
||||||
// and also remove groupId from this map
|
// and also remove groupId from this map
|
||||||
lockedMultiSelections: { [groupId: string]: true };
|
lockedMultiSelections: { [groupId: string]: true };
|
||||||
|
arrowOriginalEndpoint: GlobalPoint | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SearchMatch = {
|
export type SearchMatch = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user