Skip to content

NetworkLODOptions

Defined in: network/network.ts:544

Level-of-detail (#103): an adaptive hierarchy cut so a large network draws only what’s visible. Each pan/zoom re-cuts a retained coarsening tree — dense regions collapse to aggregate glyphs and expand into their members as you zoom in, as soon as their glyphs would no longer overlap (#426) — bounding per-frame work to the visible frontier. Opt-in via Network.lod; off by default (every node/link drawn). The tree’s geometry updates as the layout converges (so LOD helps during the solve, not only after), and the zoom-time path re-cuts only the visible frontier. Best paired with style({ sizeMode: "screen" }).

On the WebGL lane the cut re-runs live every pan/zoom frame. On the Canvas/SVG (retained) backends the same frontier draws as Scene layers — so toSVG() exports a level-of-detail map (#138) — but the retained Scene can’t re-tessellate per frame, so there the frontier is static during a gesture and re-cuts on release, and after a programmatic setTransform while zoom is enabled (the redraw-on-zoom-end model; force one with Network.syncScreenGeometry).

optional aggregateFill?: string

Defined in: network/network.ts:606

Aggregate-glyph fill (any CSS color). Default = nodeFill.


optional aggregateOutline?: false | { color?: string; gap?: number; opacity?: number; width?: number; }

Defined in: network/network.ts:638

Mark aggregate glyphs (collapsed modules/subtrees, not leaves) with a thin outline ring set a gap px outside the glyph, so it reads as expandable — distinguishing a collapsed module from an individual node at intermediate zoom. width/gap in px (default 1.5 / 2.5), color any CSS colour (default a dark neutral), opacity 0-1 (default 1).

Default: with moduleBoundary set, collapsed modules get the same line as expanded ones (its width, color and opacity, at the default gap), so a module keeps one outline whether it is collapsed or open. Without it, off. Pass an object to style it separately, or false to turn it off.


optional coarsen?: CoarsenOptions

Defined in: network/network.ts:716

Coarsening granularity for the LOD tree (depth / minimum aggregate size).


optional crossFade?: number

Defined in: network/network.ts:714

Cross-fade level transitions (#133): the half-width, as a fraction of expandPx, of the zoom band around the expand threshold over which an aggregate and its children are drawn together — the aggregate easing out (opacity 1→0) as its children ease in (0→1, smoothstep) — so a split/merge reads smoothly instead of popping. e.g. 0.3 fades over [expandPx·0.7, expandPx·1.3]. Applies to the frontier glyphs, their borders/halos, and the super-edges (which fade with their endpoints).

Off by default and zero added cost when off (0/omitted ⇒ the hard threshold): only the transitioning band of the frontier is doubled, and the per-node alpha pass runs only when set.


optional crossLevelEdges?: boolean

Defined in: network/network.ts:703

Also draw super-edges between mixed-level visible nodes — a visible leaf (or finer aggregate) and a visible coarser aggregate at a different cut level (the collapsed↔expanded mismatch). By default such an edge is dropped: when you zoom into one region, its leaves lose their links to the still-collapsed regions until both sides are at the same level again. With this on, the off-frontier on-screen endpoint is projected to its nearest present ancestor and the edge is drawn there (flows deduped), so aggregates keep their context across a mixed frontier (#139).

Off by default and zero added cost when off — the projection (an O(depth) ancestor walk per off-frontier on-screen edge + a dedup map) runs only when enabled; the same-level gather is unchanged. Needs the directed super-edge CSR (the cut drawing a module hierarchy); ignored otherwise.


optional declutter?: boolean

Defined in: network/network.ts:619

Thin overlapping frontier glyphs in screen space, keeping the most important (by strength) and hiding a glyph whose centre is within declutterSpacing·(rᵢ + rⱼ) of a kept glyph — so dense regions stay readable instead of a solid mass. Zoom-dependent (more resolve as you zoom in). Default true; false hides nothing.


optional declutterSpacing?: number

Defined in: network/network.ts:626

Spacing multiplier for declutter: a glyph is hidden when its centre is within declutterSpacing·(rᵢ + rⱼ) of a kept glyph. Default 2: kept glyphs keep a gap around them, so the links between them stay visible. The cost: in a small graph a whole non-overlapping module aggregate can be hidden (#512). 1 hides only real overlaps; <1 lets glyphs overlap partly.


optional expandPx?: number

Defined in: network/network.ts:604

Expand threshold (px): an aggregate whose on-screen footprint (2·extent·k) reaches this expands into its children; below it it draws as a single glyph — unless its members’ glyphs would not overlap at the current zoom, when it expands whatever its size (#426: an aggregate is drawn only where its members would overlap, so a small graph opens on every node). The threshold therefore sets how coarse the map is where members would overlap. Larger → coarser (fewer, bigger aggregates). After a layout({ nested }), a module’s extent is its disc’s radius (#329).

Omit it to get the tree-adaptive default (#191), which scales with how many children the tree’s finest aggregates hold: 48 px for structural coarsening / a spatial quadtree (unchanged), ~190–280 px for a provided module partition — so lod({ modules }) opens on a map of modules instead of raw nodes. Set it to pin an absolute pixel size (the meaning is unchanged).


optional maxAggregateRadius?: number

Defined in: network/network.ts:612

Cap on an aggregate glyph’s draw radius (in the active sizeMode’s units). The tree’s area-additive radius grows with subtree size — fine in world units, but set this (e.g. ~24) in screen mode so large aggregates stay readable rather than ballooning to hundreds of pixels.


optional moduleBoundary?: object

Defined in: network/network.ts:682

Draw a thin boundary ring around every expanded module in view (#329) — the aggregates the cut has opened into their members (in a crossFade band: those whose members it draws), so the hierarchy stays readable as a map of nested modules while you zoom in. After a layout({ nested }) of the tree being cut, the ring is that module’s disc — which is then also the module’s LOD geometry, so it follows its members through a drag or a transition; otherwise it is centred on the module’s members with their extent as its radius. width in the active sizeMode’s units (constant px in screen mode, default 1), color any CSS colour (default a dark neutral), opacity 0-1 (default 0.5). Rings are drawn above the links and below the nodes (#471), so a dense module’s links never hide its boundary; they fade with the members they enclose under crossFade, and export with toSVG() / toPNG(). Omit to disable.

Per module (#471). A ring can be styled by its module:

  • color: "fill" — each ring in its module’s own fill, the colour the collapsed module is drawn in (its NetworkStyle.nodeFill module colour, or aggregateFill).
  • width: (path) => number | undefined — each ring’s width by the module’s Infomap path (e.g. [2, 1] = sub-module 1 of top module 2), in the active sizeMode’s units — e.g. the module’s enter flow through the flow border’s scale, so the boundary reads as the flow into the module. undefined (or a tree that is not a module hierarchy, whose aggregates have no path) takes the constant default; 0 draws no ring.

Both are resolved once per module when the style is resolved against the tree (like FlowBorderSpec.moduleFlow) — again on a style() or lod() call or a new tree — never per frame. A collapsed module’s default aggregateOutline still takes moduleBoundary’s line, with the constant defaults standing in for a width accessor and "fill".

With crossLevelEdges on, a module link (data(graph, { modules, moduleLinks }), #199) whose endpoint is an expanded module in view — one that no finer pair can carry, as in an Infomap .ftree — is drawn to or from that module’s ring, with its flow, instead of disappearing when the module opens. Links between two expanded modules run ring to ring. Where the two circles overlap (routine for the centroid + extent rings, or when the other end sits inside the ring) there is no gap to run it across, so it runs between their centres instead. An expanded module whose centre is off-screen keeps the off-screen rule (its links are drawn toward its centre, leaving the view). Links derived from the graph’s own edges are unchanged (their flow is drawn at the members), so nothing is counted twice.

Per frame the cost is O(1) per module in view the cut expands (it visits them anyway; the walk is the same with rings on or off) plus, when anchoring, their own module links — never the whole tree.

Picking (#476). A ring is how an open module is pointed at: hover, click and select it on its ring (see Network.interactive); the hit is the module’s own, with datum.open === true. A pointer move tests the rings the frame drew, O(rings drawn), allocation-free, and resolves nothing.

optional color?: string

optional opacity?: number

optional width?: number | ((path) => number | undefined)


optional moduleLinks?: ArrayLike<ModuleLink>

Defined in: network/network.ts:590

Module-level links for modules (#199) — prefer data(graph, { modules, moduleLinks }). Summed into the map’s super-edges alongside those derived from the graph’s edges. Requires modules.

NetworkDataOptions.moduleLinks


optional modules?: ArrayLike<ModuleNode>

Defined in: network/network.ts:584

A module hierarchy scoped to these LOD options — prefer Network.data(graph, { modules }), which the engine keeps across lod(false) and every LOD source (#326). Kept as a back-compat alias: when given, it takes priority over the engine hierarchy for the cut and every other module consumer (nested layout, GPU seed, hit paths) while these options are set, and lod(false) drops it.

Pass Infomap’s JSON nodes array directly — each record’s id is the dense node index (aligned with buildGraph) and path its 1-based module chain. Records must cover every node.

buildModuleLODTree


optional source?: "structure" | "spatial" | "modules"

Defined in: network/network.ts:573

Which hierarchy the cut draws (#326, #343).

  • "modules" — the default whenever the engine holds a module hierarchy (Network.data(graph, { modules })) — cuts that module tree: modules expand → sub-modules → leaves on zoom.
  • "structure" — the default without one — coarsens the graph structurally (heavy-edge matching): an aggregate is a tightly-linked group of nodes, wherever the layout put its members.
  • "spatial" groups nodes by where they are: a quadtree over the layout (up to 8 nodes per bottom cell), so an aggregate is always a compact region, drawn where its members are. On a force layout that spreads communities apart (web graphs), the structural tree’s aggregates cover the whole view and the cut draws a large share of the graph at every zoom; the spatial one keeps the frontier bounded by the screen (a few hundred to ~2k glyphs) and its per-frame cost small. The tree follows the positions: the "worker" backend rebuilds it off the main thread on every streamed frame, and so does the "gpu" backend’s LOD worker for every frame the GPU reads back (both stop once the layout has converged); the other backends rebuild it when a layout lands, and a position transition or a drag refits it until the nodes come to rest. An aggregate’s id changes with each rebuild, so a selected or hovered aggregate is carried over to the cell in the same place; leaves keep their ids — read a hit’s members() when the event fires, as the tree it came from is replaced by the next streamed frame. Super-edges are summed from the graph’s edges per frame (no super-edge table is built): that costs O(edges of the drawn glyphs’ members) whenever the view changes — ~10 ms at the fit view for 1.5M edges, ~190 ms for 5.8M — so the source suits graphs up to a few hundred thousand nodes. Aggregates are sized area-additively.

An edge-less graph always gets the spatial tree. With a hierarchy, "structure" and "spatial" still leave it driving the nested layout, the GPU module seed and NetworkHit.path. An explicit modules here overrides the source.


optional spatial?: SpatialLODOptions

Defined in: network/network.ts:721

Options for the spatial tree (#103, #343): source: "spatial", and every edge-less graph (which cannot be coarsened). bucket (default 8) is the most nodes a bottom cell holds.


optional superEdges?: boolean

Defined in: network/network.ts:690

Draw super-edges: links between both-visible frontier nodes (leaf↔leaf, module↔module, or aggregate↔aggregate — whatever the cut exposes), sized + coloured by their accumulated flow and rendered in the active linkStyle. In a ragged module tree, where leaves sit at different depths, a leaf is also linked to a visible deeper node (a finer module or a deeper leaf) holding the other end of one of its edges (#325). Default true.

superEdges