@graphty/graphty-element / index / DataManager
Class: DataManager ​
Defined in: graphty-element/src/managers/DataManager.ts:308
Manages all data operations for nodes and edges Handles CRUD operations, caching, and data source loading
THE AUTHORITATIVE COPY OF THE GRAPH IS THE STORE, NOT THE MESHES. nodes and edges hold the render objects -- a Node builds a Babylon mesh in its constructor -- and they remain how the scene is drawn. Alongside them this manager keeps ONE GraphStore for the life of the graph: every record that arrives is pushed into its builder, and getSnapshot() hands out an immutable graph-format snapshot of it. Node.index and Edge.index are that snapshot's dense row numbers, so an id maps to a row without walking a map of meshes.
The two copies are not always in step, and the direction of the discrepancy is deliberate:
- An edge whose endpoints have not arrived is in the STORE already (the builder is
addMissingNodes: true, so it materialises both endpoints) while its render object waits inpendingEdgesfor theNodeobjects it reads in its constructor. The snapshot is therefore the more complete of the two mid-load. - A NODE whose configured id path yields something graph-format will not accept --
nullfrom a record with no id key, most often -- gets a render object withindex === INVALID_INDEXand no row in the store. The element has always drawn such a record; refusing it would be a new failure in the middle of a data load.
An EDGE is the exception, and deliberately: one whose endpoint ids the store will not take is REJECTED, counted in the import report, and never becomes a render object at all. An edge with no store row could not be filtered -- the per-frame mask forces an unplaced edge visible -- so it was permanently on screen with nothing able to hide it.
Implements ​
Constructors ​
Constructor ​
new DataManager(
eventManager,styles):DataManager
Defined in: graphty-element/src/managers/DataManager.ts:482
Creates an instance of DataManager
Parameters ​
eventManager ​
Event manager for emitting data events
styles ​
Styles
Styles instance for applying styles to data
Returns ​
DataManager
Properties ​
edgeVersion ​
edgeVersion:
number=0
Defined in: graphty-element/src/managers/DataManager.ts:354
Goes up on every edge added or removed, so a cache over the edge set knows it is stale.
meshCache ​
meshCache:
MeshCache
Defined in: graphty-element/src/managers/DataManager.ts:417
nodeCache ​
nodeCache:
Map<NodeIdType,Node>
Defined in: graphty-element/src/managers/DataManager.ts:355
Accessors ​
[WRITABLE_LANE] ​
Get Signature ​
get [WRITABLE_LANE]():
ElementPositions
Defined in: graphty-element/src/managers/DataManager.ts:546
The writable lane, for the element's own engines and nodes. See writableLane.
Returns ​
ElementPositions
the live position array
directionSettledBy ​
Get Signature ​
get directionSettledBy():
DirectionProvenance
Defined in: graphty-element/src/managers/DataManager.ts:565
How the direction of the loaded graph was settled, and by what text.
Returns ​
DirectionProvenance
the provenance; "unsettled" until a file or the configuration says
edges ​
Get Signature ​
get edges():
ReadonlyMap<string,Edge>
Defined in: graphty-element/src/managers/DataManager.ts:346
Every edge the graph holds, keyed by Edge.id.
The key type is string and not string | number, because Edge.id is the element's own edge counter printed as a string and nothing else. While the key was widened, getEdge(0) compiled, answered undefined for the edge whose id is "0", and said nothing about it.
Returns ​
ReadonlyMap<string, Edge>
The edges.
edgesByIndex ​
Get Signature ​
get edgesByIndex(): readonly (
Edge|undefined)[]
Defined in: graphty-element/src/managers/DataManager.ts:363
Render objects by their store edge index, so a freeze report's edgeRemap -- and a removal, which hands back the incident edge indices and nothing else -- can find them in O(1). Sparse: an index with no render object yet, or whose edge was removed, reads undefined.
Returns ​
readonly (Edge | undefined)[]
The edges by row, read-only.
graphResults ​
Get Signature ​
get graphResults():
AdHocData|undefined
Defined in: graphty-element/src/managers/DataManager.ts:389
Graph-level results a plugin algorithm without a descriptor wrote, kept as the graphResults value of the graph. Read-only, except to a plugin while algo.legacy runs it: what it writes then is part of that command's step.
Returns ​
AdHocData | undefined
The value, or undefined when none was written.
Set Signature ​
set graphResults(
value):void
Defined in: graphty-element/src/managers/DataManager.ts:401
Write graph-level results; only a plugin can, while algo.legacy runs it.
Throws ​
A GraphtyError with E_UNSUPPORTED outside a plugin run.
Parameters ​
value ​
AdHocData | undefined
The results.
Returns ​
void
isLoading ​
Get Signature ​
get isLoading():
boolean
Defined in: graphty-element/src/managers/DataManager.ts:1752
Whether a load from a data source is still streaming records in.
A static layout reads it to tell a chunk of a load, after which the whole graph is arranged again, from a reader's add to a finished graph, after which existing nodes stay put.
Returns ​
boolean
true between a load's first chunk and its end
lastImport ​
Get Signature ​
get lastImport():
LoadReport|null
Defined in: graphty-element/src/managers/DataManager.ts:577
What the last load did: which endpoint spelling answered, how many repeats were seen and what the policy did with them, and how many edges the graph actually holds.
A door rather than only an event, because the two load events are fire-and-forget and a consumer that subscribed after the load has no way to ask otherwise.
Returns ​
LoadReport | null
the report, or null when nothing has been loaded into this graph
nodes ​
Get Signature ​
get nodes():
ReadonlyMap<string|number,Node>
Defined in: graphty-element/src/managers/DataManager.ts:331
Every node the graph holds, keyed by id. Read-only: nodes arrive and leave through the data doors, which are undoable steps.
Returns ​
ReadonlyMap<string | number, Node>
The nodes.
positions ​
Get Signature ​
get positions():
ReadonlyElementPositions
Defined in: graphty-element/src/managers/DataManager.ts:535
The element-owned node coordinates: a stride-3 Float32Array indexed by Node.index.
The element owns these, not the snapshot -- every freeze lends the array to the new snapshot as its role: "position" column BY REFERENCE -- so a layout, a drag or a GPU readback writes in one place and nothing is lost when the graph is frozen again. A row that no layout has placed reads as NaN, never as the origin: zero is a real coordinate and "not placed yet" is not.
Read-only here: a write would move nodes with no step. The element's own engines reach the writable lane through writableLane; a consumer places nodes through session.positions.set.
Returns ​
the coordinates, read-only
seededNodeCount ​
Get Signature ​
get seededNodeCount():
number
Defined in: graphty-element/src/managers/DataManager.ts:557
How many nodes the DATA arrived carrying a coordinate for.
Distinct from positions.placedCount, which counts what anything has placed -- including a layout that has run for one frame. See GraphStore.seededNodeCount.
Returns ​
number
the count
snapshotStale ​
Get Signature ​
get snapshotStale():
boolean
Defined in: graphty-element/src/managers/DataManager.ts:508
Whether the next getSnapshot would freeze a new snapshot.
Returns ​
boolean
True when the store is not settled.
Methods ​
addDataFromSource() ​
addDataFromSource(
type,opts?,load?):Promise<void>
Defined in: graphty-element/src/managers/DataManager.ts:1834
Loads data from a registered data source, as one step: a data.import on its turn in the queue. A REPLACING load empties the graph in the same step, and a load that fails rolls the whole step back, so a malformed or empty file leaves the graph it would have replaced exactly as it was.
A load that reads no node records and no edge records at all fails with E_EMPTY_LOAD rather than completing with zero counts. A file of edges alone is not empty: its endpoints become nodes.
The load that STARTED last wins. Once a replacing load has started, every load started before it -- replacing or additive -- is superseded: it adds nothing more and rejects with E_SUPERSEDED, whichever order the sources finish in. A superseded load emits no data-loading-error, because nothing went wrong with its source.
Parameters ​
type ​
string
Data source type identifier
opts? ​
object = {}
Options to pass to the data source
load? ​
Which load this is, for every event it emits, and whether it replaces the graph
coalesce? ​
string
The key imports coalesce under while the first waits its turn
generation? ​
number
The place beginLoad reserved for this load when the caller's call was made; left unset, the load takes its place now
loadId? ​
number
The id every event about this load carries
replace? ​
boolean
Swap the graph for what the source holds, once it has all parsed
setup? ​
boolean
Declared at construction: it becomes the baseline
Returns ​
Promise<void>
addEdge() ​
addEdge(
edge,options?):void
Defined in: graphty-element/src/managers/DataManager.ts:1582
Adds a single edge to the graph
Parameters ​
edge ​
Edge data object
options? ​
AddEdgesOptions
the endpoint expressions and the repeat policy for this call
Returns ​
void
addEdges() ​
addEdges(
edges,options?):void
Defined in: graphty-element/src/managers/DataManager.ts:1608
Add edge records to the graph, resolving their endpoints once for the whole batch.
THREE THINGS HAPPEN HERE THAT USED TO HAPPEN ELSEWHERE OR NOT AT ALL.
The endpoint spelling is decided once per batch and reported, rather than read from two configured paths whose defaults disagreed with every guide the element ships. A batch whose records answer none of the accepted spellings throws instead of quietly producing a graph with nodes and no edges.
A record naming an ordered pair the graph already holds is handed to the repeat policy, which by default KEEPS it as a second edge. It used to be dropped before the store could see it, which is why statistics().repeatedEdgeCount has always been zero.
A record whose endpoint ids graph-format will not store is REJECTED and counted, rather than becoming a render object with no store row -- which is how an edge ended up permanently visible and unfilterable.
Parameters ​
edges ​
Record<string | number, unknown>[]
Array of edge data objects
options? ​
AddEdgesOptions
the endpoint expressions and the repeat policy for this call
Returns ​
void
Throws ​
A GraphtyError with E_EDGE_ENDPOINTS_UNRESOLVED when no spelling answers, and with E_DUPLICATE_EDGE under the "error" repeat policy.
addNode() ​
addNode(
node,idPath?):void
Defined in: graphty-element/src/managers/DataManager.ts:1322
Adds a single node to the graph
Parameters ​
node ​
Node data object
idPath? ​
string
JMESPath expression to extract node ID from data
Returns ​
void
addNodes() ​
addNodes(
nodes,idPath?):void
Defined in: graphty-element/src/managers/DataManager.ts:1353
Adds multiple nodes to the graph
Parameters ​
nodes ​
Record<string | number, unknown>[]
Array of node data objects
idPath? ​
string
JMESPath expression to extract node ID from data
Returns ​
void
beginLoad() ​
beginLoad(
replace):number
Defined in: graphty-element/src/managers/DataManager.ts:1899
Reserve a load's place in line, at the moment the caller asked for it.
A caller that reads a file or sniffs a URL before it loads calls this FIRST, so a load that was asked for later still wins however long the earlier one spends reading. A replacing load supersedes every load reserved before it.
Parameters ​
replace ​
boolean
Whether the load will replace the graph
Returns ​
number
The generation to hand to addDataFromSource and throwIfSuperseded
bindSession() ​
bindSession(
dispatcher,hooks):void
Defined in: graphty-element/src/managers/DataManager.ts:592
Write through the session from here on: the data doors dispatch data.apply and data.import, and the session carries both out through this manager's ingest, over this manager's store.
Parameters ​
dispatcher ​
Dispatcher
The session's dispatcher.
hooks ​
What the graph does around a write.
loading ​
Called with true when an import starts reading and false when it stops.
removing ​
Called with the nodes and edges a removal names, before it writes.
rowsAdded ​
Called by each command that adds rows, after it wrote them, with how that command starts work as its deferred members.
Returns ​
void
clear() ​
clear():
void
Defined in: graphty-element/src/managers/DataManager.ts:1935
Remove every node, edge, record and graph-level value, as one undoable step.
Returns ​
void
dispose() ​
dispose():
void
Defined in: graphty-element/src/managers/DataManager.ts:1297
Disposes of the data manager and cleans up all resources
Returns ​
void
Implementation of ​
getEdge() ​
getEdge(
edgeId):Edge|undefined
Defined in: graphty-element/src/managers/DataManager.ts:1704
Gets an edge by its ID
Parameters ​
edgeId ​
string
Edge identifier
Returns ​
Edge | undefined
Edge instance or undefined if not found
getEdgesBetween() ​
getEdgesBetween(
srcNodeId,dstNodeId): readonlyEdge[]
Defined in: graphty-element/src/managers/DataManager.ts:1722
Every edge running from one node to another.
Plural because "the edge between a and b" stopped being a single thing the moment parallel edges became representable.
Answered by the store: the builder's incidence lists name the live edges between the two rows, and edgesByIndex turns each into its render object. An edge whose render object is still pending is left out, and so, in an undirected graph, is an edge recorded the other way round -- the pair is ORDERED, the same question for either direction.
Parameters ​
srcNodeId ​
Source node identifier
dstNodeId ​
Destination node identifier
Returns ​
readonly Edge[]
the edges, oldest first; empty when there are none
getNode() ​
getNode(
nodeId):Node|undefined
Defined in: graphty-element/src/managers/DataManager.ts:1498
Gets a node by its ID, in either of the two types an integer id can be written as.
The map is keyed on the id the source file carried, untouched: GML parses a bare integer with parseInt, so the shipped Karate Club and Football samples hold NUMBER keys, while every id that has been through a URL, a DOM attribute, a JSON document or a consumer's own UI is a string by the time it comes back. Map.get("34") misses the key 34 in silence -- no throw, no event -- so pin, selectNode and zoomToNodes were no-ops on exactly those samples, and the one consumer carried its own retry for the two verbs whose return value made the miss detectable at all.
The exact key always wins, so a graph holding both 34 and "34" is unaffected. The retry is integers only: a float or a hexadecimal id would round-trip through Number into a different value than the file carried, and finding an id the file never had is worse than a lookup that missed.
Parameters ​
nodeId ​
Node identifier
Returns ​
Node | undefined
Node instance or undefined if not found
getSnapshot() ​
getSnapshot():
GraphSnapshot
Defined in: graphty-element/src/managers/DataManager.ts:500
The current graph snapshot, freezing first when records have arrived since the last one.
The same object is returned until the graph changes again, so a burst of records -- through the operation queue, through skipQueue, or through addDataFromSource, which bypasses the queue entirely -- costs exactly one freeze however many readers ask afterwards. The snapshot is immutable; the node coordinates it carries are not, because the element lends it positions by reference.
Returns ​
the snapshot
getStats() ​
getStats():
object
Defined in: graphty-element/src/managers/DataManager.ts:1954
Get statistics about the data
Returns ​
object
the node and edge counts the graph holds -- the same numbers statistics() and the stats panel give -- and the cached mesh count
cachedMeshes ​
cachedMeshes:
number
edgeCount ​
edgeCount:
number
nodeCount ​
nodeCount:
number
heldCounts() ​
heldCounts():
object
Defined in: graphty-element/src/managers/DataManager.ts:1762
What the graph HOLDS right now: the node and edge counts of the store, the same numbers statistics() and the import report give. An edge endpoint no record declared as a node is counted, and so is an edge still waiting for an endpoint.
Returns ​
object
the node and edge counts the graph holds
edges ​
edges:
number
nodes ​
nodes:
number
init() ​
init():
Promise<void>
Defined in: graphty-element/src/managers/DataManager.ts:1259
Initializes the data manager
Returns ​
Promise<void>
Promise that resolves when initialization is complete
Implementation of ​
reconcile() ​
reconcile(
slice,dirty,cause):object
Defined in: graphty-element/src/managers/DataManager.ts:713
Bring the render objects in line with the graph slice: what the derivation lane's graph hook runs, forward and on undo, redo and rollback alike. A node or edge the slice holds and nothing draws is built; one drawn that the slice no longer holds is torn down; one whose record changed is handed the new record. Forward adds were drawn as they were ingested, so for them this finds nothing to build.
Parameters ​
slice ​
GraphSlice
The slice to draw.
dirty ​
ReadonlySet<string>
The slice's keys changed since the last pass.
cause ​
What moved the state, for the events.
Returns ​
object
How many rows were built and torn down.
added ​
added:
number
removed ​
removed:
number
removeEdge() ​
removeEdge(
edgeId):boolean
Defined in: graphty-element/src/managers/DataManager.ts:1799
Removes an edge from the graph
Parameters ​
edgeId ​
string
Edge identifier to remove
Returns ​
boolean
True if the edge was removed, false if not found
removeNodeAndIncidentEdges() ​
removeNodeAndIncidentEdges(
nodeId): readonlystring[] |null
Defined in: graphty-element/src/managers/DataManager.ts:1523
Remove a node AND every edge attached to it, as one undoable step.
The cascade is what the name says, and it used to be missing: the store side already tombstoned the incident edges, but their render objects survived with their meshes, their place in the layout engine's own lists and a hard reference to the disposed Node. Three things followed from that, all of them visible to a reader. The edge kept drawing, because the frame loop walks the engine's list rather than this manager's. The edge became permanently visible and unfilterable, because the mask application forces an edge with no store row visible. And the removed Node stayed reachable through Edge.srcNode, so disposing it freed the Babylon resources and not the JavaScript retention -- which on a large graph is the removal leak that matters.
Parameters ​
nodeId ​
Node identifier to remove
Returns ​
readonly string[] | null
the ids of the edges that went with it, or null when there was no such node
setEdges() ​
setEdges(
edges,options?):void
Defined in: graphty-element/src/managers/DataManager.ts:1779
Replace every built edge with a new set, or leave the graph exactly as it was.
The ceiling is decided BEFORE anything is removed. Removing first and letting addEdges refuse would leave a host that assigned too many edges with its old edges gone and none of the new ones held, which is neither the graph it had nor the one it asked for. The new batch is counted against an emptied graph, since the old edges are what it replaces; a pending edge, whose endpoints have not arrived, survives the replace as it always has.
Parameters ​
edges ​
Record<string | number, unknown>[]
the edges the graph should hold afterwards
options? ​
AddEdgesOptions
the endpoint expressions and the repeat policy for this call
Returns ​
void
Throws ​
A GraphtyError with E_TOO_LARGE when the new set is past the ceiling, and whatever addEdges throws.
setGraphContext() ​
setGraphContext(
context):void
Defined in: graphty-element/src/managers/DataManager.ts:1238
Set the GraphContext for creating nodes and edges
Parameters ​
context ​
GraphContext instance to use for node/edge creation
Returns ​
void
setLayoutEngine() ​
setLayoutEngine(
engine):void
Defined in: graphty-element/src/managers/DataManager.ts:1251
Set the layout engine reference for managing node and edge positions
Parameters ​
engine ​
LayoutEngine | undefined
Layout engine instance or undefined to clear
Returns ​
void
setNodes() ​
setNodes(
nodes,idPath?):void
Defined in: graphty-element/src/managers/DataManager.ts:1333
Replace every node with these, as one step: a node the records name again keeps its row and its edges, and one they no longer name goes, with its edges. A set past the render ceiling is refused with E_TOO_LARGE and the step rolls back, so the graph keeps the nodes it had.
Parameters ​
nodes ​
Record<string | number, unknown>[]
the nodes the graph should hold afterwards
idPath? ​
string
JMESPath expression to extract the id; the configured node id path when unset
Returns ​
void
sliceProblems() ​
sliceProblems(
slice):string[]
Defined in: graphty-element/src/managers/DataManager.ts:672
Strict state: the drawn maps keyed exactly like the graph slice. An edge the slice holds may instead be waiting for an endpoint that has not arrived.
Parameters ​
slice ​
GraphSlice
The slice the last pass derived.
Returns ​
string[]
One sentence per problem; empty when there is none.
startLabelAnimations() ​
startLabelAnimations():
void
Defined in: graphty-element/src/managers/DataManager.ts:1943
Start label animations for all nodes Called when layout has settled
Returns ​
void
supersedeLoads() ​
supersedeLoads():
void
Defined in: graphty-element/src/managers/DataManager.ts:1912
Abandon every load in flight: each rejects with E_SUPERSEDED, its step rolled back, and adds nothing. The element's clearData calls this, so a load finishing after the graph was closed does not bring its data back.
Returns ​
void
throwIfSuperseded() ​
throwIfSuperseded(
generation,type):void
Defined in: graphty-element/src/managers/DataManager.ts:1924
Throw E_SUPERSEDED when a load reserved at generation has been overtaken.
Parameters ​
generation ​
number
What beginLoad returned for the load
type ​
string
The load's format, for the message
Returns ​
void
undirected() ​
undirected(
snapshot):DerivedGraph
Defined in: graphty-element/src/managers/DataManager.ts:517
The undirected view of a snapshot, built once per snapshot and cached.
Parameters ​
snapshot ​
a snapshot this manager produced
Returns ​
the derived graph, including the edge remap an edge-result adapter needs
updateStyles() ​
updateStyles(
styles):void
Defined in: graphty-element/src/managers/DataManager.ts:1230
Update the configuration document reference when it changes
Parameters ​
styles ​
Styles
New configuration document to read from
Returns ​
void