34 lines
2.3 KiB
TypeScript
34 lines
2.3 KiB
TypeScript
import type {Document,Id} from '../canvas-core/types.ts';
|
|
import {equal,fault} from '../canvas-core/values.ts';
|
|
import type {projectCanvas} from './projection.ts';
|
|
|
|
type Projection=ReturnType<typeof projectCanvas>;
|
|
type Retained<T>={incarnation:number;ownerCanvasId:Id;value:T};
|
|
/** View-owned rendering cache, never a document store. Keep unchanged React Flow input identities. */
|
|
export function createProjectionCache(){
|
|
let scope:object|undefined,projectId:Id|undefined,canvasId:Id|undefined;
|
|
let nodes=new Map<Id,Retained<Projection['nodes'][number]>>(),edges=new Map<Id,Retained<Projection['edges'][number]>>();
|
|
function retain<T extends{id:Id}>(document:Document,values:T[],previous:Map<Id,Retained<T>>){
|
|
const next=new Map<Id,Retained<T>>();
|
|
for(let index=0;index<values.length;index++){
|
|
const value=values[index],record=document.elements.get(value.id);if(!record)throw fault('projection_identity_missing',[value.id]);
|
|
const old=previous.get(value.id),retained=old&&old.incarnation===record.incarnation&&old.ownerCanvasId===record.ownerCanvasId&&equal(old.value,value)?old.value:value;
|
|
values[index]=retained;next.set(value.id,{incarnation:record.incarnation,ownerCanvasId:record.ownerCanvasId,value:retained});
|
|
}
|
|
return next;
|
|
}
|
|
return Object.freeze({
|
|
reuse(owner:object,document:Document,viewCanvasId:Id,projection:Projection):Projection{
|
|
if(scope!==owner||projectId!==document.projectId||canvasId!==viewCanvasId){nodes.clear();edges.clear();scope=owner;projectId=document.projectId;canvasId=viewCanvasId;}
|
|
nodes=retain(document,projection.nodes,nodes);edges=retain(document,projection.edges,edges);
|
|
return projection;
|
|
},
|
|
getNode(id:Id){return nodes.get(id)?.value;},
|
|
canRetainMeasurement(owner:object,document:Document,viewCanvasId:Id,value:Projection['nodes'][number]){
|
|
const old=nodes.get(value.id),record=document.elements.get(value.id);
|
|
return scope===owner&&projectId===document.projectId&&canvasId===viewCanvasId&&!!old&&!!record&&old.incarnation===record.incarnation&&old.ownerCanvasId===record.ownerCanvasId&&old.value.type===value.type&&old.value.width===value.width&&old.value.height===value.height&&equal(old.value.data,value.data);
|
|
},
|
|
clear(){nodes.clear();edges.clear();scope=undefined;projectId=undefined;canvasId=undefined;},
|
|
});
|
|
}
|