handle bound texts
This commit is contained in:
parent
be65ac7f22
commit
c68c2be44c
@ -1,5 +1,7 @@
|
|||||||
import { mutateElement } from "../../element/mutateElement";
|
import { mutateElement } from "../../element/mutateElement";
|
||||||
import type { ExcalidrawElement } from "../../element/types";
|
import { getBoundTextElement } from "../../element/textElement";
|
||||||
|
import { isArrowElement } from "../../element/typeChecks";
|
||||||
|
import type { ElementsMap, ExcalidrawElement } from "../../element/types";
|
||||||
import { degreeToRadian, radianToDegree } from "../../math";
|
import { degreeToRadian, radianToDegree } from "../../math";
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
@ -7,19 +9,18 @@ import { getStepSizedValue, isPropertyEditable } from "./utils";
|
|||||||
|
|
||||||
interface AngleProps {
|
interface AngleProps {
|
||||||
element: ExcalidrawElement;
|
element: ExcalidrawElement;
|
||||||
|
elementsMap: ElementsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STEP_SIZE = 15;
|
const STEP_SIZE = 15;
|
||||||
|
|
||||||
const Angle = ({ element }: AngleProps) => {
|
const Angle = ({ element, elementsMap }: AngleProps) => {
|
||||||
const handleDegreeChange: DragInputCallbackType = (
|
const handleDegreeChange: DragInputCallbackType = ({
|
||||||
accumulatedChange,
|
accumulatedChange,
|
||||||
instantChange,
|
|
||||||
stateAtStart,
|
stateAtStart,
|
||||||
shouldKeepAspectRatio,
|
|
||||||
shouldChangeByStepSize,
|
shouldChangeByStepSize,
|
||||||
nextValue,
|
nextValue,
|
||||||
) => {
|
}) => {
|
||||||
const _stateAtStart = stateAtStart[0];
|
const _stateAtStart = stateAtStart[0];
|
||||||
if (_stateAtStart) {
|
if (_stateAtStart) {
|
||||||
if (nextValue !== undefined) {
|
if (nextValue !== undefined) {
|
||||||
@ -27,6 +28,12 @@ const Angle = ({ element }: AngleProps) => {
|
|||||||
mutateElement(element, {
|
mutateElement(element, {
|
||||||
angle: nextAngle,
|
angle: nextAngle,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const boundTextElement = getBoundTextElement(element, elementsMap);
|
||||||
|
if (boundTextElement && !isArrowElement(element)) {
|
||||||
|
mutateElement(boundTextElement, { angle: nextAngle });
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,13 +45,19 @@ const Angle = ({ element }: AngleProps) => {
|
|||||||
nextAngleInDegrees = getStepSizedValue(nextAngleInDegrees, STEP_SIZE);
|
nextAngleInDegrees = getStepSizedValue(nextAngleInDegrees, STEP_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextAngleInDegrees =
|
||||||
|
nextAngleInDegrees < 0 ? nextAngleInDegrees + 360 : nextAngleInDegrees;
|
||||||
|
|
||||||
|
const nextAngle = degreeToRadian(nextAngleInDegrees);
|
||||||
|
|
||||||
mutateElement(element, {
|
mutateElement(element, {
|
||||||
angle: degreeToRadian(
|
angle: nextAngle,
|
||||||
nextAngleInDegrees < 0
|
|
||||||
? nextAngleInDegrees + 360
|
|
||||||
: nextAngleInDegrees,
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const boundTextElement = getBoundTextElement(element, elementsMap);
|
||||||
|
if (boundTextElement && !isArrowElement(element)) {
|
||||||
|
mutateElement(boundTextElement, { angle: nextAngle });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,13 +1,26 @@
|
|||||||
import type { ExcalidrawElement } from "../../element/types";
|
import type { ElementsMap, ExcalidrawElement } from "../../element/types";
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import { getStepSizedValue, isPropertyEditable } from "./utils";
|
import { getStepSizedValue, isPropertyEditable } from "./utils";
|
||||||
import { mutateElement } from "../../element/mutateElement";
|
import { mutateElement } from "../../element/mutateElement";
|
||||||
import { rescalePointsInElement } from "../../element/resizeElements";
|
import {
|
||||||
|
measureFontSizeFromWidth,
|
||||||
|
rescalePointsInElement,
|
||||||
|
} from "../../element/resizeElements";
|
||||||
|
import {
|
||||||
|
getApproxMinLineHeight,
|
||||||
|
getApproxMinLineWidth,
|
||||||
|
getBoundTextElement,
|
||||||
|
getBoundTextMaxWidth,
|
||||||
|
handleBindTextResize,
|
||||||
|
} from "../../element/textElement";
|
||||||
|
import { getFontString } from "../../utils";
|
||||||
|
import { updateBoundElements } from "../../element/binding";
|
||||||
|
|
||||||
interface DimensionDragInputProps {
|
interface DimensionDragInputProps {
|
||||||
property: "width" | "height";
|
property: "width" | "height";
|
||||||
element: ExcalidrawElement;
|
element: ExcalidrawElement;
|
||||||
|
elementsMap: ElementsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STEP_SIZE = 10;
|
const STEP_SIZE = 10;
|
||||||
@ -51,13 +64,16 @@ export const newOrigin = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getResizedUpdates = (
|
const resizeElement = (
|
||||||
nextWidth: number,
|
nextWidth: number,
|
||||||
nextHeight: number,
|
nextHeight: number,
|
||||||
|
keepAspectRatio: boolean,
|
||||||
latestState: ExcalidrawElement,
|
latestState: ExcalidrawElement,
|
||||||
stateAtStart: ExcalidrawElement,
|
stateAtStart: ExcalidrawElement,
|
||||||
|
elementsMap: ElementsMap,
|
||||||
|
originalElementsMap: Map<string, ExcalidrawElement>,
|
||||||
) => {
|
) => {
|
||||||
return {
|
mutateElement(latestState, {
|
||||||
...newOrigin(
|
...newOrigin(
|
||||||
latestState.x,
|
latestState.x,
|
||||||
latestState.y,
|
latestState.y,
|
||||||
@ -70,18 +86,72 @@ const getResizedUpdates = (
|
|||||||
width: nextWidth,
|
width: nextWidth,
|
||||||
height: nextHeight,
|
height: nextHeight,
|
||||||
...rescalePointsInElement(stateAtStart, nextWidth, nextHeight, true),
|
...rescalePointsInElement(stateAtStart, nextWidth, nextHeight, true),
|
||||||
|
});
|
||||||
|
|
||||||
|
let boundTextFont: { fontSize?: number } = {};
|
||||||
|
const boundTextElement = getBoundTextElement(latestState, elementsMap);
|
||||||
|
|
||||||
|
if (boundTextElement) {
|
||||||
|
boundTextFont = {
|
||||||
|
fontSize: boundTextElement.fontSize,
|
||||||
};
|
};
|
||||||
|
if (keepAspectRatio) {
|
||||||
|
const updatedElement = {
|
||||||
|
...latestState,
|
||||||
|
width: nextWidth,
|
||||||
|
height: nextHeight,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DimensionDragInput = ({ property, element }: DimensionDragInputProps) => {
|
const nextFont = measureFontSizeFromWidth(
|
||||||
const handleDimensionChange: DragInputCallbackType = (
|
boundTextElement,
|
||||||
|
elementsMap,
|
||||||
|
getBoundTextMaxWidth(updatedElement, boundTextElement),
|
||||||
|
);
|
||||||
|
boundTextFont = {
|
||||||
|
fontSize: nextFont?.size ?? boundTextElement.fontSize,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const minWidth = getApproxMinLineWidth(
|
||||||
|
getFontString(boundTextElement),
|
||||||
|
boundTextElement.lineHeight,
|
||||||
|
);
|
||||||
|
const minHeight = getApproxMinLineHeight(
|
||||||
|
boundTextElement.fontSize,
|
||||||
|
boundTextElement.lineHeight,
|
||||||
|
);
|
||||||
|
nextWidth = Math.max(nextWidth, minWidth);
|
||||||
|
nextHeight = Math.max(nextHeight, minHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBoundElements(latestState, elementsMap, {
|
||||||
|
newSize: {
|
||||||
|
width: nextWidth,
|
||||||
|
height: nextHeight,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (boundTextElement && boundTextFont) {
|
||||||
|
mutateElement(boundTextElement, {
|
||||||
|
fontSize: boundTextFont.fontSize,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
handleBindTextResize(latestState, elementsMap, "e", keepAspectRatio);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DimensionDragInput = ({
|
||||||
|
property,
|
||||||
|
element,
|
||||||
|
elementsMap,
|
||||||
|
}: DimensionDragInputProps) => {
|
||||||
|
const handleDimensionChange: DragInputCallbackType = ({
|
||||||
accumulatedChange,
|
accumulatedChange,
|
||||||
instantChange,
|
|
||||||
stateAtStart,
|
stateAtStart,
|
||||||
|
originalElementsMap,
|
||||||
shouldKeepAspectRatio,
|
shouldKeepAspectRatio,
|
||||||
shouldChangeByStepSize,
|
shouldChangeByStepSize,
|
||||||
nextValue,
|
nextValue,
|
||||||
) => {
|
}) => {
|
||||||
const _stateAtStart = stateAtStart[0];
|
const _stateAtStart = stateAtStart[0];
|
||||||
if (_stateAtStart) {
|
if (_stateAtStart) {
|
||||||
const keepAspectRatio =
|
const keepAspectRatio =
|
||||||
@ -106,10 +176,16 @@ const DimensionDragInput = ({ property, element }: DimensionDragInputProps) => {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
mutateElement(
|
resizeElement(
|
||||||
|
nextWidth,
|
||||||
|
nextHeight,
|
||||||
|
keepAspectRatio,
|
||||||
element,
|
element,
|
||||||
getResizedUpdates(nextWidth, nextHeight, element, _stateAtStart),
|
_stateAtStart,
|
||||||
|
elementsMap,
|
||||||
|
originalElementsMap,
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const changeInWidth = property === "width" ? accumulatedChange : 0;
|
const changeInWidth = property === "width" ? accumulatedChange : 0;
|
||||||
@ -141,9 +217,14 @@ const DimensionDragInput = ({ property, element }: DimensionDragInputProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutateElement(
|
resizeElement(
|
||||||
|
nextWidth,
|
||||||
|
nextHeight,
|
||||||
|
keepAspectRatio,
|
||||||
element,
|
element,
|
||||||
getResizedUpdates(nextWidth, nextHeight, element, _stateAtStart),
|
_stateAtStart,
|
||||||
|
elementsMap,
|
||||||
|
originalElementsMap,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2,21 +2,30 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|||||||
import throttle from "lodash.throttle";
|
import throttle from "lodash.throttle";
|
||||||
import { EVENT } from "../../constants";
|
import { EVENT } from "../../constants";
|
||||||
import { KEYS } from "../../keys";
|
import { KEYS } from "../../keys";
|
||||||
import type { ExcalidrawElement } from "../../element/types";
|
import type { ElementsMap, ExcalidrawElement } from "../../element/types";
|
||||||
import { deepCopyElement } from "../../element/newElement";
|
import { deepCopyElement } from "../../element/newElement";
|
||||||
|
|
||||||
import "./DragInput.scss";
|
import "./DragInput.scss";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { useApp } from "../App";
|
import { useApp } from "../App";
|
||||||
|
|
||||||
export type DragInputCallbackType = (
|
export type DragInputCallbackType = ({
|
||||||
accumulatedChange: number,
|
accumulatedChange,
|
||||||
instantChange: number,
|
instantChange,
|
||||||
stateAtStart: ExcalidrawElement[],
|
stateAtStart,
|
||||||
shouldKeepAspectRatio: boolean,
|
originalElementsMap,
|
||||||
shouldChangeByStepSize: boolean,
|
shouldKeepAspectRatio,
|
||||||
nextValue?: number,
|
shouldChangeByStepSize,
|
||||||
) => void;
|
nextValue,
|
||||||
|
}: {
|
||||||
|
accumulatedChange: number;
|
||||||
|
instantChange: number;
|
||||||
|
stateAtStart: ExcalidrawElement[];
|
||||||
|
originalElementsMap: ElementsMap;
|
||||||
|
shouldKeepAspectRatio: boolean;
|
||||||
|
shouldChangeByStepSize: boolean;
|
||||||
|
nextValue?: number;
|
||||||
|
}) => void;
|
||||||
|
|
||||||
interface StatsDragInputProps {
|
interface StatsDragInputProps {
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
@ -67,6 +76,8 @@ const StatsDragInput = ({
|
|||||||
} | null = null;
|
} | null = null;
|
||||||
|
|
||||||
let stateAtStart: ExcalidrawElement[] | null = null;
|
let stateAtStart: ExcalidrawElement[] | null = null;
|
||||||
|
let originalElementsMap: Map<string, ExcalidrawElement> | null =
|
||||||
|
null;
|
||||||
|
|
||||||
let accumulatedChange: number | null = null;
|
let accumulatedChange: number | null = null;
|
||||||
|
|
||||||
@ -79,6 +90,15 @@ const StatsDragInput = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!originalElementsMap) {
|
||||||
|
originalElementsMap = app.scene
|
||||||
|
.getNonDeletedElements()
|
||||||
|
.reduce((acc, element) => {
|
||||||
|
acc.set(element.id, deepCopyElement(element));
|
||||||
|
return acc;
|
||||||
|
}, new Map() as ElementsMap);
|
||||||
|
}
|
||||||
|
|
||||||
if (!accumulatedChange) {
|
if (!accumulatedChange) {
|
||||||
accumulatedChange = 0;
|
accumulatedChange = 0;
|
||||||
}
|
}
|
||||||
@ -87,13 +107,14 @@ const StatsDragInput = ({
|
|||||||
const instantChange = event.clientX - lastPointer.x;
|
const instantChange = event.clientX - lastPointer.x;
|
||||||
accumulatedChange += instantChange;
|
accumulatedChange += instantChange;
|
||||||
|
|
||||||
cbThrottled(
|
cbThrottled({
|
||||||
accumulatedChange,
|
accumulatedChange,
|
||||||
instantChange,
|
instantChange,
|
||||||
stateAtStart,
|
stateAtStart,
|
||||||
shouldKeepAspectRatio!!,
|
originalElementsMap,
|
||||||
event.shiftKey,
|
shouldKeepAspectRatio: shouldKeepAspectRatio!!,
|
||||||
);
|
shouldChangeByStepSize: event.shiftKey,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
lastPointer = {
|
lastPointer = {
|
||||||
@ -117,6 +138,7 @@ const StatsDragInput = ({
|
|||||||
lastPointer = null;
|
lastPointer = null;
|
||||||
accumulatedChange = null;
|
accumulatedChange = null;
|
||||||
stateAtStart = null;
|
stateAtStart = null;
|
||||||
|
originalElementsMap = null;
|
||||||
|
|
||||||
document.body.classList.remove("dragResize");
|
document.body.classList.remove("dragResize");
|
||||||
},
|
},
|
||||||
@ -149,14 +171,16 @@ const StatsDragInput = ({
|
|||||||
setInputValue(value.toString());
|
setInputValue(value.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dragInputCallback(
|
|
||||||
0,
|
dragInputCallback({
|
||||||
0,
|
accumulatedChange: 0,
|
||||||
elements,
|
instantChange: 0,
|
||||||
shouldKeepAspectRatio!!,
|
stateAtStart: elements,
|
||||||
false,
|
originalElementsMap: app.scene.getNonDeletedElementsMap(),
|
||||||
v,
|
shouldKeepAspectRatio: shouldKeepAspectRatio!!,
|
||||||
);
|
shouldChangeByStepSize: false,
|
||||||
|
nextValue: v,
|
||||||
|
});
|
||||||
app.store.shouldCaptureIncrement();
|
app.store.shouldCaptureIncrement();
|
||||||
eventTarget.blur();
|
eventTarget.blur();
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,12 @@ const MIN_FONT_SIZE = 4;
|
|||||||
const STEP_SIZE = 4;
|
const STEP_SIZE = 4;
|
||||||
|
|
||||||
const FontSize = ({ element, elementsMap }: FontSizeProps) => {
|
const FontSize = ({ element, elementsMap }: FontSizeProps) => {
|
||||||
const handleFontSizeChange: DragInputCallbackType = (
|
const handleFontSizeChange: DragInputCallbackType = ({
|
||||||
accumulatedChange,
|
accumulatedChange,
|
||||||
instantChange,
|
|
||||||
stateAtStart,
|
stateAtStart,
|
||||||
shouldKeepAspectRatio,
|
|
||||||
shouldChangeByStepSize,
|
shouldChangeByStepSize,
|
||||||
nextValue,
|
nextValue,
|
||||||
) => {
|
}) => {
|
||||||
const _stateAtStart = stateAtStart[0];
|
const _stateAtStart = stateAtStart[0];
|
||||||
if (_stateAtStart) {
|
if (_stateAtStart) {
|
||||||
if (nextValue) {
|
if (nextValue) {
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import { getCommonBounds } from "../../element";
|
import { getCommonBounds, isTextElement } from "../../element";
|
||||||
|
import { updateBoundElements } from "../../element/binding";
|
||||||
import { mutateElement } from "../../element/mutateElement";
|
import { mutateElement } from "../../element/mutateElement";
|
||||||
import { rescalePointsInElement } from "../../element/resizeElements";
|
import { rescalePointsInElement } from "../../element/resizeElements";
|
||||||
import type { ExcalidrawElement } from "../../element/types";
|
import {
|
||||||
|
getBoundTextElement,
|
||||||
|
handleBindTextResize,
|
||||||
|
} from "../../element/textElement";
|
||||||
|
import type { ElementsMap, ExcalidrawElement } from "../../element/types";
|
||||||
import DragInput from "./DragInput";
|
import DragInput from "./DragInput";
|
||||||
import type { DragInputCallbackType } from "./DragInput";
|
import type { DragInputCallbackType } from "./DragInput";
|
||||||
import { getStepSizedValue } from "./utils";
|
import { getStepSizedValue } from "./utils";
|
||||||
@ -9,6 +14,7 @@ import { getStepSizedValue } from "./utils";
|
|||||||
interface MultiDimensionProps {
|
interface MultiDimensionProps {
|
||||||
property: "width" | "height";
|
property: "width" | "height";
|
||||||
elements: ExcalidrawElement[];
|
elements: ExcalidrawElement[];
|
||||||
|
elementsMap: ElementsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STEP_SIZE = 10;
|
const STEP_SIZE = 10;
|
||||||
@ -32,18 +38,66 @@ const getResizedUpdates = (
|
|||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
...rescalePointsInElement(stateAtStart, nextWidth, nextHeight, false),
|
...rescalePointsInElement(stateAtStart, nextWidth, nextHeight, false),
|
||||||
|
...(isTextElement(stateAtStart)
|
||||||
|
? { fontSize: stateAtStart.fontSize * scale }
|
||||||
|
: {}),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const MultiDimension = ({ property, elements }: MultiDimensionProps) => {
|
const resizeElement = (
|
||||||
const handleDimensionChange: DragInputCallbackType = (
|
anchorX: number,
|
||||||
|
anchorY: number,
|
||||||
|
property: MultiDimensionProps["property"],
|
||||||
|
scale: number,
|
||||||
|
latestElement: ExcalidrawElement,
|
||||||
|
origElement: ExcalidrawElement,
|
||||||
|
elementsMap: ElementsMap,
|
||||||
|
originalElementsMap: ElementsMap,
|
||||||
|
shouldInformMutation: boolean,
|
||||||
|
) => {
|
||||||
|
const updates = getResizedUpdates(anchorX, anchorY, scale, origElement);
|
||||||
|
|
||||||
|
mutateElement(latestElement, updates, shouldInformMutation);
|
||||||
|
const boundTextElement = getBoundTextElement(
|
||||||
|
origElement,
|
||||||
|
originalElementsMap,
|
||||||
|
);
|
||||||
|
if (boundTextElement) {
|
||||||
|
const newFontSize = boundTextElement.fontSize * scale;
|
||||||
|
updateBoundElements(latestElement, elementsMap, {
|
||||||
|
newSize: { width: updates.width, height: updates.height },
|
||||||
|
});
|
||||||
|
const latestBoundTextElement = elementsMap.get(boundTextElement.id);
|
||||||
|
if (latestBoundTextElement && isTextElement(latestBoundTextElement)) {
|
||||||
|
mutateElement(
|
||||||
|
latestBoundTextElement,
|
||||||
|
{
|
||||||
|
fontSize: newFontSize,
|
||||||
|
},
|
||||||
|
shouldInformMutation,
|
||||||
|
);
|
||||||
|
handleBindTextResize(
|
||||||
|
latestElement,
|
||||||
|
elementsMap,
|
||||||
|
property === "width" ? "e" : "s",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const MultiDimension = ({
|
||||||
|
property,
|
||||||
|
elements,
|
||||||
|
elementsMap,
|
||||||
|
}: MultiDimensionProps) => {
|
||||||
|
const handleDimensionChange: DragInputCallbackType = ({
|
||||||
accumulatedChange,
|
accumulatedChange,
|
||||||
instantChange,
|
|
||||||
stateAtStart,
|
stateAtStart,
|
||||||
shouldKeepAspectRatio,
|
originalElementsMap,
|
||||||
shouldChangeByStepSize,
|
shouldChangeByStepSize,
|
||||||
nextValue,
|
nextValue,
|
||||||
) => {
|
}) => {
|
||||||
const [x1, y1, x2, y2] = getCommonBounds(stateAtStart);
|
const [x1, y1, x2, y2] = getCommonBounds(stateAtStart);
|
||||||
const initialWidth = x2 - x1;
|
const initialWidth = x2 - x1;
|
||||||
const initialHeight = y2 - y1;
|
const initialHeight = y2 - y1;
|
||||||
@ -60,15 +114,21 @@ const MultiDimension = ({ property, elements }: MultiDimensionProps) => {
|
|||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < stateAtStart.length) {
|
while (i < stateAtStart.length) {
|
||||||
const element = elements[i];
|
const latestElement = elements[i];
|
||||||
const origElement = stateAtStart[i];
|
const origElement = stateAtStart[i];
|
||||||
|
|
||||||
// it should never happen that element and origElement are different
|
// it should never happen that element and origElement are different
|
||||||
// but check just in case
|
// but check just in case
|
||||||
if (element.id === origElement.id) {
|
if (latestElement.id === origElement.id) {
|
||||||
mutateElement(
|
resizeElement(
|
||||||
element,
|
anchorX,
|
||||||
getResizedUpdates(anchorX, anchorY, scale, origElement),
|
anchorY,
|
||||||
|
property,
|
||||||
|
scale,
|
||||||
|
latestElement,
|
||||||
|
origElement,
|
||||||
|
elementsMap,
|
||||||
|
originalElementsMap,
|
||||||
i === stateAtStart.length - 1,
|
i === stateAtStart.length - 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -113,13 +173,19 @@ const MultiDimension = ({ property, elements }: MultiDimensionProps) => {
|
|||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < stateAtStart.length) {
|
while (i < stateAtStart.length) {
|
||||||
const element = elements[i];
|
const latestElement = elements[i];
|
||||||
const origElement = stateAtStart[i];
|
const origElement = stateAtStart[i];
|
||||||
|
|
||||||
if (element.id === origElement.id) {
|
if (latestElement.id === origElement.id) {
|
||||||
mutateElement(
|
resizeElement(
|
||||||
element,
|
anchorX,
|
||||||
getResizedUpdates(anchorX, anchorY, scale, origElement),
|
anchorY,
|
||||||
|
property,
|
||||||
|
scale,
|
||||||
|
latestElement,
|
||||||
|
origElement,
|
||||||
|
elementsMap,
|
||||||
|
originalElementsMap,
|
||||||
i === stateAtStart.length - 1,
|
i === stateAtStart.length - 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useState } from "react";
|
|||||||
import { getCommonBounds } from "../../element/bounds";
|
import { getCommonBounds } from "../../element/bounds";
|
||||||
import type { NonDeletedExcalidrawElement } from "../../element/types";
|
import type { NonDeletedExcalidrawElement } from "../../element/types";
|
||||||
import { t } from "../../i18n";
|
import { t } from "../../i18n";
|
||||||
import { getTargetElements } from "../../scene";
|
import { getSelectedElements } from "../../scene";
|
||||||
import type Scene from "../../scene/Scene";
|
import type Scene from "../../scene/Scene";
|
||||||
import type { AppState, ExcalidrawProps } from "../../types";
|
import type { AppState, ExcalidrawProps } from "../../types";
|
||||||
import { CloseIcon } from "../icons";
|
import { CloseIcon } from "../icons";
|
||||||
@ -29,7 +29,14 @@ export const Stats = (props: StatsProps) => {
|
|||||||
const elements = props.scene.getNonDeletedElements();
|
const elements = props.scene.getNonDeletedElements();
|
||||||
const elementsMap = props.scene.getNonDeletedElementsMap();
|
const elementsMap = props.scene.getNonDeletedElementsMap();
|
||||||
const sceneNonce = props.scene.getSceneNonce();
|
const sceneNonce = props.scene.getSceneNonce();
|
||||||
const selectedElements = getTargetElements(elements, props.appState);
|
// const selectedElements = getTargetElements(elements, props.appState);
|
||||||
|
const selectedElements = getSelectedElements(
|
||||||
|
props.scene.getNonDeletedElementsMap(),
|
||||||
|
props.appState,
|
||||||
|
{
|
||||||
|
includeBoundTextElement: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const singleElement =
|
const singleElement =
|
||||||
selectedElements.length === 1 ? selectedElements[0] : null;
|
selectedElements.length === 1 ? selectedElements[0] : null;
|
||||||
@ -112,9 +119,17 @@ export const Stats = (props: StatsProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="statsItem">
|
<div className="statsItem">
|
||||||
<Dimension property="width" element={singleElement} />
|
<Dimension
|
||||||
<Dimension property="height" element={singleElement} />
|
property="width"
|
||||||
<Angle element={singleElement} />
|
element={singleElement}
|
||||||
|
elementsMap={elementsMap}
|
||||||
|
/>
|
||||||
|
<Dimension
|
||||||
|
property="height"
|
||||||
|
element={singleElement}
|
||||||
|
elementsMap={elementsMap}
|
||||||
|
/>
|
||||||
|
<Angle element={singleElement} elementsMap={elementsMap} />
|
||||||
{singleElement.type === "text" && (
|
{singleElement.type === "text" && (
|
||||||
<FontSize
|
<FontSize
|
||||||
element={singleElement}
|
element={singleElement}
|
||||||
@ -142,10 +157,12 @@ export const Stats = (props: StatsProps) => {
|
|||||||
<MultiDimension
|
<MultiDimension
|
||||||
property="width"
|
property="width"
|
||||||
elements={multipleElements}
|
elements={multipleElements}
|
||||||
|
elementsMap={elementsMap}
|
||||||
/>
|
/>
|
||||||
<MultiDimension
|
<MultiDimension
|
||||||
property="height"
|
property="height"
|
||||||
elements={multipleElements}
|
elements={multipleElements}
|
||||||
|
elementsMap={elementsMap}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,7 +199,7 @@ export const rescalePointsInElement = (
|
|||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const measureFontSizeFromWidth = (
|
export const measureFontSizeFromWidth = (
|
||||||
element: NonDeleted<ExcalidrawTextElement>,
|
element: NonDeleted<ExcalidrawTextElement>,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
nextWidth: number,
|
nextWidth: number,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user