فهرست منبع

simplify distance helper and factor out common bounds helper (#581)

* simplify distance helper

* factor out common bounds helper
David Luzar 5 سال پیش
والد
کامیت
7b842fc330
7فایلهای تغییر یافته به همراه42 افزوده شده و 77 حذف شده
  1. 17 0
      src/element/bounds.ts
  2. 1 0
      src/element/index.ts
  3. 4 18
      src/index.tsx
  4. 10 28
      src/scene/data.ts
  5. 6 17
      src/scene/getExportCanvasPreview.ts
  6. 3 13
      src/scene/scrollbars.ts
  7. 1 1
      src/utils.ts

+ 17 - 0
src/element/bounds.ts

@@ -57,3 +57,20 @@ export function getLinePoints(element: ExcalidrawElement) {
 
   return [x1, y1, x2, y2];
 }
+
+export function getCommonBounds(elements: readonly ExcalidrawElement[]) {
+  let minX = Infinity;
+  let maxX = -Infinity;
+  let minY = Infinity;
+  let maxY = -Infinity;
+
+  elements.forEach(element => {
+    const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
+    minX = Math.min(minX, x1);
+    minY = Math.min(minY, y1);
+    maxX = Math.max(maxX, x2);
+    maxY = Math.max(maxY, y2);
+  });
+
+  return [minX, minY, maxX, maxY];
+}

+ 1 - 0
src/element/index.ts

@@ -1,6 +1,7 @@
 export { newElement, newTextElement, duplicateElement } from "./newElement";
 export {
   getElementAbsoluteCoords,
+  getCommonBounds,
   getDiamondPoints,
   getArrowPoints,
   getLinePoints,

+ 4 - 18
src/index.tsx

@@ -13,7 +13,7 @@ import {
   isInvisiblySmallElement,
   isTextElement,
   textWysiwyg,
-  getElementAbsoluteCoords,
+  getCommonBounds,
   getCursorForResizingElement,
   getPerfectElementSize,
   resizePerfectLineForNWHandler,
@@ -1388,24 +1388,10 @@ export class App extends React.Component<any, AppState> {
     ) {
       elements = clearSelection(elements);
 
-      let subCanvasX1 = Infinity;
-      let subCanvasX2 = -Infinity;
-      let subCanvasY1 = Infinity;
-      let subCanvasY2 = -Infinity;
+      const [minX, minY, maxX, maxY] = getCommonBounds(parsedElements);
 
-      const minX = Math.min(...parsedElements.map(element => element.x));
-      const minY = Math.min(...parsedElements.map(element => element.y));
-
-      parsedElements.forEach(parsedElement => {
-        const [x1, y1, x2, y2] = getElementAbsoluteCoords(parsedElement);
-        subCanvasX1 = Math.min(subCanvasX1, x1);
-        subCanvasY1 = Math.min(subCanvasY1, y1);
-        subCanvasX2 = Math.max(subCanvasX2, x2);
-        subCanvasY2 = Math.max(subCanvasY2, y2);
-      });
-
-      const elementsCenterX = distance(subCanvasX1, subCanvasX2) / 2;
-      const elementsCenterY = distance(subCanvasY1, subCanvasY2) / 2;
+      const elementsCenterX = distance(minX, maxX) / 2;
+      const elementsCenterY = distance(minY, maxY) / 2;
 
       const dx =
         cursorX -

+ 10 - 28
src/scene/data.ts

@@ -7,6 +7,7 @@ import { ExportType } from "./types";
 import { getExportCanvasPreview } from "./getExportCanvasPreview";
 import nanoid from "nanoid";
 import { fileOpen, fileSave } from "browser-nativefs";
+import { getCommonBounds } from "../element";
 
 import i18n from "../i18n";
 
@@ -43,35 +44,14 @@ export function serializeAsJSON(
   );
 }
 
-function calculateScroll(
+function calculateScrollCenter(
   elements: readonly ExcalidrawElement[],
 ): { scrollX: number; scrollY: number } {
-  // Bounding box of all elements
-  let top = Number.MAX_SAFE_INTEGER;
-  let left = Number.MAX_SAFE_INTEGER;
-  let bottom = -Number.MAX_SAFE_INTEGER;
-  let right = -Number.MAX_SAFE_INTEGER;
+  let [x1, y1, x2, y2] = getCommonBounds(elements);
+
+  const centerX = (x1 + x2) / 2;
+  const centerY = (y1 + y2) / 2;
 
-  for (const element of elements) {
-    left = Math.min(
-      left,
-      element.width > 0 ? element.x : element.x + element.width,
-    );
-    top = Math.min(
-      top,
-      element.height > 0 ? element.y : element.y + element.height,
-    );
-    right = Math.max(
-      right,
-      element.width > 0 ? element.x + element.width : element.x,
-    );
-    bottom = Math.max(
-      bottom,
-      element.height > 0 ? element.y + element.height : element.y,
-    );
-  }
-  const centerX = left + (right - left) / 2;
-  const centerY = top + (bottom - top) / 2;
   return {
     scrollX: window.innerWidth / 2 - centerX,
     scrollY: window.innerHeight / 2 - centerY,
@@ -136,7 +116,9 @@ export async function loadFromJSON() {
   }
   const { elements, appState } = updateAppState(contents);
   return new Promise<DataState>(resolve => {
-    resolve(restore(elements, { ...appState, ...calculateScroll(elements) }));
+    resolve(
+      restore(elements, { ...appState, ...calculateScrollCenter(elements) }),
+    );
   });
 }
 
@@ -187,7 +169,7 @@ export async function importFromBackend(id: string | null) {
       console.error(error);
     }
   }
-  return restore(elements, { ...appState, ...calculateScroll(elements) });
+  return restore(elements, { ...appState, ...calculateScrollCenter(elements) });
 }
 
 export async function exportCanvas(

+ 6 - 17
src/scene/getExportCanvasPreview.ts

@@ -1,6 +1,6 @@
 import rough from "roughjs/bin/rough";
 import { ExcalidrawElement } from "../element/types";
-import { getElementAbsoluteCoords } from "../element/bounds";
+import { getCommonBounds } from "../element/bounds";
 import { renderScene } from "../renderer/renderScene";
 import { distance } from "../utils";
 
@@ -28,21 +28,10 @@ export function getExportCanvasPreview(
   },
 ) {
   // calculate smallest area to fit the contents in
-  let subCanvasX1 = Infinity;
-  let subCanvasX2 = -Infinity;
-  let subCanvasY1 = Infinity;
-  let subCanvasY2 = -Infinity;
+  const [minX, minY, maxX, maxY] = getCommonBounds(elements);
+  const width = distance(minX, maxX) + exportPadding * 2;
+  const height = distance(minY, maxY) + exportPadding * 2;
 
-  elements.forEach(element => {
-    const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
-    subCanvasX1 = Math.min(subCanvasX1, x1);
-    subCanvasY1 = Math.min(subCanvasY1, y1);
-    subCanvasX2 = Math.max(subCanvasX2, x2);
-    subCanvasY2 = Math.max(subCanvasY2, y2);
-  });
-
-  const width = distance(subCanvasX1, subCanvasX2) + exportPadding * 2;
-  const height = distance(subCanvasY1, subCanvasY2) + exportPadding * 2;
   const tempCanvas: any = createCanvas(width, height);
   tempCanvas.getContext("2d")?.scale(scale, scale);
 
@@ -56,8 +45,8 @@ export function getExportCanvasPreview(
       scrollY: 0,
     },
     {
-      offsetX: -subCanvasX1 + exportPadding,
-      offsetY: -subCanvasY1 + exportPadding,
+      offsetX: -minX + exportPadding,
+      offsetY: -minY + exportPadding,
       renderScrollbars: false,
       renderSelection: false,
     },

+ 3 - 13
src/scene/scrollbars.ts

@@ -1,5 +1,5 @@
 import { ExcalidrawElement } from "../element/types";
-import { getElementAbsoluteCoords } from "../element";
+import { getCommonBounds } from "../element";
 
 const SCROLLBAR_MIN_SIZE = 15;
 const SCROLLBAR_MARGIN = 4;
@@ -13,23 +13,13 @@ export function getScrollBars(
   scrollX: number,
   scrollY: number,
 ) {
-  let minX = Infinity;
-  let maxX = -Infinity;
-  let minY = Infinity;
-  let maxY = -Infinity;
-
-  elements.forEach(element => {
-    const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
-    minX = Math.min(minX, x1);
-    minY = Math.min(minY, y1);
-    maxX = Math.max(maxX, x2);
-    maxY = Math.max(maxY, y2);
-  });
+  let [minX, minY, maxX, maxY] = getCommonBounds(elements);
 
   minX += scrollX;
   maxX += scrollX;
   minY += scrollY;
   maxY += scrollY;
+
   const leftOverflow = Math.max(-minX, 0);
   const rightOverflow = Math.max(-(canvasWidth - maxX), 0);
   const topOverflow = Math.max(-minY, 0);

+ 1 - 1
src/utils.ts

@@ -88,5 +88,5 @@ export function removeSelection() {
 }
 
 export function distance(x: number, y: number) {
-  return Math.abs(x > y ? x - y : y - x);
+  return Math.abs(x - y);
 }