mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
[skip ci] Change flipping
This commit is contained in:
parent
db9e501d35
commit
bcbd418154
1 changed files with 45 additions and 43 deletions
|
@ -1,6 +1,6 @@
|
||||||
import { getNonDeletedElements } from "@excalidraw/element";
|
import { getNonDeletedElements } from "@excalidraw/element";
|
||||||
import {
|
import {
|
||||||
bindOrUnbindLinearElements,
|
bindOrUnbindLinearElement,
|
||||||
isBindingEnabled,
|
isBindingEnabled,
|
||||||
} from "@excalidraw/element/binding";
|
} from "@excalidraw/element/binding";
|
||||||
import { getCommonBoundingBox } from "@excalidraw/element/bounds";
|
import { getCommonBoundingBox } from "@excalidraw/element/bounds";
|
||||||
|
@ -12,15 +12,15 @@ import { deepCopyElement } from "@excalidraw/element/duplicate";
|
||||||
import { resizeMultipleElements } from "@excalidraw/element/resizeElements";
|
import { resizeMultipleElements } from "@excalidraw/element/resizeElements";
|
||||||
import {
|
import {
|
||||||
isArrowElement,
|
isArrowElement,
|
||||||
isElbowArrow,
|
isBindableElement,
|
||||||
isLinearElement,
|
isBindingElement,
|
||||||
} from "@excalidraw/element/typeChecks";
|
} from "@excalidraw/element/typeChecks";
|
||||||
import { updateFrameMembershipOfSelectedElements } from "@excalidraw/element/frame";
|
import { updateFrameMembershipOfSelectedElements } from "@excalidraw/element/frame";
|
||||||
import { CODES, KEYS, arrayToMap } from "@excalidraw/common";
|
import { CODES, KEYS, arrayToMap } from "@excalidraw/common";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawArrowElement,
|
ExcalidrawArrowElement,
|
||||||
ExcalidrawElbowArrowElement,
|
ExcalidrawBindableElement,
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
NonDeleted,
|
NonDeleted,
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
|
@ -160,52 +160,54 @@ const flipElements = (
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
bindOrUnbindLinearElements(
|
const selectedBindables = selectedElements.filter(
|
||||||
selectedElements.filter(isLinearElement),
|
(e): e is ExcalidrawBindableElement => isBindableElement(e),
|
||||||
elementsMap,
|
|
||||||
app.scene.getNonDeletedElements(),
|
|
||||||
app.scene,
|
|
||||||
isBindingEnabled(appState),
|
|
||||||
[],
|
|
||||||
appState.zoom,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// flipping arrow elements (and potentially other) makes the selection group
|
|
||||||
// "move" across the canvas because of how arrows can bump against the "wall"
|
|
||||||
// of the selection, so we need to center the group back to the original
|
|
||||||
// position so that repeated flips don't accumulate the offset
|
|
||||||
|
|
||||||
const { elbowArrows, otherElements } = selectedElements.reduce(
|
|
||||||
(
|
|
||||||
acc: {
|
|
||||||
elbowArrows: ExcalidrawElbowArrowElement[];
|
|
||||||
otherElements: ExcalidrawElement[];
|
|
||||||
},
|
|
||||||
element,
|
|
||||||
) =>
|
|
||||||
isElbowArrow(element)
|
|
||||||
? { ...acc, elbowArrows: acc.elbowArrows.concat(element) }
|
|
||||||
: { ...acc, otherElements: acc.otherElements.concat(element) },
|
|
||||||
{ elbowArrows: [], otherElements: [] },
|
|
||||||
);
|
|
||||||
|
|
||||||
const { midX: newMidX, midY: newMidY } =
|
const { midX: newMidX, midY: newMidY } =
|
||||||
getCommonBoundingBox(selectedElements);
|
getCommonBoundingBox(selectedElements);
|
||||||
const [diffX, diffY] = [midX - newMidX, midY - newMidY];
|
const [diffX, diffY] = [midX - newMidX, midY - newMidY];
|
||||||
otherElements.forEach((element) =>
|
|
||||||
|
selectedElements.forEach((element) => {
|
||||||
|
fixBindings(element, selectedBindables, app, elementsMap);
|
||||||
|
|
||||||
mutateElement(element, {
|
mutateElement(element, {
|
||||||
x: element.x + diffX,
|
x: element.x + diffX,
|
||||||
y: element.y + diffY,
|
y: element.y + diffY,
|
||||||
}),
|
});
|
||||||
);
|
});
|
||||||
elbowArrows.forEach((element) =>
|
|
||||||
mutateElement(element, {
|
|
||||||
x: element.x + diffX,
|
|
||||||
y: element.y + diffY,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
return selectedElements;
|
return selectedElements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// BEHAVIOR: If you flip a binding element along with its bound elements,
|
||||||
|
// the binding should be preserved. If your selected elements doesn't contain
|
||||||
|
// the bound element(s), then remove the binding. Also do not "magically"
|
||||||
|
// re-bind a binable just because the arrow endpoint is flipped into the
|
||||||
|
// binding range. Rationale being the consistency with the fact that arrows
|
||||||
|
// don't bind when the arrow is moved into the binding range by its shaft.
|
||||||
|
const fixBindings = (
|
||||||
|
element: ExcalidrawElement,
|
||||||
|
selectedBindables: ExcalidrawBindableElement[],
|
||||||
|
app: AppClassProperties,
|
||||||
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
|
) => {
|
||||||
|
if (isBindingElement(element)) {
|
||||||
|
let start = null;
|
||||||
|
let end = null;
|
||||||
|
|
||||||
|
if (isBindingEnabled(app.state)) {
|
||||||
|
start = element.startBinding
|
||||||
|
? selectedBindables.find(
|
||||||
|
(e) => element.startBinding!.elementId === e.id,
|
||||||
|
) ?? null
|
||||||
|
: null;
|
||||||
|
end = element.endBinding
|
||||||
|
? selectedBindables.find(
|
||||||
|
(e) => element.endBinding!.elementId === e.id,
|
||||||
|
) ?? null
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindOrUnbindLinearElement(element, start, end, elementsMap, app.scene);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue