|
@@ -15,6 +15,7 @@ import {
|
|
ExcalidrawElement,
|
|
ExcalidrawElement,
|
|
ExcalidrawTextElementWithContainer,
|
|
ExcalidrawTextElementWithContainer,
|
|
ExcalidrawImageElement,
|
|
ExcalidrawImageElement,
|
|
|
|
+ ElementsMap,
|
|
} from "./types";
|
|
} from "./types";
|
|
import type { Mutable } from "../utility-types";
|
|
import type { Mutable } from "../utility-types";
|
|
import {
|
|
import {
|
|
@@ -41,7 +42,7 @@ import {
|
|
MaybeTransformHandleType,
|
|
MaybeTransformHandleType,
|
|
TransformHandleDirection,
|
|
TransformHandleDirection,
|
|
} from "./transformHandles";
|
|
} from "./transformHandles";
|
|
-import { AppState, Point, PointerDownState } from "../types";
|
|
|
|
|
|
+import { Point, PointerDownState } from "../types";
|
|
import Scene from "../scene/Scene";
|
|
import Scene from "../scene/Scene";
|
|
import {
|
|
import {
|
|
getApproxMinLineWidth,
|
|
getApproxMinLineWidth,
|
|
@@ -68,10 +69,10 @@ export const normalizeAngle = (angle: number): number => {
|
|
|
|
|
|
// Returns true when transform (resizing/rotation) happened
|
|
// Returns true when transform (resizing/rotation) happened
|
|
export const transformElements = (
|
|
export const transformElements = (
|
|
- pointerDownState: PointerDownState,
|
|
|
|
|
|
+ originalElements: PointerDownState["originalElements"],
|
|
transformHandleType: MaybeTransformHandleType,
|
|
transformHandleType: MaybeTransformHandleType,
|
|
selectedElements: readonly NonDeletedExcalidrawElement[],
|
|
selectedElements: readonly NonDeletedExcalidrawElement[],
|
|
- resizeArrowDirection: "origin" | "end",
|
|
|
|
|
|
+ elementsMap: ElementsMap,
|
|
shouldRotateWithDiscreteAngle: boolean,
|
|
shouldRotateWithDiscreteAngle: boolean,
|
|
shouldResizeFromCenter: boolean,
|
|
shouldResizeFromCenter: boolean,
|
|
shouldMaintainAspectRatio: boolean,
|
|
shouldMaintainAspectRatio: boolean,
|
|
@@ -79,7 +80,6 @@ export const transformElements = (
|
|
pointerY: number,
|
|
pointerY: number,
|
|
centerX: number,
|
|
centerX: number,
|
|
centerY: number,
|
|
centerY: number,
|
|
- appState: AppState,
|
|
|
|
) => {
|
|
) => {
|
|
if (selectedElements.length === 1) {
|
|
if (selectedElements.length === 1) {
|
|
const [element] = selectedElements;
|
|
const [element] = selectedElements;
|
|
@@ -89,7 +89,6 @@ export const transformElements = (
|
|
pointerX,
|
|
pointerX,
|
|
pointerY,
|
|
pointerY,
|
|
shouldRotateWithDiscreteAngle,
|
|
shouldRotateWithDiscreteAngle,
|
|
- pointerDownState.originalElements,
|
|
|
|
);
|
|
);
|
|
updateBoundElements(element);
|
|
updateBoundElements(element);
|
|
} else if (
|
|
} else if (
|
|
@@ -101,6 +100,7 @@ export const transformElements = (
|
|
) {
|
|
) {
|
|
resizeSingleTextElement(
|
|
resizeSingleTextElement(
|
|
element,
|
|
element,
|
|
|
|
+ elementsMap,
|
|
transformHandleType,
|
|
transformHandleType,
|
|
shouldResizeFromCenter,
|
|
shouldResizeFromCenter,
|
|
pointerX,
|
|
pointerX,
|
|
@@ -109,9 +109,10 @@ export const transformElements = (
|
|
updateBoundElements(element);
|
|
updateBoundElements(element);
|
|
} else if (transformHandleType) {
|
|
} else if (transformHandleType) {
|
|
resizeSingleElement(
|
|
resizeSingleElement(
|
|
- pointerDownState.originalElements,
|
|
|
|
|
|
+ originalElements,
|
|
shouldMaintainAspectRatio,
|
|
shouldMaintainAspectRatio,
|
|
element,
|
|
element,
|
|
|
|
+ elementsMap,
|
|
transformHandleType,
|
|
transformHandleType,
|
|
shouldResizeFromCenter,
|
|
shouldResizeFromCenter,
|
|
pointerX,
|
|
pointerX,
|
|
@@ -123,7 +124,7 @@ export const transformElements = (
|
|
} else if (selectedElements.length > 1) {
|
|
} else if (selectedElements.length > 1) {
|
|
if (transformHandleType === "rotation") {
|
|
if (transformHandleType === "rotation") {
|
|
rotateMultipleElements(
|
|
rotateMultipleElements(
|
|
- pointerDownState,
|
|
|
|
|
|
+ originalElements,
|
|
selectedElements,
|
|
selectedElements,
|
|
pointerX,
|
|
pointerX,
|
|
pointerY,
|
|
pointerY,
|
|
@@ -139,8 +140,9 @@ export const transformElements = (
|
|
transformHandleType === "se"
|
|
transformHandleType === "se"
|
|
) {
|
|
) {
|
|
resizeMultipleElements(
|
|
resizeMultipleElements(
|
|
- pointerDownState,
|
|
|
|
|
|
+ originalElements,
|
|
selectedElements,
|
|
selectedElements,
|
|
|
|
+ elementsMap,
|
|
transformHandleType,
|
|
transformHandleType,
|
|
shouldResizeFromCenter,
|
|
shouldResizeFromCenter,
|
|
pointerX,
|
|
pointerX,
|
|
@@ -157,7 +159,6 @@ const rotateSingleElement = (
|
|
pointerX: number,
|
|
pointerX: number,
|
|
pointerY: number,
|
|
pointerY: number,
|
|
shouldRotateWithDiscreteAngle: boolean,
|
|
shouldRotateWithDiscreteAngle: boolean,
|
|
- originalElements: Map<string, NonDeleted<ExcalidrawElement>>,
|
|
|
|
) => {
|
|
) => {
|
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
const cx = (x1 + x2) / 2;
|
|
const cx = (x1 + x2) / 2;
|
|
@@ -207,6 +208,7 @@ const rescalePointsInElement = (
|
|
|
|
|
|
const measureFontSizeFromWidth = (
|
|
const measureFontSizeFromWidth = (
|
|
element: NonDeleted<ExcalidrawTextElement>,
|
|
element: NonDeleted<ExcalidrawTextElement>,
|
|
|
|
+ elementsMap: ElementsMap,
|
|
nextWidth: number,
|
|
nextWidth: number,
|
|
nextHeight: number,
|
|
nextHeight: number,
|
|
): { size: number; baseline: number } | null => {
|
|
): { size: number; baseline: number } | null => {
|
|
@@ -215,7 +217,7 @@ const measureFontSizeFromWidth = (
|
|
|
|
|
|
const hasContainer = isBoundToContainer(element);
|
|
const hasContainer = isBoundToContainer(element);
|
|
if (hasContainer) {
|
|
if (hasContainer) {
|
|
- const container = getContainerElement(element);
|
|
|
|
|
|
+ const container = getContainerElement(element, elementsMap);
|
|
if (container) {
|
|
if (container) {
|
|
width = getBoundTextMaxWidth(container);
|
|
width = getBoundTextMaxWidth(container);
|
|
}
|
|
}
|
|
@@ -257,6 +259,7 @@ const getSidesForTransformHandle = (
|
|
|
|
|
|
const resizeSingleTextElement = (
|
|
const resizeSingleTextElement = (
|
|
element: NonDeleted<ExcalidrawTextElement>,
|
|
element: NonDeleted<ExcalidrawTextElement>,
|
|
|
|
+ elementsMap: ElementsMap,
|
|
transformHandleType: "nw" | "ne" | "sw" | "se",
|
|
transformHandleType: "nw" | "ne" | "sw" | "se",
|
|
shouldResizeFromCenter: boolean,
|
|
shouldResizeFromCenter: boolean,
|
|
pointerX: number,
|
|
pointerX: number,
|
|
@@ -303,7 +306,12 @@ const resizeSingleTextElement = (
|
|
if (scale > 0) {
|
|
if (scale > 0) {
|
|
const nextWidth = element.width * scale;
|
|
const nextWidth = element.width * scale;
|
|
const nextHeight = element.height * scale;
|
|
const nextHeight = element.height * scale;
|
|
- const metrics = measureFontSizeFromWidth(element, nextWidth, nextHeight);
|
|
|
|
|
|
+ const metrics = measureFontSizeFromWidth(
|
|
|
|
+ element,
|
|
|
|
+ elementsMap,
|
|
|
|
+ nextWidth,
|
|
|
|
+ nextHeight,
|
|
|
|
+ );
|
|
if (metrics === null) {
|
|
if (metrics === null) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -342,6 +350,7 @@ export const resizeSingleElement = (
|
|
originalElements: PointerDownState["originalElements"],
|
|
originalElements: PointerDownState["originalElements"],
|
|
shouldMaintainAspectRatio: boolean,
|
|
shouldMaintainAspectRatio: boolean,
|
|
element: NonDeletedExcalidrawElement,
|
|
element: NonDeletedExcalidrawElement,
|
|
|
|
+ elementsMap: ElementsMap,
|
|
transformHandleDirection: TransformHandleDirection,
|
|
transformHandleDirection: TransformHandleDirection,
|
|
shouldResizeFromCenter: boolean,
|
|
shouldResizeFromCenter: boolean,
|
|
pointerX: number,
|
|
pointerX: number,
|
|
@@ -448,6 +457,7 @@ export const resizeSingleElement = (
|
|
|
|
|
|
const nextFont = measureFontSizeFromWidth(
|
|
const nextFont = measureFontSizeFromWidth(
|
|
boundTextElement,
|
|
boundTextElement,
|
|
|
|
+ elementsMap,
|
|
getBoundTextMaxWidth(updatedElement),
|
|
getBoundTextMaxWidth(updatedElement),
|
|
getBoundTextMaxHeight(updatedElement, boundTextElement),
|
|
getBoundTextMaxHeight(updatedElement, boundTextElement),
|
|
);
|
|
);
|
|
@@ -637,8 +647,9 @@ export const resizeSingleElement = (
|
|
};
|
|
};
|
|
|
|
|
|
export const resizeMultipleElements = (
|
|
export const resizeMultipleElements = (
|
|
- pointerDownState: PointerDownState,
|
|
|
|
|
|
+ originalElements: PointerDownState["originalElements"],
|
|
selectedElements: readonly NonDeletedExcalidrawElement[],
|
|
selectedElements: readonly NonDeletedExcalidrawElement[],
|
|
|
|
+ elementsMap: ElementsMap,
|
|
transformHandleType: "nw" | "ne" | "sw" | "se",
|
|
transformHandleType: "nw" | "ne" | "sw" | "se",
|
|
shouldResizeFromCenter: boolean,
|
|
shouldResizeFromCenter: boolean,
|
|
pointerX: number,
|
|
pointerX: number,
|
|
@@ -658,7 +669,7 @@ export const resizeMultipleElements = (
|
|
}[],
|
|
}[],
|
|
element,
|
|
element,
|
|
) => {
|
|
) => {
|
|
- const origElement = pointerDownState.originalElements.get(element.id);
|
|
|
|
|
|
+ const origElement = originalElements.get(element.id);
|
|
if (origElement) {
|
|
if (origElement) {
|
|
acc.push({ orig: origElement, latest: element });
|
|
acc.push({ orig: origElement, latest: element });
|
|
}
|
|
}
|
|
@@ -679,7 +690,7 @@ export const resizeMultipleElements = (
|
|
if (!textId) {
|
|
if (!textId) {
|
|
return acc;
|
|
return acc;
|
|
}
|
|
}
|
|
- const text = pointerDownState.originalElements.get(textId) ?? null;
|
|
|
|
|
|
+ const text = originalElements.get(textId) ?? null;
|
|
if (!isBoundToContainer(text)) {
|
|
if (!isBoundToContainer(text)) {
|
|
return acc;
|
|
return acc;
|
|
}
|
|
}
|
|
@@ -825,7 +836,12 @@ export const resizeMultipleElements = (
|
|
}
|
|
}
|
|
|
|
|
|
if (isTextElement(orig)) {
|
|
if (isTextElement(orig)) {
|
|
- const metrics = measureFontSizeFromWidth(orig, width, height);
|
|
|
|
|
|
+ const metrics = measureFontSizeFromWidth(
|
|
|
|
+ orig,
|
|
|
|
+ elementsMap,
|
|
|
|
+ width,
|
|
|
|
+ height,
|
|
|
|
+ );
|
|
if (!metrics) {
|
|
if (!metrics) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -833,7 +849,7 @@ export const resizeMultipleElements = (
|
|
update.baseline = metrics.baseline;
|
|
update.baseline = metrics.baseline;
|
|
}
|
|
}
|
|
|
|
|
|
- const boundTextElement = pointerDownState.originalElements.get(
|
|
|
|
|
|
+ const boundTextElement = originalElements.get(
|
|
getBoundTextElementId(orig) ?? "",
|
|
getBoundTextElementId(orig) ?? "",
|
|
) as ExcalidrawTextElementWithContainer | undefined;
|
|
) as ExcalidrawTextElementWithContainer | undefined;
|
|
|
|
|
|
@@ -884,7 +900,7 @@ export const resizeMultipleElements = (
|
|
};
|
|
};
|
|
|
|
|
|
const rotateMultipleElements = (
|
|
const rotateMultipleElements = (
|
|
- pointerDownState: PointerDownState,
|
|
|
|
|
|
+ originalElements: PointerDownState["originalElements"],
|
|
elements: readonly NonDeletedExcalidrawElement[],
|
|
elements: readonly NonDeletedExcalidrawElement[],
|
|
pointerX: number,
|
|
pointerX: number,
|
|
pointerY: number,
|
|
pointerY: number,
|
|
@@ -906,8 +922,7 @@ const rotateMultipleElements = (
|
|
const cx = (x1 + x2) / 2;
|
|
const cx = (x1 + x2) / 2;
|
|
const cy = (y1 + y2) / 2;
|
|
const cy = (y1 + y2) / 2;
|
|
const origAngle =
|
|
const origAngle =
|
|
- pointerDownState.originalElements.get(element.id)?.angle ??
|
|
|
|
- element.angle;
|
|
|
|
|
|
+ originalElements.get(element.id)?.angle ?? element.angle;
|
|
const [rotatedCX, rotatedCY] = rotate(
|
|
const [rotatedCX, rotatedCY] = rotate(
|
|
cx,
|
|
cx,
|
|
cy,
|
|
cy,
|