@graphty/graphty-element / index / UpdateManager
Class: UpdateManager ​
Defined in: graphty-element/src/managers/UpdateManager.ts:212
Manages the update loop logic for the graph Coordinates updates across nodes, edges, layout, and camera
Implements ​
Constructors ​
Constructor ​
new UpdateManager(
eventManager,statsManager,layoutManager,dataManager,camera,graphContext,config?):UpdateManager
Defined in: graphty-element/src/managers/UpdateManager.ts:287
Creates a new update manager
Parameters ​
eventManager ​
Event manager for emitting update events
statsManager ​
Stats manager for performance tracking
layoutManager ​
Layout manager for graph layout
dataManager ​
Data manager for nodes and edges
camera ​
CameraManager
Camera manager for view control
graphContext ​
Graph context for accessing shared resources
config? ​
UpdateManagerConfig = {}
Optional configuration
Returns ​
UpdateManager
Accessors ​
frameIsStable ​
Get Signature ​
get frameIsStable():
boolean
Defined in: graphty-element/src/managers/UpdateManager.ts:733
Whether the picture on screen is the finished one.
True only when the layout has converged, no framing is outstanding that could still move the camera, no style work is queued, every drawn mesh has its shader, AND a frame has been drawn since all of that became true. It is the difference between graph-settled, which fires the instant the LAYOUT stops and one pass before the final framing is even requested, and a picture that will not change again.
It says nothing about a reader: somebody dragging the camera or a node changes the picture, and the element does not call that instability.
Returns ​
boolean
True when the last drawn frame drew the finished picture.
zoomToFitCompleted ​
Get Signature ​
get zoomToFitCompleted():
boolean
Defined in: graphty-element/src/managers/UpdateManager.ts:1592
Check if zoom to fit has been completed
Returns ​
boolean
True if zoom to fit has completed at least once
Methods ​
bindViewMasks() ​
bindViewMasks(
masks):void
Defined in: graphty-element/src/managers/UpdateManager.ts:349
Say where the renderer reads the selection and visibility masks from.
Binding is how the element's own model reaches the render loop: the masks belong to the session, one per dataset, and every view of that dataset honours the same two. Passing null unbinds them, which draws the whole graph with no highlight.
Parameters ​
masks ​
ViewMasks | null
The two mask sources, or null.
Returns ​
void
disableZoomToFit() ​
disableZoomToFit():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:648
Disable zoom to fit
Returns ​
void
dispose() ​
dispose():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:335
Dispose the update manager
Returns ​
void
Implementation of ​
enableZoomToFit() ​
enableZoomToFit(
explicit?):void
Defined in: graphty-element/src/managers/UpdateManager.ts:630
Frame the whole graph on the next frame that has something to measure.
The request is HONOURED rather than merely permitted. Everything below this line paces the periodic re-framing that follows a moving layout around, and that pacing answers "no" to every frame once the layout has stopped -- so routing an explicit request through it made Graph.zoomToFit() silent from the first settlement onwards, and made the element's own "re-frame now that the layout has truly settled" call dead on arrival.
Parameters ​
explicit? ​
boolean = false
True when a consumer asked, so UpdateManager.stopAutoZoomToFit leaves the request standing.
Returns ​
void
forceEdgeWalk() ​
forceEdgeWalk():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:1368
Make the next frame visit every edge, whatever the nodes say.
Called when something other than a position has changed what an edge should draw: a style pass has repainted, or the dataset has been replaced. A repaint can change a node's SIZE, which moves where its edges have to stop without moving the node at all.
Returns ​
void
getRenderFrameCount() ​
getRenderFrameCount():
number
Defined in: graphty-element/src/managers/UpdateManager.ts:679
Get the current render frame count
Returns ​
number
Total number of frames rendered
init() ​
init():
Promise<void>
Defined in: graphty-element/src/managers/UpdateManager.ts:327
Initialize the update manager
Returns ​
Promise<void>
Promise that resolves when initialization is complete
Implementation of ​
invalidateViewMasks() ​
invalidateViewMasks():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:361
Forget which mask versions the meshes are in line with, so the next pass writes all of them.
Call this when the render objects have changed under the masks -- a dataset load, a clear, a 2D/3D switch -- because the versions would otherwise say "nothing moved" about elements that are not the elements those versions were measured against.
Returns ​
void
isZoomToFitEnabled() ​
isZoomToFitEnabled():
boolean
Defined in: graphty-element/src/managers/UpdateManager.ts:671
Get current zoom to fit state
Returns ​
boolean
True if zoom to fit is enabled
meshesAdded() ​
meshesAdded():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:752
Say that meshes were built outside a pass that moves anything, so the finished picture has to be earned again.
A new mesh can bring a shader variant nothing has compiled, or a texture still loading, and a frame skips a mesh that is not ready. Most doors that build meshes also move something -- a load starts the layout, a forward dimension change frames the camera -- and that clears the finished flags on the next pass. An undo of a dimension change moves nothing, because the layout stays at rest and the camera is the reader's; nor does a skybox. Without this the last finished frame would still be called final while the new meshes are drawn as nothing: an empty canvas after undoing 2D to 3D, and the old background after setting a skybox.
Returns ​
void
rebindScene() ​
rebindScene(
camera):void
Defined in: graphty-element/src/managers/UpdateManager.ts:316
Follows the graph onto the scene and camera of the renderer chosen at init, which replace the ones this manager was built with. The old scene is disposed, and its watcher with it.
Parameters ​
camera ​
CameraManager
The new scene's camera manager.
Returns ​
void
redrawArrangement() ​
redrawArrangement(
moved?):void
Defined in: graphty-element/src/managers/UpdateManager.ts:1173
Move every node and edge to where the position array has it now, without stepping the layout: how a restored arrangement reaches the picture while the layout is at rest.
Parameters ​
moved? ​
boolean = true
Whether any coordinate was written; when none was, the nodes are placed and the edges, whose endpoints are where they were, are left as they are drawn.
Returns ​
void
renderFrames() ​
renderFrames(
count):void
Defined in: graphty-element/src/managers/UpdateManager.ts:711
Update AND draw a number of frames, the way the render loop does.
The render loop is one update pass followed by one scene.render(), so this is that pair repeated: after it returns, what is on the canvas is what the model says, and a frame drawn while the picture was finished has been counted as such by UpdateManager.frameIsStable.
Parameters ​
count ​
number
How many frames to update and draw.
Returns ​
void
stepFrames() ​
stepFrames(
count):void
Defined in: graphty-element/src/managers/UpdateManager.ts:696
Run a number of MODEL-UPDATE passes, drawing nothing.
One pass is the half of a frame that happens before the picture: it steps the layout, moves the meshes, applies queued style work and may re-frame the camera. It never puts a pixel on screen, because that is scene.render() and this method does not call it. Use it when what is being checked is the MODEL -- a mesh's material, a node's position, whether a framing happened -- and use UpdateManager.renderFrames when a picture is needed.
It was called renderFixedFrames, and every caller that read the name and wanted a picture got layout steps and no frames instead.
Parameters ​
count ​
number
How many update passes to run.
Returns ​
void
stopAutoZoomToFit() ​
stopAutoZoomToFit():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:660
Stop the element's own framing -- the follow of a moving layout and any request the element made itself -- but keep a consumer's outstanding zoomToFit(), which is answered once.
Returns ​
void
syncStyles() ​
syncStyles():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:558
Bring the meshes into line with what the session's style stack painted.
THE DIRTY SET IS THE WHOLE POINT, and it is the renderer's half of the repaint's cost contract. A style pass bounds its own work to the elements an edit touched; without this the renderer would then rebuild every mesh in the graph to find them, and the pass's bound would buy nothing. So the painter hands back exactly the indices the pass repainted, and a layer over 300 elements costs 300 elements whatever the graph's size.
An element whose paint has not changed still costs nothing: Node.applySessionPaint and Edge.applySessionPaint compare the source mesh they are handed with the one already on screen and rebuild only when it differs, so a colour change on a node is one buffer write and no geometry at all.
Returns ​
void
syncViewMasks() ​
syncViewMasks():
void
Defined in: graphty-element/src/managers/UpdateManager.ts:395
Bring the meshes into line with the two masks.
THE WHOLE POINT IS THE DELTA. A pass costs one integer comparison when nothing has moved, and when something has it walks the render objects and writes ONLY the ones whose state actually changed -- Node.setRenderState and Edge.setRenderVisible return false and touch no mesh when handed what they already hold. So scrubbing a time window that moves 200 nodes costs 200 mesh operations and not 50,000, and re-running a filter that lands on the same answer costs none.
Mesh instancing is what bounds the rest: a node is one InstancedMesh of a source shared by every node of its style, so hiding one is a flag on that instance rather than a geometry change. Babylon offers no way to hide a SUBSET of a source's instances in one call, so the first application of a large filter is one flag write per element that moved; that is the floor, and the delta above is what keeps every later pass off it.
An element the store has no row for -- INVALID_INDEX, which is what a record that never reached the builder carries -- is drawn and is not selected. The element has always drawn such a record, and a mask cannot answer for a row that does not exist.
READING A MASK RESYNCS IT against the current graph, which is the one cost this pass cannot avoid and must not: a mask that was not regrown answers "not a member" for every node that arrived since it was last evaluated, so skipping the resync would silently hide every newly loaded node while a filter is on. The resync is an identity comparison whenever the graph has not moved, so the cost lands only while records are actually arriving.
Returns ​
void
update() ​
update(
frameMs?):void
Defined in: graphty-element/src/managers/UpdateManager.ts:951
Update the graph for the current frame.
The pass itself is the private runUpdatePass(); what is added here is the one question a consumer cares about and the pass has several exits from -- whether the state it leaves behind is a finished picture.
Parameters ​
frameMs? ​
number = 0
How long the previous frame took. A running layout keeps to one step per nominal 60 Hz frame of that time, so it settles in the same seconds however slowly the frames are drawn. Omitted or 0 -- every hand-pumped pass -- it takes one step.
Returns ​
void
updateConfig() ​
updateConfig(
config):void
Defined in: graphty-element/src/managers/UpdateManager.ts:1600
Update configuration
Parameters ​
config ​
Partial<UpdateManagerConfig>
Partial configuration to merge
Returns ​
void
whyFrameIsNotStable() ​
whyFrameIsNotStable():
string
Defined in: graphty-element/src/managers/UpdateManager.ts:764
What is still keeping the picture from being final, in a consumer's words.
Written for the message a timed-out wait carries, because "the frame never settled" on its own sends the reader to a debugger.
Returns ​
string
One phrase naming the thing that is still moving.