2023-08-12 22:56:59 +02:00
|
|
|
import { Drawable } from "roughjs/bin/core";
|
|
|
|
import { RoughGenerator } from "roughjs/bin/generator";
|
2023-08-14 13:52:25 +02:00
|
|
|
import {
|
|
|
|
ExcalidrawElement,
|
|
|
|
ExcalidrawSelectionElement,
|
|
|
|
} from "../element/types";
|
|
|
|
import { elementWithCanvasCache } from "../renderer/renderElement";
|
|
|
|
import { _generateElementShape } from "./Shape";
|
|
|
|
import { ElementShape, ElementShapes } from "./types";
|
2023-08-12 22:56:59 +02:00
|
|
|
|
|
|
|
export class ShapeCache {
|
|
|
|
private static rg = new RoughGenerator();
|
|
|
|
private static cache = new WeakMap<ExcalidrawElement, ElementShape>();
|
|
|
|
|
2023-08-14 13:52:25 +02:00
|
|
|
/**
|
|
|
|
* Retrieves shape from cache if available. Use this only if shape
|
|
|
|
* is optional and you have a fallback in case it's not cached.
|
|
|
|
*/
|
2023-08-12 22:56:59 +02:00
|
|
|
public static get = <T extends ExcalidrawElement>(element: T) => {
|
|
|
|
return ShapeCache.cache.get(
|
|
|
|
element,
|
|
|
|
) as T["type"] extends keyof ElementShapes
|
|
|
|
? ElementShapes[T["type"]] | undefined
|
2023-08-14 13:52:25 +02:00
|
|
|
: ElementShape | undefined;
|
2023-08-12 22:56:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
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
|
2023-08-14 13:52:25 +02:00
|
|
|
* returns cached shape.
|
2023-08-12 22:56:59 +02:00
|
|
|
*/
|
2023-08-14 13:52:25 +02:00
|
|
|
public static generateElementShape = <
|
|
|
|
T extends Exclude<ExcalidrawElement, ExcalidrawSelectionElement>,
|
|
|
|
>(
|
2023-08-12 22:56:59 +02:00
|
|
|
element: T,
|
2023-08-14 13:52:25 +02:00
|
|
|
isExporting = false,
|
2023-08-12 22:56:59 +02:00
|
|
|
) => {
|
2023-08-14 13:52:25 +02:00
|
|
|
// 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(
|
2023-08-12 22:56:59 +02:00
|
|
|
element,
|
|
|
|
ShapeCache.rg,
|
2023-08-14 13:52:25 +02:00
|
|
|
isExporting,
|
2023-08-12 22:56:59 +02:00
|
|
|
) as T["type"] extends keyof ElementShapes
|
|
|
|
? ElementShapes[T["type"]]
|
|
|
|
: Drawable | null;
|
|
|
|
|
|
|
|
ShapeCache.cache.set(element, shape);
|
|
|
|
|
|
|
|
return shape;
|
|
|
|
};
|
|
|
|
}
|