mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-11-17 11:14:23 +01:00
feat: Center point with more precise highlight outlines
This commit is contained in:
@@ -31,7 +31,6 @@ import {
|
|||||||
getHoveredElementForBinding,
|
getHoveredElementForBinding,
|
||||||
intersectElementWithLineSegment,
|
intersectElementWithLineSegment,
|
||||||
isBindableElementInsideOtherBindable,
|
isBindableElementInsideOtherBindable,
|
||||||
isPointInElement,
|
|
||||||
} from "./collision";
|
} from "./collision";
|
||||||
import { distanceToElement } from "./distance";
|
import { distanceToElement } from "./distance";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import rough from "roughjs/bin/rough";
|
|
||||||
import {
|
import {
|
||||||
pointFrom,
|
pointFrom,
|
||||||
pointsEqual,
|
pointsEqual,
|
||||||
@@ -17,7 +16,12 @@ import {
|
|||||||
throttleRAF,
|
throttleRAF,
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import { LinearElementEditor, renderElement } from "@excalidraw/element";
|
import {
|
||||||
|
deconstructDiamondElement,
|
||||||
|
deconstructRectanguloidElement,
|
||||||
|
elementCenterPoint,
|
||||||
|
LinearElementEditor,
|
||||||
|
} from "@excalidraw/element";
|
||||||
import {
|
import {
|
||||||
getOmitSidesForDevice,
|
getOmitSidesForDevice,
|
||||||
getTransformHandles,
|
getTransformHandles,
|
||||||
@@ -219,9 +223,17 @@ const renderBindingHighlightForBindableElement = (
|
|||||||
|
|
||||||
context.restore();
|
context.restore();
|
||||||
break;
|
break;
|
||||||
case "image":
|
default:
|
||||||
case "text":
|
|
||||||
context.save();
|
context.save();
|
||||||
|
|
||||||
|
const center = elementCenterPoint(element, allElementsMap);
|
||||||
|
const cx = center[0] + appState.scrollX;
|
||||||
|
const cy = center[1] + appState.scrollY;
|
||||||
|
|
||||||
|
context.translate(cx, cy);
|
||||||
|
context.rotate(element.angle as Radians);
|
||||||
|
context.translate(-cx, -cy);
|
||||||
|
|
||||||
context.translate(
|
context.translate(
|
||||||
element.x + appState.scrollX,
|
element.x + appState.scrollX,
|
||||||
element.y + appState.scrollY,
|
element.y + appState.scrollY,
|
||||||
@@ -231,63 +243,124 @@ const renderBindingHighlightForBindableElement = (
|
|||||||
context.strokeStyle =
|
context.strokeStyle =
|
||||||
appState.theme === THEME.DARK ? "#035da1" : "#6abdfc";
|
appState.theme === THEME.DARK ? "#035da1" : "#6abdfc";
|
||||||
|
|
||||||
context.strokeRect(0, 0, element.width, element.height);
|
switch (element.type) {
|
||||||
context.restore();
|
case "ellipse":
|
||||||
|
context.beginPath();
|
||||||
|
context.ellipse(
|
||||||
|
element.width / 2,
|
||||||
|
element.height / 2,
|
||||||
|
element.width / 2,
|
||||||
|
element.height / 2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2 * Math.PI,
|
||||||
|
);
|
||||||
|
context.closePath();
|
||||||
|
context.stroke();
|
||||||
|
break;
|
||||||
|
case "diamond":
|
||||||
|
{
|
||||||
|
const [segments, curves] = deconstructDiamondElement(element);
|
||||||
|
|
||||||
|
// Draw each line segment individually
|
||||||
|
segments.forEach((segment) => {
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(
|
||||||
|
segment[0][0] - element.x,
|
||||||
|
segment[0][1] - element.y,
|
||||||
|
);
|
||||||
|
context.lineTo(
|
||||||
|
segment[1][0] - element.x,
|
||||||
|
segment[1][1] - element.y,
|
||||||
|
);
|
||||||
|
context.stroke();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw each curve individually (for rounded corners)
|
||||||
|
curves.forEach((curve) => {
|
||||||
|
const [start, control1, control2, end] = curve;
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(start[0] - element.x, start[1] - element.y);
|
||||||
|
context.bezierCurveTo(
|
||||||
|
control1[0] - element.x,
|
||||||
|
control1[1] - element.y,
|
||||||
|
control2[0] - element.x,
|
||||||
|
control2[1] - element.y,
|
||||||
|
end[0] - element.x,
|
||||||
|
end[1] - element.y,
|
||||||
|
);
|
||||||
|
context.stroke();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
renderElement(
|
|
||||||
{
|
{
|
||||||
...element,
|
const [segments, curves] = deconstructRectanguloidElement(element);
|
||||||
strokeColor: appState.theme === THEME.DARK ? "#035da1" : "#6abdfc",
|
|
||||||
fillStyle: "solid",
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
},
|
|
||||||
elementsMap,
|
|
||||||
allElementsMap,
|
|
||||||
rough.canvas(context.canvas),
|
|
||||||
context,
|
|
||||||
{
|
|
||||||
canvasBackgroundColor: "transparent",
|
|
||||||
imageCache: new Map(),
|
|
||||||
renderGrid: false,
|
|
||||||
isExporting: false,
|
|
||||||
embedsValidationStatus: new Map(),
|
|
||||||
elementsPendingErasure: new Set(),
|
|
||||||
pendingFlowchartNodes: null,
|
|
||||||
},
|
|
||||||
appState,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Overdraw the arrow if exists (if there is a suggestedBinding it's an arrow)
|
// Draw each line segment individually
|
||||||
if (appState.selectedLinearElement) {
|
segments.forEach((segment) => {
|
||||||
const arrow = LinearElementEditor.getElement(
|
context.beginPath();
|
||||||
appState.selectedLinearElement.elementId,
|
context.moveTo(
|
||||||
allElementsMap,
|
segment[0][0] - element.x,
|
||||||
|
segment[0][1] - element.y,
|
||||||
);
|
);
|
||||||
|
context.lineTo(
|
||||||
invariant(arrow, "arrow not found during highlight element binding");
|
segment[1][0] - element.x,
|
||||||
|
segment[1][1] - element.y,
|
||||||
renderElement(
|
|
||||||
arrow,
|
|
||||||
elementsMap,
|
|
||||||
allElementsMap,
|
|
||||||
rough.canvas(context.canvas),
|
|
||||||
context,
|
|
||||||
{
|
|
||||||
canvasBackgroundColor: "transparent",
|
|
||||||
imageCache: new Map(),
|
|
||||||
renderGrid: false,
|
|
||||||
isExporting: false,
|
|
||||||
embedsValidationStatus: new Map(),
|
|
||||||
elementsPendingErasure: new Set(),
|
|
||||||
pendingFlowchartNodes: null,
|
|
||||||
},
|
|
||||||
appState,
|
|
||||||
);
|
);
|
||||||
|
context.stroke();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw each curve individually (for rounded corners)
|
||||||
|
curves.forEach((curve) => {
|
||||||
|
const [start, control1, control2, end] = curve;
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(start[0] - element.x, start[1] - element.y);
|
||||||
|
context.bezierCurveTo(
|
||||||
|
control1[0] - element.x,
|
||||||
|
control1[1] - element.y,
|
||||||
|
control2[0] - element.x,
|
||||||
|
control2[1] - element.y,
|
||||||
|
end[0] - element.x,
|
||||||
|
end[1] - element.y,
|
||||||
|
);
|
||||||
|
context.stroke();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.restore();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw center snap area
|
||||||
|
context.save();
|
||||||
|
context.translate(element.x + appState.scrollX, element.y + appState.scrollY);
|
||||||
|
context.strokeStyle = "rgba(0, 0, 0, 0.1)";
|
||||||
|
context.lineWidth = 1 / appState.zoom.value;
|
||||||
|
context.setLineDash([4 / appState.zoom.value, 4 / appState.zoom.value]);
|
||||||
|
context.lineDashOffset = 0;
|
||||||
|
context.fillStyle = "rgba(0, 0, 0, 0.01)";
|
||||||
|
|
||||||
|
const radius = 0.5 * (Math.min(element.width, element.height) / 2);
|
||||||
|
context.beginPath();
|
||||||
|
context.ellipse(
|
||||||
|
element.width / 2,
|
||||||
|
element.height / 2,
|
||||||
|
radius,
|
||||||
|
radius,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2 * Math.PI,
|
||||||
|
);
|
||||||
|
context.stroke();
|
||||||
|
context.fill();
|
||||||
|
|
||||||
|
context.restore();
|
||||||
};
|
};
|
||||||
|
|
||||||
type ElementSelectionBorder = {
|
type ElementSelectionBorder = {
|
||||||
|
|||||||
Reference in New Issue
Block a user