Преглед на файлове

feat: Common elbow mid segments (#8440)

Common start or end segment length for elbow arrows regardless of arrowhead is present
Márk Tolmács преди 11 месеца
родител
ревизия
c07f5a0c80

+ 6 - 1
excalidraw-app/App.tsx

@@ -649,7 +649,12 @@ const ExcalidrawWrapper = () => {
 
     // Render the debug scene if the debug canvas is available
     if (debugCanvasRef.current && excalidrawAPI) {
-      debugRenderer(debugCanvasRef.current, appState, window.devicePixelRatio);
+      debugRenderer(
+        debugCanvasRef.current,
+        appState,
+        window.devicePixelRatio,
+        () => forceRefresh((prev) => !prev),
+      );
     }
   };
 

+ 12 - 2
excalidraw-app/components/DebugCanvas.tsx

@@ -68,12 +68,17 @@ const _debugRenderer = (
   canvas: HTMLCanvasElement,
   appState: AppState,
   scale: number,
+  refresh: () => void,
 ) => {
   const [normalizedWidth, normalizedHeight] = getNormalizedCanvasDimensions(
     canvas,
     scale,
   );
 
+  if (appState.height !== canvas.height || appState.width !== canvas.width) {
+    refresh();
+  }
+
   const context = bootstrapCanvas({
     canvas,
     scale,
@@ -138,8 +143,13 @@ export const saveDebugState = (debug: { enabled: boolean }) => {
 };
 
 export const debugRenderer = throttleRAF(
-  (canvas: HTMLCanvasElement, appState: AppState, scale: number) => {
-    _debugRenderer(canvas, appState, scale);
+  (
+    canvas: HTMLCanvasElement,
+    appState: AppState,
+    scale: number,
+    refresh: () => void,
+  ) => {
+    _debugRenderer(canvas, appState, scale, refresh);
   },
   { trailing: true },
 );

+ 13 - 12
packages/excalidraw/element/routing.test.tsx

@@ -94,7 +94,16 @@ describe("elbow arrow routing", () => {
 
 describe("elbow arrow ui", () => {
   beforeEach(async () => {
+    localStorage.clear();
     await render(<Excalidraw handleKeyboardGlobally={true} />);
+
+    fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
+      button: 2,
+      clientX: 1,
+      clientY: 1,
+    });
+    const contextMenu = UI.queryContextMenu();
+    fireEvent.click(queryByTestId(contextMenu!, "stats")!);
   });
 
   it("can follow bound shapes", async () => {
@@ -130,8 +139,8 @@ describe("elbow arrow ui", () => {
     expect(arrow.elbowed).toBe(true);
     expect(arrow.points).toEqual([
       [0, 0],
-      [35, 0],
-      [35, 200],
+      [45, 0],
+      [45, 200],
       [90, 200],
     ]);
   });
@@ -163,14 +172,6 @@ describe("elbow arrow ui", () => {
       h.state,
     )[0] as ExcalidrawArrowElement;
 
-    fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
-      button: 2,
-      clientX: 1,
-      clientY: 1,
-    });
-    const contextMenu = UI.queryContextMenu();
-    fireEvent.click(queryByTestId(contextMenu!, "stats")!);
-
     mouse.click(51, 51);
 
     const inputAngle = UI.queryStatsProperty("A")?.querySelector(
@@ -182,8 +183,8 @@ describe("elbow arrow ui", () => {
       [0, 0],
       [35, 0],
       [35, 90],
-      [25, 90],
-      [25, 165],
+      [35, 90], // Note that coordinates are rounded above!
+      [35, 165],
       [103, 165],
     ]);
   });

+ 22 - 16
packages/excalidraw/element/routing.ts

@@ -235,6 +235,8 @@ export const mutateElbowArrow = (
           BASE_PADDING,
         ),
     boundsOverlap,
+    hoveredStartElement && aabbForElement(hoveredStartElement),
+    hoveredEndElement && aabbForElement(hoveredEndElement),
   );
   const startDonglePosition = getDonglePosition(
     dynamicAABBs[0],
@@ -475,7 +477,11 @@ const generateDynamicAABBs = (
   startDifference?: [number, number, number, number],
   endDifference?: [number, number, number, number],
   disableSideHack?: boolean,
+  startElementBounds?: Bounds | null,
+  endElementBounds?: Bounds | null,
 ): Bounds[] => {
+  const startEl = startElementBounds ?? a;
+  const endEl = endElementBounds ?? b;
   const [startUp, startRight, startDown, startLeft] = startDifference ?? [
     0, 0, 0, 0,
   ];
@@ -484,29 +490,29 @@ const generateDynamicAABBs = (
   const first = [
     a[0] > b[2]
       ? a[1] > b[3] || a[3] < b[1]
-        ? Math.min((a[0] + b[2]) / 2, a[0] - startLeft)
-        : (a[0] + b[2]) / 2
+        ? Math.min((startEl[0] + endEl[2]) / 2, a[0] - startLeft)
+        : (startEl[0] + endEl[2]) / 2
       : a[0] > b[0]
       ? a[0] - startLeft
       : common[0] - startLeft,
     a[1] > b[3]
       ? a[0] > b[2] || a[2] < b[0]
-        ? Math.min((a[1] + b[3]) / 2, a[1] - startUp)
-        : (a[1] + b[3]) / 2
+        ? Math.min((startEl[1] + endEl[3]) / 2, a[1] - startUp)
+        : (startEl[1] + endEl[3]) / 2
       : a[1] > b[1]
       ? a[1] - startUp
       : common[1] - startUp,
     a[2] < b[0]
       ? a[1] > b[3] || a[3] < b[1]
-        ? Math.max((a[2] + b[0]) / 2, a[2] + startRight)
-        : (a[2] + b[0]) / 2
+        ? Math.max((startEl[2] + endEl[0]) / 2, a[2] + startRight)
+        : (startEl[2] + endEl[0]) / 2
       : a[2] < b[2]
       ? a[2] + startRight
       : common[2] + startRight,
     a[3] < b[1]
       ? a[0] > b[2] || a[2] < b[0]
-        ? Math.max((a[3] + b[1]) / 2, a[3] + startDown)
-        : (a[3] + b[1]) / 2
+        ? Math.max((startEl[3] + endEl[1]) / 2, a[3] + startDown)
+        : (startEl[3] + endEl[1]) / 2
       : a[3] < b[3]
       ? a[3] + startDown
       : common[3] + startDown,
@@ -514,29 +520,29 @@ const generateDynamicAABBs = (
   const second = [
     b[0] > a[2]
       ? b[1] > a[3] || b[3] < a[1]
-        ? Math.min((b[0] + a[2]) / 2, b[0] - endLeft)
-        : (b[0] + a[2]) / 2
+        ? Math.min((endEl[0] + startEl[2]) / 2, b[0] - endLeft)
+        : (endEl[0] + startEl[2]) / 2
       : b[0] > a[0]
       ? b[0] - endLeft
       : common[0] - endLeft,
     b[1] > a[3]
       ? b[0] > a[2] || b[2] < a[0]
-        ? Math.min((b[1] + a[3]) / 2, b[1] - endUp)
-        : (b[1] + a[3]) / 2
+        ? Math.min((endEl[1] + startEl[3]) / 2, b[1] - endUp)
+        : (endEl[1] + startEl[3]) / 2
       : b[1] > a[1]
       ? b[1] - endUp
       : common[1] - endUp,
     b[2] < a[0]
       ? b[1] > a[3] || b[3] < a[1]
-        ? Math.max((b[2] + a[0]) / 2, b[2] + endRight)
-        : (b[2] + a[0]) / 2
+        ? Math.max((endEl[2] + startEl[0]) / 2, b[2] + endRight)
+        : (endEl[2] + startEl[0]) / 2
       : b[2] < a[2]
       ? b[2] + endRight
       : common[2] + endRight,
     b[3] < a[1]
       ? b[0] > a[2] || b[2] < a[0]
-        ? Math.max((b[3] + a[1]) / 2, b[3] + endDown)
-        : (b[3] + a[1]) / 2
+        ? Math.max((endEl[3] + startEl[1]) / 2, b[3] + endDown)
+        : (endEl[3] + startEl[1]) / 2
       : b[3] < a[3]
       ? b[3] + endDown
       : common[3] + endDown,

+ 3 - 3
packages/excalidraw/visualdebug.ts

@@ -110,8 +110,8 @@ export const debugDrawBoundingBox = (
 export const debugDrawBounds = (
   box: Bounds | Bounds[],
   opts?: {
-    color: string;
-    permanent: boolean;
+    color?: string;
+    permanent?: boolean;
   },
 ) => {
   (isBounds(box) ? [box] : box).forEach((bbox) =>
@@ -136,7 +136,7 @@ export const debugDrawBounds = (
       ],
       {
         color: opts?.color ?? "green",
-        permanent: opts?.permanent,
+        permanent: !!opts?.permanent,
       },
     ),
   );