refactor: decoupling global Scene state part-1 (#7577)

This commit is contained in:
David Luzar 2024-01-22 00:23:02 +01:00 committed by GitHub
parent 740a165452
commit 0415c616b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 630 additions and 384 deletions

View file

@ -1,10 +1,14 @@
import { isElementInViewport } from "../element/sizeHelpers";
import { isImageElement } from "../element/typeChecks";
import { NonDeletedExcalidrawElement } from "../element/types";
import {
NonDeletedElementsMap,
NonDeletedExcalidrawElement,
} from "../element/types";
import { cancelRender } from "../renderer/renderScene";
import { AppState } from "../types";
import { memoize } from "../utils";
import { memoize, toBrandedType } from "../utils";
import Scene from "./Scene";
import { RenderableElementsMap } from "./types";
export class Renderer {
private scene: Scene;
@ -15,7 +19,7 @@ export class Renderer {
public getRenderableElements = (() => {
const getVisibleCanvasElements = ({
elements,
elementsMap,
zoom,
offsetLeft,
offsetTop,
@ -24,7 +28,7 @@ export class Renderer {
height,
width,
}: {
elements: readonly NonDeletedExcalidrawElement[];
elementsMap: NonDeletedElementsMap;
zoom: AppState["zoom"];
offsetLeft: AppState["offsetLeft"];
offsetTop: AppState["offsetTop"];
@ -33,43 +37,55 @@ export class Renderer {
height: AppState["height"];
width: AppState["width"];
}): readonly NonDeletedExcalidrawElement[] => {
return elements.filter((element) =>
isElementInViewport(element, width, height, {
zoom,
offsetLeft,
offsetTop,
scrollX,
scrollY,
}),
);
const visibleElements: NonDeletedExcalidrawElement[] = [];
for (const element of elementsMap.values()) {
if (
isElementInViewport(element, width, height, {
zoom,
offsetLeft,
offsetTop,
scrollX,
scrollY,
})
) {
visibleElements.push(element);
}
}
return visibleElements;
};
const getCanvasElements = ({
editingElement,
const getRenderableElements = ({
elements,
editingElement,
pendingImageElementId,
}: {
elements: readonly NonDeletedExcalidrawElement[];
editingElement: AppState["editingElement"];
pendingImageElementId: AppState["pendingImageElementId"];
}) => {
return elements.filter((element) => {
const elementsMap = toBrandedType<RenderableElementsMap>(new Map());
for (const element of elements) {
if (isImageElement(element)) {
if (
// => not placed on canvas yet (but in elements array)
pendingImageElementId === element.id
) {
return false;
continue;
}
}
// we don't want to render text element that's being currently edited
// (it's rendered on remote only)
return (
if (
!editingElement ||
editingElement.type !== "text" ||
element.id !== editingElement.id
);
});
) {
elementsMap.set(element.id, element);
}
}
return elementsMap;
};
return memoize(
@ -100,14 +116,14 @@ export class Renderer {
}) => {
const elements = this.scene.getNonDeletedElements();
const canvasElements = getCanvasElements({
const elementsMap = getRenderableElements({
elements,
editingElement,
pendingImageElementId,
});
const visibleElements = getVisibleCanvasElements({
elements: canvasElements,
elementsMap,
zoom,
offsetLeft,
offsetTop,
@ -117,7 +133,7 @@ export class Renderer {
width,
});
return { canvasElements, visibleElements };
return { elementsMap, visibleElements };
},
);
})();