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

* simplify distance helper

* factor out common bounds helper
This commit is contained in:
David Luzar 2020-01-26 20:15:08 +01:00 committed by Christopher Chedeau
parent 5853fba821
commit 7b842fc330
7 changed files with 42 additions and 77 deletions

View File

@ -57,3 +57,20 @@ export function getLinePoints(element: ExcalidrawElement) {
return [x1, y1, x2, y2]; 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];
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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