kopia lustrzana https://github.com/Tldraw/Tldraw
add cache manager, some caches
rodzic
91903c9761
commit
d592995314
|
@ -82,6 +82,7 @@ import { useQuickReactor } from '@tldraw/state';
|
|||
import { useReactor } from '@tldraw/state';
|
||||
import { useValue } from '@tldraw/state';
|
||||
import { VecModel } from '@tldraw/tlschema';
|
||||
import { WeakCache } from '@tldraw/utils';
|
||||
import { whyAmIRunning } from '@tldraw/state';
|
||||
|
||||
// @public
|
||||
|
@ -699,6 +700,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
};
|
||||
bringForward(shapes: TLShape[] | TLShapeId[]): this;
|
||||
bringToFront(shapes: TLShape[] | TLShapeId[]): this;
|
||||
readonly caches: CacheManager;
|
||||
cancel(): this;
|
||||
cancelDoubleClick(): void;
|
||||
// @internal (undocumented)
|
||||
|
|
|
@ -123,6 +123,7 @@ import { notVisibleShapes } from './derivations/notVisibleShapes'
|
|||
import { parentsToChildren } from './derivations/parentsToChildren'
|
||||
import { deriveShapeIdsInCurrentPage } from './derivations/shapeIdsInCurrentPage'
|
||||
import { getSvgJsx } from './getSvgJsx'
|
||||
import { CacheManager } from './managers/CacheManager'
|
||||
import { ClickManager } from './managers/ClickManager'
|
||||
import { EnvironmentManager } from './managers/EnvironmentManager'
|
||||
import { HistoryManager } from './managers/HistoryManager'
|
||||
|
@ -297,6 +298,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
|
||||
this.environment = new EnvironmentManager(this)
|
||||
this.scribbles = new ScribbleManager(this)
|
||||
this.caches = new CacheManager(this)
|
||||
|
||||
// Cleanup
|
||||
|
||||
|
@ -711,6 +713,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
*/
|
||||
readonly sideEffects: SideEffectManager<this>
|
||||
|
||||
/**
|
||||
* A manager for weak map caches.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
readonly caches: CacheManager
|
||||
|
||||
/**
|
||||
* The current HTML element containing the editor.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { WeakCache } from '@tldraw/utils'
|
||||
import { Editor } from '../Editor'
|
||||
|
||||
export class CacheManager {
|
||||
constructor(public editor: Editor) {}
|
||||
|
||||
private caches = new Map<string, WeakCache<any, unknown>>()
|
||||
|
||||
createCache<T extends object, Q>(name: string) {
|
||||
const cache = new WeakCache<T, Q>()
|
||||
this.caches.set(name, cache)
|
||||
return cache
|
||||
}
|
||||
|
||||
get<T extends object, Q>(name: string): WeakCache<T, Q> {
|
||||
return this.caches.get(name) as WeakCache<T, Q>
|
||||
}
|
||||
|
||||
clear(name: string) {
|
||||
const cache = this.caches.get(name)
|
||||
if (!cache) throw Error(`Cache ${name} not found`)
|
||||
cache.clear()
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
this.caches.clear()
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ import {
|
|||
TLOnHandleDragHandler,
|
||||
TLOnResizeHandler,
|
||||
Vec,
|
||||
WeakCache,
|
||||
getIndexBetween,
|
||||
getIndices,
|
||||
lineShapeMigrations,
|
||||
|
@ -30,8 +29,6 @@ import {
|
|||
getSvgPathForLineGeometry,
|
||||
} from './components/svg'
|
||||
|
||||
const handlesCache = new WeakCache<TLLineShape['props'], TLHandle[]>()
|
||||
|
||||
/** @public */
|
||||
export class LineShapeUtil extends ShapeUtil<TLLineShape> {
|
||||
static override type = 'line' as const
|
||||
|
@ -63,33 +60,31 @@ export class LineShapeUtil extends ShapeUtil<TLLineShape> {
|
|||
}
|
||||
|
||||
override getHandles(shape: TLLineShape) {
|
||||
return handlesCache.get(shape.props, () => {
|
||||
const spline = getGeometryForLineShape(shape)
|
||||
const spline = getGeometryForLineShape(shape)
|
||||
|
||||
const points = linePointsToArray(shape)
|
||||
const results: TLHandle[] = points.map((point) => ({
|
||||
...point,
|
||||
id: point.index,
|
||||
type: 'vertex',
|
||||
const points = linePointsToArray(shape)
|
||||
const results: TLHandle[] = points.map((point) => ({
|
||||
...point,
|
||||
id: point.index,
|
||||
type: 'vertex',
|
||||
canSnap: true,
|
||||
}))
|
||||
|
||||
for (let i = 0; i < points.length - 1; i++) {
|
||||
const index = getIndexBetween(points[i].index, points[i + 1].index)
|
||||
const segment = spline.segments[i]
|
||||
const point = segment.midPoint()
|
||||
results.push({
|
||||
id: index,
|
||||
type: 'create',
|
||||
index,
|
||||
x: point.x,
|
||||
y: point.y,
|
||||
canSnap: true,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < points.length - 1; i++) {
|
||||
const index = getIndexBetween(points[i].index, points[i + 1].index)
|
||||
const segment = spline.segments[i]
|
||||
const point = segment.midPoint()
|
||||
results.push({
|
||||
id: index,
|
||||
type: 'create',
|
||||
index,
|
||||
x: point.x,
|
||||
y: point.y,
|
||||
canSnap: true,
|
||||
})
|
||||
}
|
||||
|
||||
return results.sort(sortByIndex)
|
||||
})
|
||||
return results.sort(sortByIndex)
|
||||
}
|
||||
|
||||
// Events
|
||||
|
@ -164,7 +159,8 @@ export class LineShapeUtil extends ShapeUtil<TLLineShape> {
|
|||
return {
|
||||
points,
|
||||
getSelfSnapPoints: (handle) => {
|
||||
const index = this.getHandles(shape)
|
||||
const index = this.editor
|
||||
.getShapeHandles<TLLineShape>(shape)!
|
||||
.filter((h) => h.type === 'vertex')
|
||||
.findIndex((h) => h.id === handle.id)!
|
||||
|
||||
|
@ -175,7 +171,8 @@ export class LineShapeUtil extends ShapeUtil<TLLineShape> {
|
|||
// We want to skip the segments that include the handle, so
|
||||
// find the index of the handle that shares the same index property
|
||||
// as the initial dragging handle; this catches a quirk of create handles
|
||||
const index = this.getHandles(shape)
|
||||
const index = this.editor
|
||||
.getShapeHandles<TLLineShape>(shape)!
|
||||
.filter((h) => h.type === 'vertex')
|
||||
.findIndex((h) => h.id === handle.id)!
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
TLShape,
|
||||
TLShapeId,
|
||||
Vec,
|
||||
WeakCache,
|
||||
getDefaultColorTheme,
|
||||
noteShapeMigrations,
|
||||
noteShapeProps,
|
||||
|
@ -372,10 +371,16 @@ function getNoteLabelSize(editor: Editor, shape: TLNoteShape) {
|
|||
}
|
||||
}
|
||||
|
||||
const labelSizesForNote = new WeakCache<TLShape, ReturnType<typeof getNoteLabelSize>>()
|
||||
|
||||
function getLabelSize(editor: Editor, shape: TLNoteShape) {
|
||||
return labelSizesForNote.get(shape, () => getNoteLabelSize(editor, shape))
|
||||
let cache = editor.caches.get<TLShape, ReturnType<typeof getNoteLabelSize>>(
|
||||
'@tldraw/noteLabelSize'
|
||||
)
|
||||
if (!cache) {
|
||||
cache = editor.caches.createCache<TLShape, ReturnType<typeof getNoteLabelSize>>(
|
||||
'@tldraw/noteLabelSize'
|
||||
)
|
||||
}
|
||||
return cache.get(shape, () => getNoteLabelSize(editor, shape))
|
||||
}
|
||||
|
||||
function useNoteKeydownHandler(id: TLShapeId) {
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
TLShapeUtilFlag,
|
||||
TLTextShape,
|
||||
Vec,
|
||||
WeakCache,
|
||||
getDefaultColorTheme,
|
||||
preventDefault,
|
||||
textShapeMigrations,
|
||||
|
@ -28,8 +27,6 @@ import { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from '../shared/default-shape-c
|
|||
import { getFontDefForExport } from '../shared/defaultStyleDefs'
|
||||
import { resizeScaled } from '../shared/resizeScaled'
|
||||
|
||||
const sizeCache = new WeakCache<TLTextShape['props'], { height: number; width: number }>()
|
||||
|
||||
/** @public */
|
||||
export class TextShapeUtil extends ShapeUtil<TLTextShape> {
|
||||
static override type = 'text' as const
|
||||
|
@ -50,7 +47,16 @@ export class TextShapeUtil extends ShapeUtil<TLTextShape> {
|
|||
}
|
||||
|
||||
getMinDimensions(shape: TLTextShape) {
|
||||
return sizeCache.get(shape.props, (props) => getTextSize(this.editor, props))
|
||||
const { editor } = this
|
||||
let cache = editor.caches.get<TLTextShape['props'], { height: number; width: number }>(
|
||||
'@tldraw/textShapeSize'
|
||||
)
|
||||
if (!cache) {
|
||||
cache = editor.caches.createCache<TLTextShape['props'], { height: number; width: number }>(
|
||||
'@tldraw/textShapeSize'
|
||||
)
|
||||
}
|
||||
return cache.get(shape.props, (props) => getTextSize(this.editor, props))
|
||||
}
|
||||
|
||||
getGeometry(shape: TLTextShape) {
|
||||
|
|
|
@ -349,6 +349,7 @@ export function warnDeprecatedGetter(name: string): void;
|
|||
|
||||
// @public
|
||||
export class WeakCache<K extends object, V> {
|
||||
clear(): void;
|
||||
get<P extends K>(item: P, cb: (item: P) => V): NonNullable<V>;
|
||||
items: WeakMap<K, V>;
|
||||
}
|
||||
|
|
|
@ -20,4 +20,11 @@ export class WeakCache<K extends object, V> {
|
|||
|
||||
return this.items.get(item)!
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache. (Technically we create a new WeakMap, but the old one will get cleaned up by the GC eventually.)
|
||||
*/
|
||||
clear() {
|
||||
this.items = new WeakMap()
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue