import { Drawable } from "roughjs/bin/core"; import { RoughGenerator } from "roughjs/bin/generator"; import { ExcalidrawElement, ExcalidrawSelectionElement, } from "../element/types"; import { elementWithCanvasCache } from "../renderer/renderElement"; import { _generateElementShape } from "./Shape"; import { ElementShape, ElementShapes } from "./types"; export class ShapeCache { private static rg = new RoughGenerator(); private static cache = new WeakMap(); /** * 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 = (element: T) => { return ShapeCache.cache.get( element, ) as T["type"] extends keyof ElementShapes ? ElementShapes[T["type"]] | undefined : ElementShape | undefined; }; public static set = ( 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, >( element: T, isExporting = false, ) => { // when exporting, always regenerated to guarantee the latest shape const cachedShape = 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, isExporting, ) as T["type"] extends keyof ElementShapes ? ElementShapes[T["type"]] : Drawable | null; ShapeCache.cache.set(element, shape); return shape; }; }