Rectangle highlight

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs 2025-05-02 16:36:15 +02:00
parent 086d012b05
commit 7275263686
No known key found for this signature in database

View file

@ -17,7 +17,10 @@ import {
throttleRAF, throttleRAF,
} from "@excalidraw/common"; } from "@excalidraw/common";
import { maxBindingGap } from "@excalidraw/element/binding"; import {
FIXED_BINDING_DISTANCE,
maxBindingGap,
} from "@excalidraw/element/binding";
import { LinearElementEditor } from "@excalidraw/element/linearElementEditor"; import { LinearElementEditor } from "@excalidraw/element/linearElementEditor";
import { import {
getOmitSidesForDevice, getOmitSidesForDevice,
@ -69,6 +72,7 @@ import type {
ExcalidrawFrameLikeElement, ExcalidrawFrameLikeElement,
ExcalidrawImageElement, ExcalidrawImageElement,
ExcalidrawLinearElement, ExcalidrawLinearElement,
ExcalidrawRectanguloidElement,
ExcalidrawTextElement, ExcalidrawTextElement,
GroupId, GroupId,
NonDeleted, NonDeleted,
@ -161,6 +165,186 @@ const highlightPoint = <Point extends LocalPoint | GlobalPoint>(
); );
}; };
const drawHighlightForRectWithRotation = (
context: CanvasRenderingContext2D,
element: ExcalidrawRectanguloidElement,
padding: number,
) => {
const [x, y] = pointRotateRads(
pointFrom<GlobalPoint>(element.x, element.y),
elementCenterPoint(element),
element.angle,
);
context.save();
context.translate(x, y);
context.rotate(element.angle);
const radius = getCornerRadius(
Math.min(element.width, element.height),
element,
);
context.beginPath();
// {
// const topLeftApprox = offsetBezier(
// pointFrom(0, 0 + radius),
// pointFrom(0, 0),
// pointFrom(0, 0),
// pointFrom(0 + radius, 0),
// padding,
// );
// const topRightApprox = offsetBezier(
// pointFrom(element.width - radius, 0),
// pointFrom(element.width, 0),
// pointFrom(element.width, 0),
// pointFrom(element.width, radius),
// padding,
// );
// const bottomRightApprox = offsetBezier(
// pointFrom(element.width, element.height - radius),
// pointFrom(element.width, element.height),
// pointFrom(element.width, element.height),
// pointFrom(element.width - radius, element.height),
// padding,
// );
// const bottomLeftApprox = offsetBezier(
// pointFrom(radius, element.height),
// pointFrom(0, element.height),
// pointFrom(0, element.height),
// pointFrom(0, element.height - radius),
// padding,
// );
// context.moveTo(
// topLeftApprox[topLeftApprox.length - 1][0],
// topLeftApprox[topLeftApprox.length - 1][1],
// );
// context.lineTo(topRightApprox[0][0], topRightApprox[0][1]);
// drawCatmullRom(context, topRightApprox);
// context.lineTo(bottomRightApprox[0][0], bottomRightApprox[0][1]);
// drawCatmullRom(context, bottomRightApprox);
// context.lineTo(bottomLeftApprox[0][0], bottomLeftApprox[0][1]);
// drawCatmullRom(context, bottomLeftApprox);
// context.lineTo(topLeftApprox[0][0], topLeftApprox[0][1]);
// drawCatmullRom(context, topLeftApprox);
// }
context.moveTo(-padding + radius, -padding);
context.lineTo(element.width + padding - radius, -padding);
context.quadraticCurveTo(
element.width + padding,
-padding,
element.width + padding,
-padding + radius,
);
context.lineTo(element.width + padding, element.height + padding - radius);
context.quadraticCurveTo(
element.width + padding,
element.height + padding,
element.width + padding - radius,
element.height + padding,
);
context.lineTo(-padding + radius, element.height + padding);
context.quadraticCurveTo(
-padding,
element.height + padding,
-padding,
element.height + padding - radius,
);
context.lineTo(-padding, -padding + radius);
context.quadraticCurveTo(-padding, -padding, -padding + radius, -padding);
context.moveTo(-FIXED_BINDING_DISTANCE + radius, -FIXED_BINDING_DISTANCE);
context.quadraticCurveTo(
-FIXED_BINDING_DISTANCE,
-FIXED_BINDING_DISTANCE,
-FIXED_BINDING_DISTANCE,
-FIXED_BINDING_DISTANCE + radius,
);
context.lineTo(
-FIXED_BINDING_DISTANCE,
element.height + FIXED_BINDING_DISTANCE - radius,
);
context.quadraticCurveTo(
-FIXED_BINDING_DISTANCE,
element.height + FIXED_BINDING_DISTANCE,
-FIXED_BINDING_DISTANCE + radius,
element.height + FIXED_BINDING_DISTANCE,
);
context.lineTo(
element.width + FIXED_BINDING_DISTANCE - radius,
element.height + FIXED_BINDING_DISTANCE,
);
context.quadraticCurveTo(
element.width + FIXED_BINDING_DISTANCE,
element.height + FIXED_BINDING_DISTANCE,
element.width + FIXED_BINDING_DISTANCE,
element.height + FIXED_BINDING_DISTANCE - radius,
);
context.lineTo(
element.width + FIXED_BINDING_DISTANCE,
-FIXED_BINDING_DISTANCE + radius,
);
context.quadraticCurveTo(
element.width + FIXED_BINDING_DISTANCE,
-FIXED_BINDING_DISTANCE,
element.width + FIXED_BINDING_DISTANCE - radius,
-FIXED_BINDING_DISTANCE,
);
context.lineTo(-FIXED_BINDING_DISTANCE + radius, -FIXED_BINDING_DISTANCE);
// {
// const topLeftApprox = offsetBezier(
// pointFrom(0 + radius, 0),
// pointFrom(0, 0),
// pointFrom(0, 0),
// pointFrom(0, 0 + radius),
// -FIXED_BINDING_DISTANCE,
// );
// const topRightApprox = offsetBezier(
// pointFrom(element.width, radius),
// pointFrom(element.width, 0),
// pointFrom(element.width, 0),
// pointFrom(element.width - radius, 0),
// -FIXED_BINDING_DISTANCE,
// );
// const bottomRightApprox = offsetBezier(
// pointFrom(element.width - radius, element.height),
// pointFrom(element.width, element.height),
// pointFrom(element.width, element.height),
// pointFrom(element.width, element.height - radius),
// -FIXED_BINDING_DISTANCE,
// );
// const bottomLeftApprox = offsetBezier(
// pointFrom(0, element.height - radius),
// pointFrom(0, element.height),
// pointFrom(0, element.height),
// pointFrom(radius, element.height),
// -FIXED_BINDING_DISTANCE,
// );
// context.moveTo(
// topLeftApprox[topLeftApprox.length - 1][0],
// topLeftApprox[topLeftApprox.length - 1][1],
// );
// context.lineTo(bottomLeftApprox[0][0], bottomLeftApprox[0][1]);
// drawCatmullRom(context, bottomLeftApprox);
// context.lineTo(bottomRightApprox[0][0], bottomRightApprox[0][1]);
// drawCatmullRom(context, bottomRightApprox);
// context.lineTo(topRightApprox[0][0], topRightApprox[0][1]);
// drawCatmullRom(context, topRightApprox);
// context.lineTo(topLeftApprox[0][0], topLeftApprox[0][1]);
// drawCatmullRom(context, topLeftApprox);
// }
context.closePath();
context.fill();
context.restore();
};
const strokeRectWithRotation = ( const strokeRectWithRotation = (
context: CanvasRenderingContext2D, context: CanvasRenderingContext2D,
x: number, x: number,
@ -276,28 +460,28 @@ const strokeDiamondWithRotation = (
pointFrom(topX, topY), pointFrom(topX, topY),
pointFrom(topX, topY), pointFrom(topX, topY),
pointFrom(topX - verticalRadius, topY + horizontalRadius), pointFrom(topX - verticalRadius, topY + horizontalRadius),
-5, -FIXED_BINDING_DISTANCE,
); );
const rightApprox = offsetBezier( const rightApprox = offsetBezier(
pointFrom(rightX - verticalRadius, rightY + horizontalRadius), pointFrom(rightX - verticalRadius, rightY + horizontalRadius),
pointFrom(rightX, rightY), pointFrom(rightX, rightY),
pointFrom(rightX, rightY), pointFrom(rightX, rightY),
pointFrom(rightX - verticalRadius, rightY - horizontalRadius), pointFrom(rightX - verticalRadius, rightY - horizontalRadius),
-5, -FIXED_BINDING_DISTANCE,
); );
const bottomApprox = offsetBezier( const bottomApprox = offsetBezier(
pointFrom(bottomX - verticalRadius, bottomY - horizontalRadius), pointFrom(bottomX - verticalRadius, bottomY - horizontalRadius),
pointFrom(bottomX, bottomY), pointFrom(bottomX, bottomY),
pointFrom(bottomX, bottomY), pointFrom(bottomX, bottomY),
pointFrom(bottomX + verticalRadius, bottomY - horizontalRadius), pointFrom(bottomX + verticalRadius, bottomY - horizontalRadius),
-5, -FIXED_BINDING_DISTANCE,
); );
const leftApprox = offsetBezier( const leftApprox = offsetBezier(
pointFrom(leftX + verticalRadius, leftY - horizontalRadius), pointFrom(leftX + verticalRadius, leftY - horizontalRadius),
pointFrom(leftX, leftY), pointFrom(leftX, leftY),
pointFrom(leftX, leftY), pointFrom(leftX, leftY),
pointFrom(leftX + verticalRadius, leftY + horizontalRadius), pointFrom(leftX + verticalRadius, leftY + horizontalRadius),
-5, -FIXED_BINDING_DISTANCE,
); );
context.moveTo( context.moveTo(
@ -378,12 +562,6 @@ const renderBindingHighlightForBindableElement = (
); );
// To ensure the binding highlight doesn't overlap the element itself // To ensure the binding highlight doesn't overlap the element itself
const padding = maxBindingGap(element, element.width, element.height, zoom); const padding = maxBindingGap(element, element.width, element.height, zoom);
//context.lineWidth / 2 + BINDING_HIGHLIGHT_OFFSET;
const radius = getCornerRadius(
Math.min(element.width, element.height),
element,
);
switch (element.type) { switch (element.type) {
case "rectangle": case "rectangle":
@ -393,18 +571,7 @@ const renderBindingHighlightForBindableElement = (
case "embeddable": case "embeddable":
case "frame": case "frame":
case "magicframe": case "magicframe":
strokeRectWithRotation( drawHighlightForRectWithRotation(context, element, padding);
context,
x1 - padding,
y1 - padding,
width + padding * 2,
height + padding * 2,
x1 + width / 2,
y1 + height / 2,
element.angle,
undefined,
radius,
);
break; break;
case "diamond": case "diamond":
strokeDiamondWithRotation(context, padding, element); strokeDiamondWithRotation(context, padding, element);