fix: improve text wrapping in ellipse and alignment (#6172)
* fix: improve text wrapping in ellipse * compute height when font properties updated * fix alignment * fix alignment when resizing * fix * ad padding * always compute height when redrawing bounding box and refactor * lint * fix specs * fix * redraw text bounding box when pasted or refreshed * fix * Add specs * fix * restore on font load * add comments
This commit is contained in:
parent
0fcbddda8e
commit
88ff32e9b3
@ -108,6 +108,7 @@ import {
|
|||||||
textWysiwyg,
|
textWysiwyg,
|
||||||
transformElements,
|
transformElements,
|
||||||
updateTextElement,
|
updateTextElement,
|
||||||
|
redrawTextBoundingBox,
|
||||||
} from "../element";
|
} from "../element";
|
||||||
import {
|
import {
|
||||||
bindOrUnbindLinearElement,
|
bindOrUnbindLinearElement,
|
||||||
@ -264,6 +265,7 @@ import {
|
|||||||
getBoundTextElement,
|
getBoundTextElement,
|
||||||
getContainerCenter,
|
getContainerCenter,
|
||||||
getContainerDims,
|
getContainerDims,
|
||||||
|
getContainerElement,
|
||||||
getTextBindableContainerAtPosition,
|
getTextBindableContainerAtPosition,
|
||||||
isValidTextContainer,
|
isValidTextContainer,
|
||||||
} from "../element/textElement";
|
} from "../element/textElement";
|
||||||
@ -1637,6 +1639,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.scene.replaceAllElements(nextElements);
|
this.scene.replaceAllElements(nextElements);
|
||||||
|
|
||||||
|
nextElements.forEach((nextElement) => {
|
||||||
|
if (isTextElement(nextElement) && isBoundToContainer(nextElement)) {
|
||||||
|
const container = getContainerElement(nextElement);
|
||||||
|
redrawTextBoundingBox(nextElement, container);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.history.resumeRecording();
|
this.history.resumeRecording();
|
||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
|
@ -290,6 +290,11 @@ export const getMaxContainerWidth = (container: ExcalidrawElement) => {
|
|||||||
return BOUND_TEXT_PADDING * 8 * 2;
|
return BOUND_TEXT_PADDING * 8 * 2;
|
||||||
}
|
}
|
||||||
return containerWidth;
|
return containerWidth;
|
||||||
|
} else if (container.type === "ellipse") {
|
||||||
|
// The width of the largest rectangle inscribed inside an ellipse is
|
||||||
|
// Math.round((ellipse.width / 2) * Math.sqrt(2)) which is derived from
|
||||||
|
// equation of an ellipse -https://github.com/excalidraw/excalidraw/pull/6172
|
||||||
|
return Math.round((width / 2) * Math.sqrt(2)) - BOUND_TEXT_PADDING * 2;
|
||||||
}
|
}
|
||||||
return width - BOUND_TEXT_PADDING * 2;
|
return width - BOUND_TEXT_PADDING * 2;
|
||||||
};
|
};
|
||||||
@ -306,6 +311,11 @@ export const getMaxContainerHeight = (container: ExcalidrawElement) => {
|
|||||||
return BOUND_TEXT_PADDING * 8 * 2;
|
return BOUND_TEXT_PADDING * 8 * 2;
|
||||||
}
|
}
|
||||||
return height;
|
return height;
|
||||||
|
} else if (container.type === "ellipse") {
|
||||||
|
// The height of the largest rectangle inscribed inside an ellipse is
|
||||||
|
// Math.round((ellipse.height / 2) * Math.sqrt(2)) which is derived from
|
||||||
|
// equation of an ellipse - https://github.com/excalidraw/excalidraw/pull/6172
|
||||||
|
return Math.round((height / 2) * Math.sqrt(2)) - BOUND_TEXT_PADDING * 2;
|
||||||
}
|
}
|
||||||
return height - BOUND_TEXT_PADDING * 2;
|
return height - BOUND_TEXT_PADDING * 2;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { BOUND_TEXT_PADDING } from "../constants";
|
import { BOUND_TEXT_PADDING } from "../constants";
|
||||||
import { measureText, wrapText } from "./textElement";
|
import { API } from "../tests/helpers/api";
|
||||||
|
import {
|
||||||
|
computeContainerHeightForBoundText,
|
||||||
|
getContainerCoords,
|
||||||
|
measureText,
|
||||||
|
wrapText,
|
||||||
|
} from "./textElement";
|
||||||
import { FontString } from "./types";
|
import { FontString } from "./types";
|
||||||
|
|
||||||
describe("Test wrapText", () => {
|
describe("Test wrapText", () => {
|
||||||
@ -193,4 +199,49 @@ describe("Test measureText", () => {
|
|||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Test getContainerCoords", () => {
|
||||||
|
const params = { width: 200, height: 100, x: 10, y: 20 };
|
||||||
|
it("should compute coords correctly when ellipse", () => {
|
||||||
|
const ellipse = API.createElement({
|
||||||
|
type: "ellipse",
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
expect(getContainerCoords(ellipse)).toEqual({
|
||||||
|
x: 44.2893218813452455,
|
||||||
|
y: 39.64466094067262,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("should compute coords correctly when rectangle", () => {
|
||||||
|
const rectangle = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
expect(getContainerCoords(rectangle)).toEqual({
|
||||||
|
x: 10,
|
||||||
|
y: 20,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Test computeContainerHeightForBoundText", () => {
|
||||||
|
const params = {
|
||||||
|
width: 178,
|
||||||
|
height: 194,
|
||||||
|
};
|
||||||
|
it("should compute container height correctly for rectangle", () => {
|
||||||
|
const element = API.createElement({
|
||||||
|
type: "rectangle",
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
expect(computeContainerHeightForBoundText(element, 150)).toEqual(160);
|
||||||
|
});
|
||||||
|
it("should compute container height correctly for ellipse", () => {
|
||||||
|
const element = API.createElement({
|
||||||
|
type: "ellipse",
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
expect(computeContainerHeightForBoundText(element, 150)).toEqual(212);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -44,68 +44,69 @@ export const redrawTextBoundingBox = (
|
|||||||
container: ExcalidrawElement | null,
|
container: ExcalidrawElement | null,
|
||||||
) => {
|
) => {
|
||||||
let maxWidth = undefined;
|
let maxWidth = undefined;
|
||||||
let text = textElement.text;
|
|
||||||
|
const boundTextUpdates = {
|
||||||
|
x: textElement.x,
|
||||||
|
y: textElement.y,
|
||||||
|
text: textElement.text,
|
||||||
|
width: textElement.width,
|
||||||
|
height: textElement.height,
|
||||||
|
baseline: textElement.baseline,
|
||||||
|
};
|
||||||
|
|
||||||
|
boundTextUpdates.text = textElement.text;
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
maxWidth = getMaxContainerWidth(container);
|
maxWidth = getMaxContainerWidth(container);
|
||||||
text = wrapText(
|
boundTextUpdates.text = wrapText(
|
||||||
textElement.originalText,
|
textElement.originalText,
|
||||||
getFontString(textElement),
|
getFontString(textElement),
|
||||||
maxWidth,
|
maxWidth,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const metrics = measureText(text, getFontString(textElement), maxWidth);
|
const metrics = measureText(
|
||||||
let coordY = textElement.y;
|
boundTextUpdates.text,
|
||||||
let coordX = textElement.x;
|
getFontString(textElement),
|
||||||
// Resize container and vertically center align the text
|
maxWidth,
|
||||||
|
);
|
||||||
|
|
||||||
|
boundTextUpdates.width = metrics.width;
|
||||||
|
boundTextUpdates.height = metrics.height;
|
||||||
|
boundTextUpdates.baseline = metrics.baseline;
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
if (!isArrowElement(container)) {
|
if (isArrowElement(container)) {
|
||||||
const containerDims = getContainerDims(container);
|
|
||||||
let nextHeight = containerDims.height;
|
|
||||||
if (textElement.verticalAlign === VERTICAL_ALIGN.TOP) {
|
|
||||||
coordY = container.y;
|
|
||||||
} else if (textElement.verticalAlign === VERTICAL_ALIGN.BOTTOM) {
|
|
||||||
coordY =
|
|
||||||
container.y +
|
|
||||||
containerDims.height -
|
|
||||||
metrics.height -
|
|
||||||
BOUND_TEXT_PADDING;
|
|
||||||
} else {
|
|
||||||
coordY = container.y + containerDims.height / 2 - metrics.height / 2;
|
|
||||||
if (metrics.height > getMaxContainerHeight(container)) {
|
|
||||||
nextHeight = metrics.height + BOUND_TEXT_PADDING * 2;
|
|
||||||
coordY = container.y + nextHeight / 2 - metrics.height / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (textElement.textAlign === TEXT_ALIGN.LEFT) {
|
|
||||||
coordX = container.x + BOUND_TEXT_PADDING;
|
|
||||||
} else if (textElement.textAlign === TEXT_ALIGN.RIGHT) {
|
|
||||||
coordX =
|
|
||||||
container.x +
|
|
||||||
containerDims.width -
|
|
||||||
metrics.width -
|
|
||||||
BOUND_TEXT_PADDING;
|
|
||||||
} else {
|
|
||||||
coordX = container.x + containerDims.width / 2 - metrics.width / 2;
|
|
||||||
}
|
|
||||||
updateOriginalContainerCache(container.id, nextHeight);
|
|
||||||
mutateElement(container, { height: nextHeight });
|
|
||||||
} else {
|
|
||||||
const centerX = textElement.x + textElement.width / 2;
|
const centerX = textElement.x + textElement.width / 2;
|
||||||
const centerY = textElement.y + textElement.height / 2;
|
const centerY = textElement.y + textElement.height / 2;
|
||||||
const diffWidth = metrics.width - textElement.width;
|
const diffWidth = metrics.width - textElement.width;
|
||||||
const diffHeight = metrics.height - textElement.height;
|
const diffHeight = metrics.height - textElement.height;
|
||||||
coordY = centerY - (textElement.height + diffHeight) / 2;
|
boundTextUpdates.x = centerY - (textElement.height + diffHeight) / 2;
|
||||||
coordX = centerX - (textElement.width + diffWidth) / 2;
|
boundTextUpdates.y = centerX - (textElement.width + diffWidth) / 2;
|
||||||
|
} else {
|
||||||
|
const containerDims = getContainerDims(container);
|
||||||
|
let maxContainerHeight = getMaxContainerHeight(container);
|
||||||
|
|
||||||
|
let nextHeight = containerDims.height;
|
||||||
|
if (metrics.height > maxContainerHeight) {
|
||||||
|
nextHeight = computeContainerHeightForBoundText(
|
||||||
|
container,
|
||||||
|
metrics.height,
|
||||||
|
);
|
||||||
|
mutateElement(container, { height: nextHeight });
|
||||||
|
maxContainerHeight = getMaxContainerHeight(container);
|
||||||
|
updateOriginalContainerCache(container.id, nextHeight);
|
||||||
|
}
|
||||||
|
const updatedTextElement = {
|
||||||
|
...textElement,
|
||||||
|
...boundTextUpdates,
|
||||||
|
} as ExcalidrawTextElementWithContainer;
|
||||||
|
const { x, y } = computeBoundTextPosition(container, updatedTextElement);
|
||||||
|
boundTextUpdates.x = x;
|
||||||
|
boundTextUpdates.y = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutateElement(textElement, {
|
|
||||||
width: metrics.width,
|
mutateElement(textElement, boundTextUpdates);
|
||||||
height: metrics.height,
|
|
||||||
baseline: metrics.baseline,
|
|
||||||
y: coordY,
|
|
||||||
x: coordX,
|
|
||||||
text,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bindTextToShapeAfterDuplication = (
|
export const bindTextToShapeAfterDuplication = (
|
||||||
@ -197,7 +198,11 @@ export const handleBindTextResize = (
|
|||||||
}
|
}
|
||||||
// increase height in case text element height exceeds
|
// increase height in case text element height exceeds
|
||||||
if (nextHeight > maxHeight) {
|
if (nextHeight > maxHeight) {
|
||||||
containerHeight = nextHeight + getBoundTextElementOffset(textElement) * 2;
|
containerHeight = computeContainerHeightForBoundText(
|
||||||
|
container,
|
||||||
|
nextHeight,
|
||||||
|
);
|
||||||
|
|
||||||
const diff = containerHeight - containerDims.height;
|
const diff = containerHeight - containerDims.height;
|
||||||
// fix the y coord when resizing from ne/nw/n
|
// fix the y coord when resizing from ne/nw/n
|
||||||
const updatedY =
|
const updatedY =
|
||||||
@ -217,48 +222,57 @@ export const handleBindTextResize = (
|
|||||||
text,
|
text,
|
||||||
width: nextWidth,
|
width: nextWidth,
|
||||||
height: nextHeight,
|
height: nextHeight,
|
||||||
|
|
||||||
baseline: nextBaseLine,
|
baseline: nextBaseLine,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isArrowElement(container)) {
|
if (!isArrowElement(container)) {
|
||||||
updateBoundTextPosition(
|
mutateElement(
|
||||||
container,
|
textElement,
|
||||||
textElement as ExcalidrawTextElementWithContainer,
|
computeBoundTextPosition(
|
||||||
|
container,
|
||||||
|
textElement as ExcalidrawTextElementWithContainer,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateBoundTextPosition = (
|
const computeBoundTextPosition = (
|
||||||
container: ExcalidrawElement,
|
container: ExcalidrawElement,
|
||||||
boundTextElement: ExcalidrawTextElementWithContainer,
|
boundTextElement: ExcalidrawTextElementWithContainer,
|
||||||
) => {
|
) => {
|
||||||
const containerDims = getContainerDims(container);
|
const containerCoords = getContainerCoords(container);
|
||||||
const boundTextElementPadding = getBoundTextElementOffset(boundTextElement);
|
const maxContainerHeight = getMaxContainerHeight(container);
|
||||||
|
const maxContainerWidth = getMaxContainerWidth(container);
|
||||||
|
const padding = container.type === "ellipse" ? 0 : BOUND_TEXT_PADDING;
|
||||||
|
|
||||||
|
let x;
|
||||||
let y;
|
let y;
|
||||||
if (boundTextElement.verticalAlign === VERTICAL_ALIGN.TOP) {
|
if (boundTextElement.verticalAlign === VERTICAL_ALIGN.TOP) {
|
||||||
y = container.y + boundTextElementPadding;
|
y = containerCoords.y + padding;
|
||||||
} else if (boundTextElement.verticalAlign === VERTICAL_ALIGN.BOTTOM) {
|
} else if (boundTextElement.verticalAlign === VERTICAL_ALIGN.BOTTOM) {
|
||||||
y =
|
y =
|
||||||
container.y +
|
containerCoords.y +
|
||||||
containerDims.height -
|
(maxContainerHeight - boundTextElement.height + padding);
|
||||||
boundTextElement.height -
|
|
||||||
boundTextElementPadding;
|
|
||||||
} else {
|
} else {
|
||||||
y = container.y + containerDims.height / 2 - boundTextElement.height / 2;
|
y =
|
||||||
|
containerCoords.y +
|
||||||
|
(maxContainerHeight / 2 - boundTextElement.height / 2 + padding);
|
||||||
}
|
}
|
||||||
const x =
|
if (boundTextElement.textAlign === TEXT_ALIGN.LEFT) {
|
||||||
boundTextElement.textAlign === TEXT_ALIGN.LEFT
|
x = containerCoords.x + padding;
|
||||||
? container.x + boundTextElementPadding
|
} else if (boundTextElement.textAlign === TEXT_ALIGN.RIGHT) {
|
||||||
: boundTextElement.textAlign === TEXT_ALIGN.RIGHT
|
x =
|
||||||
? container.x +
|
containerCoords.x +
|
||||||
containerDims.width -
|
(maxContainerWidth - boundTextElement.width + padding);
|
||||||
boundTextElement.width -
|
} else {
|
||||||
boundTextElementPadding
|
x =
|
||||||
: container.x + containerDims.width / 2 - boundTextElement.width / 2;
|
containerCoords.x +
|
||||||
|
(maxContainerWidth / 2 - boundTextElement.width / 2 + padding);
|
||||||
mutateElement(boundTextElement, { x, y });
|
}
|
||||||
|
return { x, y };
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://github.com/grassator/canvas-text-editor/blob/master/lib/FontMetrics.js
|
// https://github.com/grassator/canvas-text-editor/blob/master/lib/FontMetrics.js
|
||||||
export const measureText = (
|
export const measureText = (
|
||||||
text: string,
|
text: string,
|
||||||
@ -621,6 +635,24 @@ export const getContainerCenter = (
|
|||||||
return { x: midSegmentMidpoint[0], y: midSegmentMidpoint[1] };
|
return { x: midSegmentMidpoint[0], y: midSegmentMidpoint[1] };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getContainerCoords = (container: NonDeletedExcalidrawElement) => {
|
||||||
|
if (container.type === "ellipse") {
|
||||||
|
// The derivation of coordinates is explained in https://github.com/excalidraw/excalidraw/pull/6172
|
||||||
|
const offsetX =
|
||||||
|
(container.width / 2) * (1 - Math.sqrt(2) / 2) + BOUND_TEXT_PADDING;
|
||||||
|
const offsetY =
|
||||||
|
(container.height / 2) * (1 - Math.sqrt(2) / 2) + BOUND_TEXT_PADDING;
|
||||||
|
return {
|
||||||
|
x: container.x + offsetX,
|
||||||
|
y: container.y + offsetY,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
x: container.x,
|
||||||
|
y: container.y,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
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)) {
|
||||||
@ -633,12 +665,13 @@ export const getBoundTextElementOffset = (
|
|||||||
boundTextElement: ExcalidrawTextElement | null,
|
boundTextElement: ExcalidrawTextElement | null,
|
||||||
) => {
|
) => {
|
||||||
const container = getContainerElement(boundTextElement);
|
const container = getContainerElement(boundTextElement);
|
||||||
if (!container) {
|
if (!container || !boundTextElement) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (isArrowElement(container)) {
|
if (isArrowElement(container)) {
|
||||||
return BOUND_TEXT_PADDING * 8;
|
return BOUND_TEXT_PADDING * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BOUND_TEXT_PADDING;
|
return BOUND_TEXT_PADDING;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -723,3 +756,16 @@ export const isValidTextContainer = (element: ExcalidrawElement) => {
|
|||||||
isArrowElement(element)
|
isArrowElement(element)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const computeContainerHeightForBoundText = (
|
||||||
|
container: NonDeletedExcalidrawElement,
|
||||||
|
boundTextElementHeight: number,
|
||||||
|
) => {
|
||||||
|
if (container.type === "ellipse") {
|
||||||
|
return Math.round((boundTextElementHeight / Math.sqrt(2)) * 2);
|
||||||
|
}
|
||||||
|
if (isArrowElement(container)) {
|
||||||
|
return boundTextElementHeight + BOUND_TEXT_PADDING * 8 * 2;
|
||||||
|
}
|
||||||
|
return boundTextElementHeight + BOUND_TEXT_PADDING * 2;
|
||||||
|
};
|
||||||
|
@ -791,9 +791,7 @@ describe("textWysiwyg", () => {
|
|||||||
text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||||
expect(text.text).toBe("Hello \nWorld!");
|
expect(text.text).toBe("Hello \nWorld!");
|
||||||
expect(text.originalText).toBe("Hello World!");
|
expect(text.originalText).toBe("Hello World!");
|
||||||
expect(text.y).toBe(
|
expect(text.y).toBe(27.5);
|
||||||
rectangle.y + rectangle.height / 2 - (APPROX_LINE_HEIGHT * 2) / 2,
|
|
||||||
);
|
|
||||||
expect(text.x).toBe(rectangle.x + BOUND_TEXT_PADDING);
|
expect(text.x).toBe(rectangle.x + BOUND_TEXT_PADDING);
|
||||||
expect(text.height).toBe(APPROX_LINE_HEIGHT * 2);
|
expect(text.height).toBe(APPROX_LINE_HEIGHT * 2);
|
||||||
expect(text.width).toBe(rectangle.width - BOUND_TEXT_PADDING * 2);
|
expect(text.width).toBe(rectangle.width - BOUND_TEXT_PADDING * 2);
|
||||||
@ -827,9 +825,7 @@ describe("textWysiwyg", () => {
|
|||||||
|
|
||||||
expect(text.text).toBe("Hello");
|
expect(text.text).toBe("Hello");
|
||||||
expect(text.originalText).toBe("Hello");
|
expect(text.originalText).toBe("Hello");
|
||||||
expect(text.y).toBe(
|
expect(text.y).toBe(40);
|
||||||
rectangle.y + rectangle.height / 2 - APPROX_LINE_HEIGHT / 2,
|
|
||||||
);
|
|
||||||
expect(text.x).toBe(rectangle.x + BOUND_TEXT_PADDING);
|
expect(text.x).toBe(rectangle.x + BOUND_TEXT_PADDING);
|
||||||
expect(text.height).toBe(APPROX_LINE_HEIGHT);
|
expect(text.height).toBe(APPROX_LINE_HEIGHT);
|
||||||
expect(text.width).toBe(rectangle.width - BOUND_TEXT_PADDING * 2);
|
expect(text.width).toBe(rectangle.width - BOUND_TEXT_PADDING * 2);
|
||||||
@ -1248,7 +1244,7 @@ describe("textWysiwyg", () => {
|
|||||||
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
15,
|
15,
|
||||||
20,
|
25,
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
@ -1259,7 +1255,7 @@ describe("textWysiwyg", () => {
|
|||||||
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
94.5,
|
94.5,
|
||||||
20,
|
25,
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
@ -1269,22 +1265,22 @@ describe("textWysiwyg", () => {
|
|||||||
fireEvent.click(screen.getByTitle("Align top"));
|
fireEvent.click(screen.getByTitle("Align top"));
|
||||||
|
|
||||||
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
174,
|
174,
|
||||||
20,
|
25,
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when center left", async () => {
|
it("when center left", async () => {
|
||||||
fireEvent.click(screen.getByTitle("Center vertically"));
|
fireEvent.click(screen.getByTitle("Center vertically"));
|
||||||
fireEvent.click(screen.getByTitle("Left"));
|
fireEvent.click(screen.getByTitle("Left"));
|
||||||
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
15,
|
15,
|
||||||
25,
|
20,
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when center center", async () => {
|
it("when center center", async () => {
|
||||||
@ -1292,11 +1288,11 @@ describe("textWysiwyg", () => {
|
|||||||
fireEvent.click(screen.getByTitle("Center vertically"));
|
fireEvent.click(screen.getByTitle("Center vertically"));
|
||||||
|
|
||||||
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
-25,
|
-25,
|
||||||
25,
|
20,
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when center right", async () => {
|
it("when center right", async () => {
|
||||||
@ -1304,11 +1300,11 @@ describe("textWysiwyg", () => {
|
|||||||
fireEvent.click(screen.getByTitle("Center vertically"));
|
fireEvent.click(screen.getByTitle("Center vertically"));
|
||||||
|
|
||||||
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
174,
|
174,
|
||||||
25,
|
20,
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when bottom left", async () => {
|
it("when bottom left", async () => {
|
||||||
|
@ -25,6 +25,7 @@ import {
|
|||||||
getApproxLineHeight,
|
getApproxLineHeight,
|
||||||
getBoundTextElementId,
|
getBoundTextElementId,
|
||||||
getBoundTextElementOffset,
|
getBoundTextElementOffset,
|
||||||
|
getContainerCoords,
|
||||||
getContainerDims,
|
getContainerDims,
|
||||||
getContainerElement,
|
getContainerElement,
|
||||||
getTextElementAngle,
|
getTextElementAngle,
|
||||||
@ -230,19 +231,22 @@ 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 padding =
|
||||||
|
container.type === "ellipse"
|
||||||
|
? 0
|
||||||
|
: getBoundTextElementOffset(updatedTextElement);
|
||||||
|
const containerCoords = getContainerCoords(container);
|
||||||
|
|
||||||
// vertically center align the text
|
// vertically center align the text
|
||||||
if (verticalAlign === VERTICAL_ALIGN.MIDDLE) {
|
if (verticalAlign === VERTICAL_ALIGN.MIDDLE) {
|
||||||
if (!isArrowElement(container)) {
|
if (!isArrowElement(container)) {
|
||||||
coordY =
|
coordY =
|
||||||
container.y + containerDims.height / 2 - textElementHeight / 2;
|
containerCoords.y + maxHeight / 2 - textElementHeight / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (verticalAlign === VERTICAL_ALIGN.BOTTOM) {
|
if (verticalAlign === VERTICAL_ALIGN.BOTTOM) {
|
||||||
coordY =
|
coordY =
|
||||||
container.y +
|
containerCoords.y + (maxHeight - textElementHeight + padding);
|
||||||
containerDims.height -
|
|
||||||
textElementHeight -
|
|
||||||
getBoundTextElementOffset(updatedTextElement);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user