mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-11-18 19:54:35 +01:00
Initial implementation of containerBehavior.margin
This commit is contained in:
@@ -329,16 +329,24 @@ const generateElementCanvas = (
|
||||
boundTextCanvasContext.translate(-shiftX, -shiftY);
|
||||
// Clear the bound text area
|
||||
boundTextCanvasContext.clearRect(
|
||||
-(boundTextElement.width / 2 + BOUND_TEXT_PADDING) *
|
||||
-(
|
||||
boundTextElement.width / 2 +
|
||||
(element.containerBehavior?.margin ?? BOUND_TEXT_PADDING)
|
||||
) *
|
||||
window.devicePixelRatio *
|
||||
scale,
|
||||
-(boundTextElement.height / 2 + BOUND_TEXT_PADDING) *
|
||||
-(
|
||||
boundTextElement.height / 2 +
|
||||
(element.containerBehavior?.margin ?? BOUND_TEXT_PADDING)
|
||||
) *
|
||||
window.devicePixelRatio *
|
||||
scale,
|
||||
(boundTextElement.width + BOUND_TEXT_PADDING * 2) *
|
||||
(boundTextElement.width +
|
||||
(element.containerBehavior?.margin ?? BOUND_TEXT_PADDING) * 2) *
|
||||
window.devicePixelRatio *
|
||||
scale,
|
||||
(boundTextElement.height + BOUND_TEXT_PADDING * 2) *
|
||||
(boundTextElement.height +
|
||||
(element.containerBehavior?.margin ?? BOUND_TEXT_PADDING) * 2) *
|
||||
window.devicePixelRatio *
|
||||
scale,
|
||||
);
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
SHIFT_LOCKING_ANGLE,
|
||||
rescalePoints,
|
||||
getFontString,
|
||||
BOUND_TEXT_PADDING,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import type { GlobalPoint } from "@excalidraw/math";
|
||||
@@ -741,10 +742,12 @@ export const resizeSingleElement = (
|
||||
const minWidth = getApproxMinLineWidth(
|
||||
getFontString(boundTextElement),
|
||||
boundTextElement.lineHeight,
|
||||
latestElement.containerBehavior?.margin ?? BOUND_TEXT_PADDING,
|
||||
);
|
||||
const minHeight = getApproxMinLineHeight(
|
||||
boundTextElement.fontSize,
|
||||
boundTextElement.lineHeight,
|
||||
latestElement.containerBehavior?.margin ?? BOUND_TEXT_PADDING,
|
||||
);
|
||||
nextWidth = Math.max(nextWidth, minWidth);
|
||||
nextHeight = Math.max(nextHeight, minHeight);
|
||||
|
||||
@@ -108,6 +108,7 @@ export const redrawTextBoundingBox = (
|
||||
const nextHeight = computeContainerDimensionForBoundText(
|
||||
metrics.height,
|
||||
container.type,
|
||||
container.containerBehavior?.margin ?? BOUND_TEXT_PADDING,
|
||||
);
|
||||
scene.mutateElement(container, { height: nextHeight });
|
||||
updateOriginalContainerCache(container.id, nextHeight);
|
||||
@@ -117,6 +118,7 @@ export const redrawTextBoundingBox = (
|
||||
const nextWidth = computeContainerDimensionForBoundText(
|
||||
metrics.width,
|
||||
container.type,
|
||||
container.containerBehavior?.margin ?? BOUND_TEXT_PADDING,
|
||||
);
|
||||
scene.mutateElement(container, { width: nextWidth });
|
||||
}
|
||||
@@ -187,6 +189,7 @@ export const handleBindTextResize = (
|
||||
containerHeight = computeContainerDimensionForBoundText(
|
||||
nextHeight,
|
||||
container.type,
|
||||
container.containerBehavior?.margin ?? BOUND_TEXT_PADDING,
|
||||
);
|
||||
|
||||
const diff = containerHeight - container.height;
|
||||
@@ -353,8 +356,8 @@ export const getContainerCenter = (
|
||||
};
|
||||
|
||||
export const getContainerCoords = (container: NonDeletedExcalidrawElement) => {
|
||||
let offsetX = BOUND_TEXT_PADDING;
|
||||
let offsetY = BOUND_TEXT_PADDING;
|
||||
let offsetX = container.containerBehavior?.margin ?? BOUND_TEXT_PADDING;
|
||||
let offsetY = container.containerBehavior?.margin ?? BOUND_TEXT_PADDING;
|
||||
|
||||
if (container.type === "ellipse") {
|
||||
// The derivation of coordinates is explained in https://github.com/excalidraw/excalidraw/pull/6172
|
||||
@@ -446,9 +449,10 @@ export const isValidTextContainer = (element: {
|
||||
export const computeContainerDimensionForBoundText = (
|
||||
dimension: number,
|
||||
containerType: ExtractSetType<typeof VALID_CONTAINER_TYPES>,
|
||||
boundTextPadding: number,
|
||||
) => {
|
||||
dimension = Math.ceil(dimension);
|
||||
const padding = BOUND_TEXT_PADDING * 2;
|
||||
const padding = boundTextPadding * 2;
|
||||
|
||||
if (containerType === "ellipse") {
|
||||
return Math.round(((dimension + padding) / Math.sqrt(2)) * 2);
|
||||
@@ -467,6 +471,8 @@ export const getBoundTextMaxWidth = (
|
||||
boundTextElement: ExcalidrawTextElement | null,
|
||||
) => {
|
||||
const { width } = container;
|
||||
const boundTextPadding =
|
||||
container.containerBehavior?.margin ?? BOUND_TEXT_PADDING;
|
||||
if (isArrowElement(container)) {
|
||||
const minWidth =
|
||||
(boundTextElement?.fontSize ?? DEFAULT_FONT_SIZE) *
|
||||
@@ -477,14 +483,14 @@ export const getBoundTextMaxWidth = (
|
||||
// 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 Math.round((width / 2) * Math.sqrt(2)) - boundTextPadding * 2;
|
||||
}
|
||||
if (container.type === "diamond") {
|
||||
// The width of the largest rectangle inscribed inside a rhombus is
|
||||
// Math.round(width / 2) - https://github.com/excalidraw/excalidraw/pull/6265
|
||||
return Math.round(width / 2) - BOUND_TEXT_PADDING * 2;
|
||||
return Math.round(width / 2) - boundTextPadding * 2;
|
||||
}
|
||||
return width - BOUND_TEXT_PADDING * 2;
|
||||
return width - boundTextPadding * 2;
|
||||
};
|
||||
|
||||
export const getBoundTextMaxHeight = (
|
||||
@@ -492,8 +498,10 @@ export const getBoundTextMaxHeight = (
|
||||
boundTextElement: ExcalidrawTextElementWithContainer,
|
||||
) => {
|
||||
const { height } = container;
|
||||
const boundTextPadding =
|
||||
container.containerBehavior?.margin ?? BOUND_TEXT_PADDING;
|
||||
if (isArrowElement(container)) {
|
||||
const containerHeight = height - BOUND_TEXT_PADDING * 8 * 2;
|
||||
const containerHeight = height - boundTextPadding * 8 * 2;
|
||||
if (containerHeight <= 0) {
|
||||
return boundTextElement.height;
|
||||
}
|
||||
@@ -503,14 +511,14 @@ export const getBoundTextMaxHeight = (
|
||||
// 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 Math.round((height / 2) * Math.sqrt(2)) - boundTextPadding * 2;
|
||||
}
|
||||
if (container.type === "diamond") {
|
||||
// The height of the largest rectangle inscribed inside a rhombus is
|
||||
// Math.round(height / 2) - https://github.com/excalidraw/excalidraw/pull/6265
|
||||
return Math.round(height / 2) - BOUND_TEXT_PADDING * 2;
|
||||
return Math.round(height / 2) - boundTextPadding * 2;
|
||||
}
|
||||
return height - BOUND_TEXT_PADDING * 2;
|
||||
return height - boundTextPadding * 2;
|
||||
};
|
||||
|
||||
/** retrieves text from text elements and concatenates to a single string */
|
||||
|
||||
@@ -32,22 +32,24 @@ const DUMMY_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toLocaleUpperCase();
|
||||
export const getApproxMinLineWidth = (
|
||||
font: FontString,
|
||||
lineHeight: ExcalidrawTextElement["lineHeight"],
|
||||
boundTextPadding: number = BOUND_TEXT_PADDING,
|
||||
) => {
|
||||
const maxCharWidth = getMaxCharWidth(font);
|
||||
if (maxCharWidth === 0) {
|
||||
return (
|
||||
measureText(DUMMY_TEXT.split("").join("\n"), font, lineHeight).width +
|
||||
BOUND_TEXT_PADDING * 2
|
||||
boundTextPadding * 2
|
||||
);
|
||||
}
|
||||
return maxCharWidth + BOUND_TEXT_PADDING * 2;
|
||||
return maxCharWidth + boundTextPadding * 2;
|
||||
};
|
||||
|
||||
export const getMinTextElementWidth = (
|
||||
font: FontString,
|
||||
lineHeight: ExcalidrawTextElement["lineHeight"],
|
||||
boundTextPadding: number = BOUND_TEXT_PADDING,
|
||||
) => {
|
||||
return measureText("", font, lineHeight).width + BOUND_TEXT_PADDING * 2;
|
||||
return measureText("", font, lineHeight).width + boundTextPadding * 2;
|
||||
};
|
||||
|
||||
export const isMeasureTextSupported = () => {
|
||||
@@ -99,8 +101,9 @@ export const getLineHeightInPx = (
|
||||
export const getApproxMinLineHeight = (
|
||||
fontSize: ExcalidrawTextElement["fontSize"],
|
||||
lineHeight: ExcalidrawTextElement["lineHeight"],
|
||||
boundTextPadding: number = BOUND_TEXT_PADDING,
|
||||
) => {
|
||||
return getLineHeightInPx(fontSize, lineHeight) + BOUND_TEXT_PADDING * 2;
|
||||
return getLineHeightInPx(fontSize, lineHeight) + boundTextPadding * 2;
|
||||
};
|
||||
|
||||
let textMetricsProvider: TextMetricsProvider | undefined;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getLineHeight } from "@excalidraw/common";
|
||||
import { BOUND_TEXT_PADDING, getLineHeight } from "@excalidraw/common";
|
||||
import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
||||
|
||||
import { FONT_FAMILY, TEXT_ALIGN, VERTICAL_ALIGN } from "@excalidraw/common";
|
||||
@@ -63,9 +63,13 @@ describe("Test measureText", () => {
|
||||
type: "rectangle",
|
||||
...params,
|
||||
});
|
||||
expect(computeContainerDimensionForBoundText(150, element.type)).toEqual(
|
||||
160,
|
||||
);
|
||||
expect(
|
||||
computeContainerDimensionForBoundText(
|
||||
150,
|
||||
element.type,
|
||||
BOUND_TEXT_PADDING,
|
||||
),
|
||||
).toEqual(160);
|
||||
});
|
||||
|
||||
it("should compute container height correctly for ellipse", () => {
|
||||
@@ -73,9 +77,13 @@ describe("Test measureText", () => {
|
||||
type: "ellipse",
|
||||
...params,
|
||||
});
|
||||
expect(computeContainerDimensionForBoundText(150, element.type)).toEqual(
|
||||
226,
|
||||
);
|
||||
expect(
|
||||
computeContainerDimensionForBoundText(
|
||||
150,
|
||||
element.type,
|
||||
BOUND_TEXT_PADDING,
|
||||
),
|
||||
).toEqual(226);
|
||||
});
|
||||
|
||||
it("should compute container height correctly for diamond", () => {
|
||||
@@ -83,9 +91,13 @@ describe("Test measureText", () => {
|
||||
type: "diamond",
|
||||
...params,
|
||||
});
|
||||
expect(computeContainerDimensionForBoundText(150, element.type)).toEqual(
|
||||
320,
|
||||
);
|
||||
expect(
|
||||
computeContainerDimensionForBoundText(
|
||||
150,
|
||||
element.type,
|
||||
BOUND_TEXT_PADDING,
|
||||
),
|
||||
).toEqual(320);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user