mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Position revert
This commit is contained in:
parent
9a599cfc05
commit
5cc5c626df
4 changed files with 87 additions and 45 deletions
|
@ -18,10 +18,7 @@ import type { AppState } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import type { Degrees, Radians } from "@excalidraw/math";
|
import type { Degrees, Radians } from "@excalidraw/math";
|
||||||
|
|
||||||
import type {
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
ExcalidrawElement,
|
|
||||||
NonDeletedExcalidrawElement,
|
|
||||||
} from "@excalidraw/element/types";
|
|
||||||
|
|
||||||
import { angleIcon } from "../icons";
|
import { angleIcon } from "../icons";
|
||||||
|
|
||||||
|
@ -75,14 +72,6 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
|
||||||
mutateElement(boundTextElement, { angle: nextAngle });
|
mutateElement(boundTextElement, { angle: nextAngle });
|
||||||
}
|
}
|
||||||
|
|
||||||
setAppState({
|
|
||||||
suggestedBindings: getSuggestedBindingsForArrows(
|
|
||||||
[latestElement] as NonDeletedExcalidrawElement[],
|
|
||||||
elementsMap,
|
|
||||||
originalAppState.zoom,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +103,7 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
|
||||||
|
|
||||||
setAppState({
|
setAppState({
|
||||||
suggestedBindings: getSuggestedBindingsForArrows(
|
suggestedBindings: getSuggestedBindingsForArrows(
|
||||||
[latestElement] as NonDeletedExcalidrawElement[],
|
[latestElement],
|
||||||
elementsMap,
|
elementsMap,
|
||||||
originalAppState.zoom,
|
originalAppState.zoom,
|
||||||
),
|
),
|
||||||
|
@ -122,7 +111,7 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinished: DragFinishedCallbackType = ({
|
const handleFinished: DragFinishedCallbackType<AngleProps["property"]> = ({
|
||||||
originalElements,
|
originalElements,
|
||||||
originalAppState,
|
originalAppState,
|
||||||
scene,
|
scene,
|
||||||
|
@ -137,25 +126,15 @@ const handleFinished: DragFinishedCallbackType = ({
|
||||||
|
|
||||||
if (latestElement) {
|
if (latestElement) {
|
||||||
updateBindings(latestElement, elementsMap, originalAppState.zoom, () => {
|
updateBindings(latestElement, elementsMap, originalAppState.zoom, () => {
|
||||||
const revertAngle = (latestElement.angle -
|
const change = degreesToRadians(accumulatedChange as Degrees);
|
||||||
degreesToRadians(accumulatedChange as Degrees)) as Radians;
|
|
||||||
|
|
||||||
mutateElement(latestElement, {
|
mutateElement(latestElement, {
|
||||||
angle: revertAngle,
|
angle: (latestElement.angle - change) as Radians,
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const boundTextElement = getBoundTextElement(
|
setAppState({
|
||||||
latestElement,
|
suggestedBindings: [],
|
||||||
elementsMap,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (boundTextElement && !isArrowElement(latestElement)) {
|
|
||||||
mutateElement(boundTextElement, { angle: revertAngle });
|
|
||||||
}
|
|
||||||
|
|
||||||
setAppState({
|
|
||||||
suggestedBindings: [],
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,14 @@ export type DragInputCallbackType<
|
||||||
setAppState: React.Component<any, AppState>["setState"];
|
setAppState: React.Component<any, AppState>["setState"];
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
export type DragFinishedCallbackType<E = ExcalidrawElement> = (props: {
|
export type DragFinishedCallbackType<
|
||||||
|
P extends StatsInputProperty,
|
||||||
|
E = ExcalidrawElement,
|
||||||
|
> = (props: {
|
||||||
originalElements: readonly E[];
|
originalElements: readonly E[];
|
||||||
originalElementsMap: ElementsMap;
|
originalElementsMap: ElementsMap;
|
||||||
scene: Scene;
|
scene: Scene;
|
||||||
|
property: P;
|
||||||
originalAppState: AppState;
|
originalAppState: AppState;
|
||||||
accumulatedChange: number;
|
accumulatedChange: number;
|
||||||
setAppState: React.Component<any, AppState>["setState"];
|
setAppState: React.Component<any, AppState>["setState"];
|
||||||
|
@ -57,7 +61,7 @@ interface StatsDragInputProps<
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
shouldKeepAspectRatio?: boolean;
|
shouldKeepAspectRatio?: boolean;
|
||||||
dragInputCallback: DragInputCallbackType<T, E>;
|
dragInputCallback: DragInputCallbackType<T, E>;
|
||||||
dragFinishedCallback?: DragFinishedCallbackType<E>;
|
dragFinishedCallback?: DragFinishedCallbackType<T, E>;
|
||||||
property: T;
|
property: T;
|
||||||
scene: Scene;
|
scene: Scene;
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
|
@ -136,6 +140,7 @@ const StatsDragInput = <
|
||||||
// reason: idempotent to avoid unnecessary
|
// reason: idempotent to avoid unnecessary
|
||||||
if (isNaN(original) || Math.abs(rounded - original) >= SMALLEST_DELTA) {
|
if (isNaN(original) || Math.abs(rounded - original) >= SMALLEST_DELTA) {
|
||||||
stateRef.current.lastUpdatedValue = updatedValue;
|
stateRef.current.lastUpdatedValue = updatedValue;
|
||||||
|
const originalElementsMap = app.scene.getNonDeletedElementsMap();
|
||||||
dragInputCallback({
|
dragInputCallback({
|
||||||
accumulatedChange: 0,
|
accumulatedChange: 0,
|
||||||
instantChange: 0,
|
instantChange: 0,
|
||||||
|
@ -150,6 +155,15 @@ const StatsDragInput = <
|
||||||
setInputValue: (value) => setInputValue(String(value)),
|
setInputValue: (value) => setInputValue(String(value)),
|
||||||
setAppState,
|
setAppState,
|
||||||
});
|
});
|
||||||
|
dragFinishedCallback?.({
|
||||||
|
originalElements: elements,
|
||||||
|
originalElementsMap,
|
||||||
|
scene,
|
||||||
|
originalAppState: appState,
|
||||||
|
accumulatedChange: rounded,
|
||||||
|
property,
|
||||||
|
setAppState,
|
||||||
|
});
|
||||||
app.syncActionResult({
|
app.syncActionResult({
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
});
|
});
|
||||||
|
@ -303,6 +317,7 @@ const StatsDragInput = <
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
scene,
|
scene,
|
||||||
originalAppState,
|
originalAppState,
|
||||||
|
property,
|
||||||
accumulatedChange,
|
accumulatedChange,
|
||||||
setAppState,
|
setAppState,
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,12 +7,17 @@ import {
|
||||||
import { mutateElement } from "@excalidraw/element/mutateElement";
|
import { mutateElement } from "@excalidraw/element/mutateElement";
|
||||||
import { isImageElement } from "@excalidraw/element/typeChecks";
|
import { isImageElement } from "@excalidraw/element/typeChecks";
|
||||||
|
|
||||||
|
import { getSuggestedBindingsForArrows } from "@excalidraw/element/binding";
|
||||||
|
|
||||||
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import StatsDragInput from "./DragInput";
|
import StatsDragInput from "./DragInput";
|
||||||
import { getStepSizedValue, moveElement } from "./utils";
|
import { getStepSizedValue, moveElement, updateBindings } from "./utils";
|
||||||
|
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type {
|
||||||
|
DragFinishedCallbackType,
|
||||||
|
DragInputCallbackType,
|
||||||
|
} from "./DragInput";
|
||||||
import type Scene from "../../scene/Scene";
|
import type Scene from "../../scene/Scene";
|
||||||
import type { AppState } from "../../types";
|
import type { AppState } from "../../types";
|
||||||
|
|
||||||
|
@ -36,6 +41,7 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
property,
|
property,
|
||||||
scene,
|
scene,
|
||||||
originalAppState,
|
originalAppState,
|
||||||
|
setAppState,
|
||||||
}) => {
|
}) => {
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const origElement = originalElements[0];
|
const origElement = originalElements[0];
|
||||||
|
@ -122,6 +128,14 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
crop: nextCrop,
|
crop: nextCrop,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setAppState({
|
||||||
|
suggestedBindings: getSuggestedBindingsForArrows(
|
||||||
|
[origElement],
|
||||||
|
elementsMap,
|
||||||
|
originalAppState.zoom,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +149,7 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
elementsMap,
|
elementsMap,
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,15 +181,51 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
|
||||||
elementsMap,
|
elementsMap,
|
||||||
originalElementsMap,
|
originalElementsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (origElement) {
|
||||||
|
const latestElement = elementsMap.get(origElement.id);
|
||||||
|
|
||||||
|
if (latestElement) {
|
||||||
|
setAppState({
|
||||||
|
suggestedBindings: getSuggestedBindingsForArrows(
|
||||||
|
[latestElement],
|
||||||
|
elementsMap,
|
||||||
|
originalAppState.zoom,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Position = ({
|
const handleFinished: DragFinishedCallbackType<"x" | "y"> = ({
|
||||||
property,
|
originalElements,
|
||||||
element,
|
originalAppState,
|
||||||
elementsMap,
|
|
||||||
scene,
|
scene,
|
||||||
appState,
|
accumulatedChange,
|
||||||
}: PositionProps) => {
|
property,
|
||||||
|
setAppState,
|
||||||
|
}) => {
|
||||||
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
|
const origElement = originalElements[0];
|
||||||
|
|
||||||
|
if (origElement) {
|
||||||
|
const latestElement = elementsMap.get(origElement.id);
|
||||||
|
|
||||||
|
if (latestElement) {
|
||||||
|
updateBindings(latestElement, elementsMap, originalAppState.zoom, () => {
|
||||||
|
mutateElement(latestElement, {
|
||||||
|
[property]: latestElement[property] - accumulatedChange,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setAppState({
|
||||||
|
suggestedBindings: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position = ({ property, element, scene, appState }: PositionProps) => {
|
||||||
const [topLeftX, topLeftY] = pointRotateRads(
|
const [topLeftX, topLeftY] = pointRotateRads(
|
||||||
pointFrom(element.x, element.y),
|
pointFrom(element.x, element.y),
|
||||||
pointFrom(element.x + element.width / 2, element.y + element.height / 2),
|
pointFrom(element.x + element.width / 2, element.y + element.height / 2),
|
||||||
|
@ -202,6 +253,7 @@ const Position = ({
|
||||||
label={property === "x" ? "X" : "Y"}
|
label={property === "x" ? "X" : "Y"}
|
||||||
elements={[element]}
|
elements={[element]}
|
||||||
dragInputCallback={handlePositionChange}
|
dragInputCallback={handlePositionChange}
|
||||||
|
dragFinishedCallback={handleFinished}
|
||||||
scene={scene}
|
scene={scene}
|
||||||
value={value}
|
value={value}
|
||||||
property={property}
|
property={property}
|
||||||
|
|
|
@ -204,7 +204,7 @@ export const updateBindings = (
|
||||||
latestElement: ExcalidrawElement,
|
latestElement: ExcalidrawElement,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
zoom?: AppState["zoom"],
|
zoom?: AppState["zoom"],
|
||||||
remainedBound?: () => void,
|
bindingElementKeptOriginalBinding?: () => void,
|
||||||
) => {
|
) => {
|
||||||
if (isBindingElement(latestElement)) {
|
if (isBindingElement(latestElement)) {
|
||||||
const [start, end] = getOriginalBindingsIfStillCloseToArrowEnds(
|
const [start, end] = getOriginalBindingsIfStillCloseToArrowEnds(
|
||||||
|
@ -217,7 +217,7 @@ export const updateBindings = (
|
||||||
(latestElement.startBinding && start) ||
|
(latestElement.startBinding && start) ||
|
||||||
(latestElement.endBinding && end)
|
(latestElement.endBinding && end)
|
||||||
) {
|
) {
|
||||||
remainedBound?.();
|
bindingElementKeptOriginalBinding?.();
|
||||||
} else {
|
} else {
|
||||||
if (latestElement.startBinding && !start) {
|
if (latestElement.startBinding && !start) {
|
||||||
unbindLinearElement(latestElement, "start");
|
unbindLinearElement(latestElement, "start");
|
||||||
|
@ -227,9 +227,5 @@ export const updateBindings = (
|
||||||
unbindLinearElement(latestElement, "end");
|
unbindLinearElement(latestElement, "end");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// else if (end) {
|
|
||||||
// updateBoundElements(end, elementsMap);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue