diff options
| author | kj_sh604 | 2026-03-15 16:19:35 -0400 |
|---|---|---|
| committer | kj_sh604 | 2026-03-15 16:19:35 -0400 |
| commit | 6ec259a0e71174651bae95d4628138bf6fd68742 (patch) | |
| tree | 5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/scene/ShapeCache.ts | |
| parent | 16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff) | |
refactor: packages/
Diffstat (limited to 'packages/excalidraw/scene/ShapeCache.ts')
| -rw-r--r-- | packages/excalidraw/scene/ShapeCache.ts | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/packages/excalidraw/scene/ShapeCache.ts b/packages/excalidraw/scene/ShapeCache.ts new file mode 100644 index 0000000..39d388a --- /dev/null +++ b/packages/excalidraw/scene/ShapeCache.ts @@ -0,0 +1,86 @@ +import type { Drawable } from "roughjs/bin/core"; +import { RoughGenerator } from "roughjs/bin/generator"; +import type { + ExcalidrawElement, + ExcalidrawSelectionElement, +} from "../element/types"; +import { elementWithCanvasCache } from "../renderer/renderElement"; +import { _generateElementShape } from "./Shape"; +import type { ElementShape, ElementShapes } from "./types"; +import { COLOR_PALETTE } from "../colors"; +import type { AppState, EmbedsValidationStatus } from "../types"; + +export class ShapeCache { + private static rg = new RoughGenerator(); + private static cache = new WeakMap<ExcalidrawElement, ElementShape>(); + + /** + * Retrieves shape from cache if available. Use this only if shape + * is optional and you have a fallback in case it's not cached. + */ + public static get = <T extends ExcalidrawElement>(element: T) => { + return ShapeCache.cache.get( + element, + ) as T["type"] extends keyof ElementShapes + ? ElementShapes[T["type"]] | undefined + : ElementShape | undefined; + }; + + public static set = <T extends ExcalidrawElement>( + element: T, + shape: T["type"] extends keyof ElementShapes + ? ElementShapes[T["type"]] + : Drawable, + ) => ShapeCache.cache.set(element, shape); + + public static delete = (element: ExcalidrawElement) => + ShapeCache.cache.delete(element); + + public static destroy = () => { + ShapeCache.cache = new WeakMap(); + }; + + /** + * Generates & caches shape for element if not already cached, otherwise + * returns cached shape. + */ + public static generateElementShape = < + T extends Exclude<ExcalidrawElement, ExcalidrawSelectionElement>, + >( + element: T, + renderConfig: { + isExporting: boolean; + canvasBackgroundColor: AppState["viewBackgroundColor"]; + embedsValidationStatus: EmbedsValidationStatus; + } | null, + ) => { + // when exporting, always regenerated to guarantee the latest shape + const cachedShape = renderConfig?.isExporting + ? undefined + : ShapeCache.get(element); + + // `null` indicates no rc shape applicable for this element type, + // but it's considered a valid cache value (= do not regenerate) + if (cachedShape !== undefined) { + return cachedShape; + } + + elementWithCanvasCache.delete(element); + + const shape = _generateElementShape( + element, + ShapeCache.rg, + renderConfig || { + isExporting: false, + canvasBackgroundColor: COLOR_PALETTE.white, + embedsValidationStatus: null, + }, + ) as T["type"] extends keyof ElementShapes + ? ElementShapes[T["type"]] + : Drawable | null; + + ShapeCache.cache.set(element, shape); + + return shape; + }; +} |
