mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-23 17:30:44 +02:00
Compare commits
10 Commits
aakansha-d
...
zsviczian-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c1f8eca7de | ||
![]() |
340b9757c3 | ||
![]() |
6035ebe95f | ||
![]() |
1a877fa8c7 | ||
![]() |
956228f4a1 | ||
![]() |
cfb9f8d8c7 | ||
![]() |
da06e8ad27 | ||
![]() |
27c7e75761 | ||
![]() |
2b8d69c65d | ||
![]() |
6d071a8a13 |
@@ -43,9 +43,9 @@ import {
|
|||||||
getApproxMinLineWidth,
|
getApproxMinLineWidth,
|
||||||
getBoundTextElement,
|
getBoundTextElement,
|
||||||
getBoundTextElementId,
|
getBoundTextElementId,
|
||||||
|
getContainerElement,
|
||||||
handleBindTextResize,
|
handleBindTextResize,
|
||||||
getMaxContainerWidth,
|
getMaxContainerWidth,
|
||||||
getContainerElement,
|
|
||||||
} from "./textElement";
|
} from "./textElement";
|
||||||
|
|
||||||
export const normalizeAngle = (angle: number): number => {
|
export const normalizeAngle = (angle: number): number => {
|
||||||
@@ -414,12 +414,30 @@ export const resizeSingleElement = (
|
|||||||
fontSize: stateOfBoundTextElementAtResize.fontSize,
|
fontSize: stateOfBoundTextElementAtResize.fontSize,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (shouldMaintainAspectRatio) {
|
||||||
|
const updatedElement = {
|
||||||
|
...element,
|
||||||
|
width: eleNewWidth,
|
||||||
|
height: eleNewHeight,
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextFontSize = measureFontSizeFromWidth(
|
||||||
|
boundTextElement,
|
||||||
|
getMaxContainerWidth(updatedElement),
|
||||||
|
);
|
||||||
|
if (nextFontSize === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boundTextFont = {
|
||||||
|
fontSize: nextFontSize,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
const minWidth = getApproxMinLineWidth(getFontString(boundTextElement));
|
const minWidth = getApproxMinLineWidth(getFontString(boundTextElement));
|
||||||
const minHeight = getApproxMinLineHeight(getFontString(boundTextElement));
|
const minHeight = getApproxMinLineHeight(getFontString(boundTextElement));
|
||||||
eleNewWidth = Math.ceil(Math.max(eleNewWidth, minWidth));
|
eleNewWidth = Math.ceil(Math.max(eleNewWidth, minWidth));
|
||||||
eleNewHeight = Math.ceil(Math.max(eleNewHeight, minHeight));
|
eleNewHeight = Math.ceil(Math.max(eleNewHeight, minHeight));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [newBoundsX1, newBoundsY1, newBoundsX2, newBoundsY2] =
|
const [newBoundsX1, newBoundsY1, newBoundsX2, newBoundsY2] =
|
||||||
getResizedElementAbsoluteCoords(
|
getResizedElementAbsoluteCoords(
|
||||||
@@ -551,11 +569,7 @@ export const resizeSingleElement = (
|
|||||||
if (boundTextElement && boundTextFont) {
|
if (boundTextElement && boundTextFont) {
|
||||||
mutateElement(boundTextElement, { fontSize: boundTextFont.fontSize });
|
mutateElement(boundTextElement, { fontSize: boundTextFont.fontSize });
|
||||||
}
|
}
|
||||||
handleBindTextResize(
|
handleBindTextResize(element, transformHandleDirection);
|
||||||
element,
|
|
||||||
transformHandleDirection,
|
|
||||||
shouldMaintainAspectRatio,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -2,11 +2,10 @@ import { BOUND_TEXT_PADDING } from "../constants";
|
|||||||
import { API } from "../tests/helpers/api";
|
import { API } from "../tests/helpers/api";
|
||||||
import {
|
import {
|
||||||
computeContainerDimensionForBoundText,
|
computeContainerDimensionForBoundText,
|
||||||
computeBoundTextElementCoords,
|
getContainerCoords,
|
||||||
getMaxContainerWidth,
|
getMaxContainerWidth,
|
||||||
getMaxContainerHeight,
|
getMaxContainerHeight,
|
||||||
wrapText,
|
wrapText,
|
||||||
computeContainerCoords,
|
|
||||||
} from "./textElement";
|
} from "./textElement";
|
||||||
import { FontString } from "./types";
|
import { FontString } from "./types";
|
||||||
|
|
||||||
@@ -178,7 +177,8 @@ break it now`,
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test computeBoundTextElementCoords", () => {
|
describe("Test measureText", () => {
|
||||||
|
describe("Test getContainerCoords", () => {
|
||||||
const params = { width: 200, height: 100, x: 10, y: 20 };
|
const params = { width: 200, height: 100, x: 10, y: 20 };
|
||||||
|
|
||||||
it("should compute coords correctly when ellipse", () => {
|
it("should compute coords correctly when ellipse", () => {
|
||||||
@@ -186,7 +186,7 @@ describe("Test computeBoundTextElementCoords", () => {
|
|||||||
type: "ellipse",
|
type: "ellipse",
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
expect(computeBoundTextElementCoords(element)).toEqual({
|
expect(getContainerCoords(element)).toEqual({
|
||||||
x: 44.2893218813452455,
|
x: 44.2893218813452455,
|
||||||
y: 39.64466094067262,
|
y: 39.64466094067262,
|
||||||
});
|
});
|
||||||
@@ -197,7 +197,7 @@ describe("Test computeBoundTextElementCoords", () => {
|
|||||||
type: "rectangle",
|
type: "rectangle",
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
expect(computeBoundTextElementCoords(element)).toEqual({
|
expect(getContainerCoords(element)).toEqual({
|
||||||
x: 15,
|
x: 15,
|
||||||
y: 25,
|
y: 25,
|
||||||
});
|
});
|
||||||
@@ -208,44 +208,14 @@ describe("Test computeBoundTextElementCoords", () => {
|
|||||||
type: "diamond",
|
type: "diamond",
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
expect(computeBoundTextElementCoords(element)).toEqual({
|
expect(getContainerCoords(element)).toEqual({
|
||||||
x: 65,
|
x: 65,
|
||||||
y: 50,
|
y: 50,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe("Test computeContainerCoords", () => {
|
|
||||||
const boundTextElement = API.createElement({
|
|
||||||
type: "text",
|
|
||||||
width: 200,
|
|
||||||
height: 100,
|
|
||||||
x: 10,
|
|
||||||
y: 20,
|
|
||||||
});
|
|
||||||
it("should compute coords correctly when ellipse", () => {
|
|
||||||
expect(computeContainerCoords(boundTextElement, "ellipse")).toEqual({
|
|
||||||
x: -24.289321881345245,
|
|
||||||
y: 0.3553390593273775,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should compute coords correctly when rectangle", () => {
|
describe("Test computeContainerDimensionForBoundText", () => {
|
||||||
expect(computeContainerCoords(boundTextElement, "rectangle")).toEqual({
|
|
||||||
x: 5,
|
|
||||||
y: 15,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should compute coords correctly when diamond", () => {
|
|
||||||
expect(computeContainerCoords(boundTextElement, "diamond")).toEqual({
|
|
||||||
x: -45,
|
|
||||||
y: -10,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Test computeContainerDimensionForBoundText", () => {
|
|
||||||
const params = {
|
const params = {
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 194,
|
height: 194,
|
||||||
@@ -280,9 +250,9 @@ describe("Test computeContainerDimensionForBoundText", () => {
|
|||||||
320,
|
320,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test getMaxContainerWidth", () => {
|
describe("Test getMaxContainerWidth", () => {
|
||||||
const params = {
|
const params = {
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 194,
|
height: 194,
|
||||||
@@ -302,9 +272,9 @@ describe("Test getMaxContainerWidth", () => {
|
|||||||
const container = API.createElement({ type: "diamond", ...params });
|
const container = API.createElement({ type: "diamond", ...params });
|
||||||
expect(getMaxContainerWidth(container)).toBe(79);
|
expect(getMaxContainerWidth(container)).toBe(79);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test getMaxContainerHeight", () => {
|
describe("Test getMaxContainerHeight", () => {
|
||||||
const params = {
|
const params = {
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 194,
|
height: 194,
|
||||||
@@ -324,4 +294,5 @@ describe("Test getMaxContainerHeight", () => {
|
|||||||
const container = API.createElement({ type: "diamond", ...params });
|
const container = API.createElement({ type: "diamond", ...params });
|
||||||
expect(getMaxContainerHeight(container)).toBe(87);
|
expect(getMaxContainerHeight(container)).toBe(87);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -147,7 +147,6 @@ export const bindTextToShapeAfterDuplication = (
|
|||||||
export const handleBindTextResize = (
|
export const handleBindTextResize = (
|
||||||
container: NonDeletedExcalidrawElement,
|
container: NonDeletedExcalidrawElement,
|
||||||
transformHandleType: MaybeTransformHandleType,
|
transformHandleType: MaybeTransformHandleType,
|
||||||
shouldMaintainAspectRatio = false,
|
|
||||||
) => {
|
) => {
|
||||||
const boundTextElementId = getBoundTextElementId(container);
|
const boundTextElementId = getBoundTextElementId(container);
|
||||||
if (!boundTextElementId) {
|
if (!boundTextElementId) {
|
||||||
@@ -185,7 +184,7 @@ export const handleBindTextResize = (
|
|||||||
nextWidth = dimensions.width;
|
nextWidth = dimensions.width;
|
||||||
}
|
}
|
||||||
// increase height in case text element height exceeds
|
// increase height in case text element height exceeds
|
||||||
if (!shouldMaintainAspectRatio && nextHeight > maxHeight) {
|
if (nextHeight > maxHeight) {
|
||||||
containerHeight = computeContainerDimensionForBoundText(
|
containerHeight = computeContainerDimensionForBoundText(
|
||||||
nextHeight,
|
nextHeight,
|
||||||
container.type,
|
container.type,
|
||||||
@@ -206,53 +205,6 @@ export const handleBindTextResize = (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
shouldMaintainAspectRatio &&
|
|
||||||
(nextHeight > maxHeight || nextWidth > maxWidth)
|
|
||||||
) {
|
|
||||||
let height = containerDims.height;
|
|
||||||
let width = containerDims.width;
|
|
||||||
let x = container.x;
|
|
||||||
let y = container.y;
|
|
||||||
|
|
||||||
if (nextHeight > maxHeight) {
|
|
||||||
height = computeContainerDimensionForBoundText(
|
|
||||||
nextHeight,
|
|
||||||
container.type,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (nextWidth > maxWidth) {
|
|
||||||
width = computeContainerDimensionForBoundText(
|
|
||||||
nextWidth,
|
|
||||||
container.type,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const diffX = width - containerDims.width;
|
|
||||||
const diffY = height - containerDims.height;
|
|
||||||
|
|
||||||
if (transformHandleType === "n") {
|
|
||||||
y = container.y - diffY;
|
|
||||||
} else if (
|
|
||||||
transformHandleType === "e" ||
|
|
||||||
transformHandleType === "w" ||
|
|
||||||
transformHandleType === "ne" ||
|
|
||||||
transformHandleType === "nw"
|
|
||||||
) {
|
|
||||||
y = container.y - diffY / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transformHandleType === "s" || transformHandleType === "n") {
|
|
||||||
x = container.x - diffX / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutateElement(container, {
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mutateElement(textElement, {
|
mutateElement(textElement, {
|
||||||
text,
|
text,
|
||||||
width: nextWidth,
|
width: nextWidth,
|
||||||
@@ -275,7 +227,7 @@ const computeBoundTextPosition = (
|
|||||||
container: ExcalidrawElement,
|
container: ExcalidrawElement,
|
||||||
boundTextElement: ExcalidrawTextElementWithContainer,
|
boundTextElement: ExcalidrawTextElementWithContainer,
|
||||||
) => {
|
) => {
|
||||||
const containerCoords = computeBoundTextElementCoords(container);
|
const containerCoords = getContainerCoords(container);
|
||||||
const maxContainerHeight = getMaxContainerHeight(container);
|
const maxContainerHeight = getMaxContainerHeight(container);
|
||||||
const maxContainerWidth = getMaxContainerWidth(container);
|
const maxContainerWidth = getMaxContainerWidth(container);
|
||||||
|
|
||||||
@@ -644,9 +596,7 @@ export const getContainerCenter = (
|
|||||||
return { x: midSegmentMidpoint[0], y: midSegmentMidpoint[1] };
|
return { x: midSegmentMidpoint[0], y: midSegmentMidpoint[1] };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const computeBoundTextElementCoords = (
|
export const getContainerCoords = (container: NonDeletedExcalidrawElement) => {
|
||||||
container: NonDeletedExcalidrawElement,
|
|
||||||
) => {
|
|
||||||
let offsetX = BOUND_TEXT_PADDING;
|
let offsetX = BOUND_TEXT_PADDING;
|
||||||
let offsetY = BOUND_TEXT_PADDING;
|
let offsetY = BOUND_TEXT_PADDING;
|
||||||
|
|
||||||
@@ -666,27 +616,6 @@ export const computeBoundTextElementCoords = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const computeContainerCoords = (
|
|
||||||
boundTextElement: ExcalidrawTextElement,
|
|
||||||
containerType: string,
|
|
||||||
) => {
|
|
||||||
let offsetX = BOUND_TEXT_PADDING;
|
|
||||||
let offsetY = BOUND_TEXT_PADDING;
|
|
||||||
|
|
||||||
if (containerType === "ellipse") {
|
|
||||||
offsetX += (boundTextElement.width / 2) * (1 - Math.sqrt(2) / 2);
|
|
||||||
offsetY += (boundTextElement.height / 2) * (1 - Math.sqrt(2) / 2);
|
|
||||||
}
|
|
||||||
if (containerType === "diamond") {
|
|
||||||
offsetX += boundTextElement.width / 4;
|
|
||||||
offsetY += boundTextElement.height / 4;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
x: boundTextElement.x - offsetX,
|
|
||||||
y: boundTextElement.y - offsetY,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTextElementAngle = (textElement: ExcalidrawTextElement) => {
|
export const getTextElementAngle = (textElement: ExcalidrawTextElement) => {
|
||||||
const container = getContainerElement(textElement);
|
const container = getContainerElement(textElement);
|
||||||
if (!container || isArrowElement(container)) {
|
if (!container || isArrowElement(container)) {
|
||||||
|
@@ -989,136 +989,26 @@ describe("textWysiwyg", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.only("when using shift resize", () => {
|
it("should scale font size correctly when resizing using shift", async () => {
|
||||||
it("should wrap text correctly when resizing using shift from 'ne' handle", async () => {
|
|
||||||
Keyboard.keyPress(KEYS.ENTER);
|
Keyboard.keyPress(KEYS.ENTER);
|
||||||
|
|
||||||
const editor = document.querySelector(
|
const editor = document.querySelector(
|
||||||
".excalidraw-textEditorContainer > textarea",
|
".excalidraw-textEditorContainer > textarea",
|
||||||
) as HTMLTextAreaElement;
|
) as HTMLTextAreaElement;
|
||||||
await new Promise((r) => setTimeout(r, 0));
|
await new Promise((r) => setTimeout(r, 0));
|
||||||
fireEvent.change(editor, {
|
fireEvent.change(editor, { target: { value: "Hello" } });
|
||||||
target: { value: "Excalidraw is an opensource virtual whiteboard" },
|
|
||||||
});
|
|
||||||
editor.blur();
|
editor.blur();
|
||||||
const textElement = h.elements[1] as ExcalidrawTextElement;
|
const textElement = h.elements[1] as ExcalidrawTextElement;
|
||||||
expect(rectangle.width).toBe(90);
|
expect(rectangle.width).toBe(90);
|
||||||
expect(rectangle.height).toBe(202);
|
expect(rectangle.height).toBe(75);
|
||||||
expect(textElement.fontSize).toBe(20);
|
expect(textElement.fontSize).toBe(20);
|
||||||
expect(textElement.text).toBe(
|
|
||||||
`Excalid
|
|
||||||
raw is
|
|
||||||
an
|
|
||||||
opensou
|
|
||||||
rce
|
|
||||||
virtual
|
|
||||||
whitebo
|
|
||||||
ard`,
|
|
||||||
);
|
|
||||||
|
|
||||||
resize(rectangle, "ne", [rectangle.x + 100, rectangle.y - 50], {
|
resize(rectangle, "ne", [rectangle.x + 100, rectangle.y - 50], {
|
||||||
shift: true,
|
shift: true,
|
||||||
});
|
});
|
||||||
expect(rectangle.width).toBe(200);
|
expect(rectangle.width).toBe(200);
|
||||||
expect(rectangle.height).toBe(449);
|
expect(rectangle.height).toBe(166.66666666666669);
|
||||||
expect(textElement.fontSize).toBe(20);
|
expect(textElement.fontSize).toBe(47.5);
|
||||||
expect(textElement.text).toBe(
|
|
||||||
`Excalidraw is an
|
|
||||||
opensource virtual
|
|
||||||
whiteboard`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should wrap text correctly when resizing using shift vertically using 'n' handle", async () => {
|
|
||||||
Keyboard.keyPress(KEYS.ENTER);
|
|
||||||
|
|
||||||
const editor = document.querySelector(
|
|
||||||
".excalidraw-textEditorContainer > textarea",
|
|
||||||
) as HTMLTextAreaElement;
|
|
||||||
await new Promise((r) => setTimeout(r, 0));
|
|
||||||
fireEvent.change(editor, {
|
|
||||||
target: { value: "Excalidraw is an opensource virtual whiteboard" },
|
|
||||||
});
|
|
||||||
editor.blur();
|
|
||||||
const textElement = h.elements[1] as ExcalidrawTextElement;
|
|
||||||
expect(rectangle.width).toBe(90);
|
|
||||||
expect(rectangle.height).toBe(202);
|
|
||||||
expect(textElement.fontSize).toBe(20);
|
|
||||||
expect(textElement.text).toBe(
|
|
||||||
`Excalid
|
|
||||||
raw is
|
|
||||||
an
|
|
||||||
opensou
|
|
||||||
rce
|
|
||||||
virtual
|
|
||||||
whitebo
|
|
||||||
ard`,
|
|
||||||
);
|
|
||||||
|
|
||||||
resize(rectangle, "n", [rectangle.x + 30, rectangle.y - 50], {
|
|
||||||
shift: true,
|
|
||||||
});
|
|
||||||
expect(rectangle.width).toBe(104);
|
|
||||||
expect(rectangle.height).toBe(232);
|
|
||||||
expect(textElement.fontSize).toBe(20);
|
|
||||||
expect(textElement.text).toBe(
|
|
||||||
`Excalid
|
|
||||||
raw is
|
|
||||||
an
|
|
||||||
opensou
|
|
||||||
rce
|
|
||||||
virtual
|
|
||||||
whitebo
|
|
||||||
ard`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should wrap text correctly when resizing using shift horizontally and text overflows", async () => {
|
|
||||||
Keyboard.keyPress(KEYS.ENTER);
|
|
||||||
|
|
||||||
const editor = document.querySelector(
|
|
||||||
".excalidraw-textEditorContainer > textarea",
|
|
||||||
) as HTMLTextAreaElement;
|
|
||||||
await new Promise((r) => setTimeout(r, 0));
|
|
||||||
fireEvent.change(editor, {
|
|
||||||
target: { value: "Excalidraw is an opensource virtual whiteboard" },
|
|
||||||
});
|
|
||||||
editor.blur();
|
|
||||||
const textElement = h.elements[1] as ExcalidrawTextElement;
|
|
||||||
expect(rectangle.width).toBe(90);
|
|
||||||
expect(rectangle.height).toBe(202);
|
|
||||||
expect(rectangle.y).toBe(20);
|
|
||||||
expect(textElement.fontSize).toBe(20);
|
|
||||||
expect(textElement.text).toBe(
|
|
||||||
`Excalid
|
|
||||||
raw is
|
|
||||||
an
|
|
||||||
opensou
|
|
||||||
rce
|
|
||||||
virtual
|
|
||||||
whitebo
|
|
||||||
ard`,
|
|
||||||
);
|
|
||||||
|
|
||||||
resize(rectangle, "e", [rectangle.x - 30, rectangle.y + 30], {
|
|
||||||
shift: true,
|
|
||||||
});
|
|
||||||
expect(rectangle.width).toBe(70);
|
|
||||||
expect(rectangle.height).toBe(226);
|
|
||||||
expect(rectangle.y).toBe(8);
|
|
||||||
expect(textElement.fontSize).toBe(20);
|
|
||||||
expect(textElement.text).toBe(
|
|
||||||
`Excal
|
|
||||||
idraw
|
|
||||||
is an
|
|
||||||
opens
|
|
||||||
ource
|
|
||||||
virtu
|
|
||||||
al
|
|
||||||
white
|
|
||||||
board`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should bind text correctly when container duplicated with alt-drag", async () => {
|
it("should bind text correctly when container duplicated with alt-drag", async () => {
|
||||||
|
@@ -11,7 +11,7 @@ import {
|
|||||||
isBoundToContainer,
|
isBoundToContainer,
|
||||||
isTextElement,
|
isTextElement,
|
||||||
} from "./typeChecks";
|
} from "./typeChecks";
|
||||||
import { CLASSES, isFirefox, isSafari, VERTICAL_ALIGN } from "../constants";
|
import { CLASSES, VERTICAL_ALIGN } from "../constants";
|
||||||
import {
|
import {
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
@@ -24,7 +24,7 @@ import { mutateElement } from "./mutateElement";
|
|||||||
import {
|
import {
|
||||||
getApproxLineHeight,
|
getApproxLineHeight,
|
||||||
getBoundTextElementId,
|
getBoundTextElementId,
|
||||||
computeBoundTextElementCoords,
|
getContainerCoords,
|
||||||
getContainerDims,
|
getContainerDims,
|
||||||
getContainerElement,
|
getContainerElement,
|
||||||
getTextElementAngle,
|
getTextElementAngle,
|
||||||
@@ -233,7 +233,7 @@ export const textWysiwyg = ({
|
|||||||
// Start pushing text upward until a diff of 30px (padding)
|
// Start pushing text upward until a diff of 30px (padding)
|
||||||
// is reached
|
// is reached
|
||||||
else {
|
else {
|
||||||
const containerCoords = computeBoundTextElementCoords(container);
|
const containerCoords = getContainerCoords(container);
|
||||||
|
|
||||||
// vertically center align the text
|
// vertically center align the text
|
||||||
if (verticalAlign === VERTICAL_ALIGN.MIDDLE) {
|
if (verticalAlign === VERTICAL_ALIGN.MIDDLE) {
|
||||||
@@ -270,12 +270,10 @@ export const textWysiwyg = ({
|
|||||||
const lineHeight = updatedTextElement.containerId
|
const lineHeight = updatedTextElement.containerId
|
||||||
? approxLineHeight
|
? approxLineHeight
|
||||||
: updatedTextElement.height / lines.length;
|
: updatedTextElement.height / lines.length;
|
||||||
|
|
||||||
if (!container) {
|
if (!container) {
|
||||||
maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
|
maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
|
||||||
textElementWidth = Math.min(textElementWidth, maxWidth);
|
textElementWidth = Math.min(textElementWidth, maxWidth);
|
||||||
} else if (isFirefox || isSafari) {
|
|
||||||
// As firefox, Safari needs little higher dimensions on DOM
|
|
||||||
textElementWidth += 0.5;
|
|
||||||
}
|
}
|
||||||
// Make sure text editor height doesn't go beyond viewport
|
// Make sure text editor height doesn't go beyond viewport
|
||||||
const editorMaxHeight =
|
const editorMaxHeight =
|
||||||
@@ -348,7 +346,32 @@ export const textWysiwyg = ({
|
|||||||
overflowWrap: "break-word",
|
overflowWrap: "break-word",
|
||||||
boxSizing: "content-box",
|
boxSizing: "content-box",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const magicOffset =
|
||||||
|
(excalidrawContainer
|
||||||
|
? parseFloat(getComputedStyle(excalidrawContainer).fontSize)
|
||||||
|
: 16) / 16;
|
||||||
|
|
||||||
|
const onEditableInput = () => {
|
||||||
|
const updatedTextElement = Scene.getScene(element)?.getElement(
|
||||||
|
id,
|
||||||
|
) as ExcalidrawTextElement;
|
||||||
|
const font = getFontString(updatedTextElement);
|
||||||
|
if (isBoundToContainer(element)) {
|
||||||
|
const container = getContainerElement(element);
|
||||||
|
const wrappedText = wrapText(
|
||||||
|
normalizeText(editable.value),
|
||||||
|
font,
|
||||||
|
getMaxContainerWidth(container!),
|
||||||
|
);
|
||||||
|
const { width, height } = measureText(wrappedText, font);
|
||||||
|
editable.style.width = `${width + magicOffset}px`;
|
||||||
|
editable.style.height = `${height}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
updateWysiwygStyle();
|
updateWysiwygStyle();
|
||||||
|
onEditableInput();
|
||||||
|
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
editable.onpaste = async (event) => {
|
editable.onpaste = async (event) => {
|
||||||
@@ -378,21 +401,7 @@ export const textWysiwyg = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
editable.oninput = () => {
|
editable.oninput = () => {
|
||||||
const updatedTextElement = Scene.getScene(element)?.getElement(
|
onEditableInput();
|
||||||
id,
|
|
||||||
) as ExcalidrawTextElement;
|
|
||||||
const font = getFontString(updatedTextElement);
|
|
||||||
if (isBoundToContainer(element)) {
|
|
||||||
const container = getContainerElement(element);
|
|
||||||
const wrappedText = wrapText(
|
|
||||||
normalizeText(editable.value),
|
|
||||||
font,
|
|
||||||
getMaxContainerWidth(container!),
|
|
||||||
);
|
|
||||||
const { width, height } = measureText(wrappedText, font);
|
|
||||||
editable.style.width = `${width}px`;
|
|
||||||
editable.style.height = `${height}px`;
|
|
||||||
}
|
|
||||||
onChange(normalizeText(editable.value));
|
onChange(normalizeText(editable.value));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -42,7 +42,7 @@ import { getStroke, StrokeOptions } from "perfect-freehand";
|
|||||||
import {
|
import {
|
||||||
getApproxLineHeight,
|
getApproxLineHeight,
|
||||||
getBoundTextElement,
|
getBoundTextElement,
|
||||||
computeBoundTextElementCoords,
|
getContainerCoords,
|
||||||
getContainerElement,
|
getContainerElement,
|
||||||
getMaxContainerHeight,
|
getMaxContainerHeight,
|
||||||
getMaxContainerWidth,
|
getMaxContainerWidth,
|
||||||
@@ -820,7 +820,7 @@ const drawElementFromCanvas = (
|
|||||||
process.env.REACT_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX &&
|
process.env.REACT_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX &&
|
||||||
hasBoundTextElement(element)
|
hasBoundTextElement(element)
|
||||||
) {
|
) {
|
||||||
const coords = computeBoundTextElementCoords(element);
|
const coords = getContainerCoords(element);
|
||||||
context.strokeStyle = "#c92a2a";
|
context.strokeStyle = "#c92a2a";
|
||||||
context.lineWidth = 3;
|
context.lineWidth = 3;
|
||||||
context.strokeRect(
|
context.strokeRect(
|
||||||
|
Reference in New Issue
Block a user