Skip to content
D
Documentation

Layout — classes

reference
5 min readUpdated

Classes

Import these from @grafloria/engine.

Classes

BaseLayoutAlgorithm

Base abstract class for layout algorithms

Provides common functionality that all layout algorithms can use. Extend this class when implementing a new layout algorithm.

ts
abstract class BaseLayoutAlgorithm implements ILayoutAlgorithm

Methods

  • constructor(config?: LayoutConfiguration)
  • abstract getName(): string — Get the name of the layout algorithm
  • abstract getType(): 'grid' | 'force-directed' | 'hierarchical' | 'hybrid' — Get the type of the layout algorithm
  • abstract calculatePlacement(options: PlacementOptions): PlacementResult — Calculate position for a single new node

This is called when a node is added to the diagram. The algorithm should return a position that:

  • Doesn't overlap with existing nodes
  • Follows the layout strategy
  • Fits within the viewport (or is close to existing content)
  • abstract reLayout(diagram: DiagramModel, config?: LayoutConfiguration): Map<string, Point> — Re-layout all nodes in the diagram

This is called when the user explicitly requests a re-layout (e.g., clicks "Re-Arrange" button). The algorithm should calculate new positions for ALL nodes.

  • configure(config: LayoutConfiguration): void — Configure the layout algorithm
  • getConfiguration(): LayoutConfiguration — Get current configuration
  • canApply(diagram: DiagramModel): { valid: boolean; reason?: string } — Validate if this algorithm can be applied to the given diagram

For example:

  • Hierarchical layout requires a DAG (no cycles)
  • Force-directed works better with connected nodes

CommunityLayoutAdapter

Community Detection Layout Adapter

Uses Louvain algorithm to detect communities and arranges them.

ts
class CommunityLayoutAdapter implements LayoutAdapter

Properties

NameTypeDefaultDescription
name'community'Name of the layout adapter (e.g., 'dagre', 'elk')

Methods

  • async apply( nodes: NodeModel[], links: LinkModel[], options: Partial<CommunityLayoutOptions> = {} ): Promise<LayoutResult> — Apply community detection layout
  • async applyIncremental( nodes: NodeModel[], links: LinkModel[], incrementalOptions: any, layoutOptions?: Partial<CommunityLayoutOptions> ): Promise<LayoutResult & { incremental: any }> — Apply incremental layout
  • validateOptions(options: Partial<CommunityLayoutOptions>): boolean — Validate options

CompoundLayoutService

ts
class CompoundLayoutService

Methods

  • constructor( private readonly diagram: DiagramModel, private readonly options: CompoundLayoutOptions = {} )
  • async layout(): Promise<CompoundLayoutResult> — Run the compound layout over the whole diagram.

ConstraintManager

Helper class for managing and applying layout constraints

ts
class ConstraintManager

Methods

  • constructor(constraints?: LayoutConstraints)
  • addConstraints(constraints: LayoutConstraints): void — Add constraints to the manager
  • getConstraints(nodeId: string): NodeConstraint[] — Get all constraints for a specific node
  • hasConstraints(nodeId: string): boolean — Check if a node has any constraints
  • applyConstraints( nodeId: string, proposedPosition: Position, conflictResolution: 'priority' | 'first' | 'last' = 'priority' ): Position — Apply constraints to a position, returning the constrained position
  • clear(): void — Clear all constraints
  • removeConstraints(nodeId: string): void — Remove constraints for a specific node
  • getConstrainedNodeCount(): number — Get total number of constrained nodes
  • getConstrainedNodeIds(): string[] — Get all constrained node IDs

DagreLayoutAdapter

Dagre Layout Adapter

Provides hierarchical layout using the Dagre library. Converts between Grafloria's node/link model and Dagre's graph structure.

ts
class DagreLayoutAdapter implements LayoutAdapter

Properties

NameTypeDefaultDescription
name'dagre'Name of the layout adapter (e.g., 'dagre', 'elk')

Methods

  • async apply( nodes: NodeModel[], links: LinkModel[], options: Partial<DagreLayoutOptions> = {} ): Promise<LayoutResult> — Apply Dagre layout to nodes and links
  • validateOptions(options: Partial<DagreLayoutOptions>): boolean — Validate Dagre layout options
  • async applyIncremental( nodes: NodeModel[], links: LinkModel[], incrementalOptions: IncrementalLayoutOptions, layoutOptions?: Partial<DagreLayoutOptions> ): Promise<LayoutResult & { incremental: IncrementalLayoutResult }> — Apply incremental layout - layout new nodes while preserving existing positions

EdgeBundlingManager

Edge bundling computation utilities

ts
class EdgeBundlingManager

Methods

  • static computeBundling( edges: EdgeInfo[], nodePositions: Map<string, Point2D>, portPositions: Map<string, Point2D>, options: EdgeBundlingOptions ): EdgeBundlingResult (static) — Compute edge bundling for a set of edges

ELKLayoutAdapter

ELK Layout Adapter

Provides advanced layout algorithms using the Eclipse Layout Kernel. Supports multiple algorithms with extensive configuration options.

ts
class ELKLayoutAdapter implements LayoutAdapter

Properties

NameTypeDefaultDescription
name'elk'Name of the layout adapter (e.g., 'dagre', 'elk')

Methods

  • async apply( nodes: NodeModel[], links: LinkModel[], options: Partial<ELKLayoutOptions> = {} ): Promise<LayoutResult> — Apply ELK layout to nodes and links
  • validateOptions(options: Partial<ELKLayoutOptions>): boolean — Validate ELK layout options
  • async applyIncremental( nodes: NodeModel[], links: LinkModel[], incrementalOptions: IncrementalLayoutOptions, layoutOptions?: Partial<ELKLayoutOptions> ): Promise<LayoutResult & { incremental: IncrementalLayoutResult }> — Apply incremental layout - layout new nodes while preserving existing positions

ForceLayoutAdapter

Force-Directed Layout Adapter

Implements Fruchterman-Reingold algorithm with Barnes-Hut optimization.

ts
class ForceLayoutAdapter implements SteppableLayoutAdapter

Properties

NameTypeDefaultDescription
name'force'Name of the layout adapter (e.g., 'dagre', 'elk')

Methods

  • createRun( nodes: NodeModel[], links: LinkModel[], options: Partial<ForceLayoutOptions> = {} ): LayoutRun — The simulation, exposed one iteration at a time.

This is where the physics lives, and it is the ONLY place it lives: apply() below is now just "drive this to convergence". Splitting the loop out (rather than copying it into a worker-flavoured twin) is what keeps the off-thread path honest — the worker and the main thread run the same arithmetic in the same order, so they cannot drift.

Pure and synchronous: no clock, no DOM, and randomness only through the seeded generator. Those three abstinences are the whole reason a worker run and an inline run produce byte-identical coordinates.

snapshot() is meaningful after ANY number of steps, which is what makes a cancelled force layout return the 200-iteration picture it already has instead of throwing it away.

  • async apply( nodes: NodeModel[], links: LinkModel[], options: Partial<ForceLayoutOptions> = {} ): Promise<LayoutResult> — Apply force-directed layout (run the simulation to convergence).
  • async applyIncremental( nodes: NodeModel[], links: LinkModel[], incrementalOptions: any, layoutOptions?: Partial<ForceLayoutOptions> ): Promise<LayoutResult & { incremental: any }> — Apply incremental layout
  • validateOptions(options: Partial<ForceLayoutOptions>): boolean — Validate options

IncrementalLayoutManager

Helper class for managing incremental layouts

ts
class IncrementalLayoutManager

Methods

  • static identifyNewNodes( nodes: NodeModel[], options: IncrementalLayoutOptions ): string[] (static) — Identify new nodes that need to be laid out
  • static identifyExistingNodes( nodes: NodeModel[], newNodeIds: string[] ): string[] (static) — Identify existing nodes that should be constrained
  • static generateConstraints( nodes: NodeModel[], options: IncrementalLayoutOptions ): LayoutConstraints (static) — Generate constraints for incremental layout based on strategy
  • static calculateResult( nodes: NodeModel[], oldPositions: Map<string, { x: number; y: number }>, newNodeIds: string[], constraints: LayoutConstraints, strategy: IncrementalLayoutStrategy ): IncrementalLayoutResult (static) — Calculate movement statistics after incremental layout

LayoutHistory

Layout History Manager

Manages undo/redo stack for layout operations

ts
class LayoutHistory

Methods

  • constructor(options: LayoutHistoryOptions = {})
  • pushSnapshot( nodes: NodeModel[], description?: string, algorithm?: string, options?: any ): LayoutSnapshot — Create and push a new snapshot
  • undo(): LayoutSnapshot | undefined — Undo to previous snapshot
  • redo(): LayoutSnapshot | undefined — Redo to next snapshot
  • canUndo(): boolean — Check if undo is possible
  • canRedo(): boolean — Check if redo is possible
  • getCurrentSnapshot(): LayoutSnapshot | undefined — Get current snapshot
  • getAllSnapshots(): LayoutSnapshot[] — Get all snapshots
  • getSnapshotById(id: string): LayoutSnapshot | undefined — Get snapshot by ID
  • restoreSnapshot(id: string): LayoutSnapshot | undefined — Restore a specific snapshot by ID
  • clear(): void — Clear all history
  • size(): number — Get history size
  • getCurrentIndex(): number — Get current index in history
  • static applySnapshot(snapshot: LayoutSnapshot, nodes: NodeModel[]): number (static) — Apply snapshot to nodes
  • exportToJSON(): string — Export history to JSON
  • importFromJSON(json: string): boolean — Import history from JSON
  • getStatistics(): { totalSnapshots: number; currentIndex: number; canUndo: boolean; canRedo: boolean; oldestTimestamp: number; newestTimestamp: number; averageInterval: number; } — Get history statistics

LayoutHost

The caller-side host.

Pass a real Worker (or anything satisfying LayoutPort) to run off-thread; pass nothing to run inline on the same thread. Identical behaviour, no protocol drift, because BOTH paths speak through serveLayout.

ts
class LayoutHost

Methods

  • constructor(port?: LayoutPort, deps: ServeLayoutDeps = {})
  • run( algorithm: string, graph: LayoutGraph, options: LayoutWireOptions = {}, runOptions: LayoutRunOptions = {} ): Promise<HostLayoutResult>

LayoutPresets

Predefined layout presets for common scenarios

ts
class LayoutPresets

Properties

NameTypeDefaultDescription
HIERARCHICAL (static)LayoutPresetCategoryOrganizational/Hierarchical Layouts
FLOW (static)LayoutPresetCategoryProcess/Flow Layouts
NETWORK (static)LayoutPresetCategoryNetwork/Graph Layouts
ARCHITECTURE (static)LayoutPresetCategoryArchitecture/System Layouts
INTERACTIVE (static)LayoutPresetCategoryInteractive/Dashboard Layouts

Methods

  • static getAllCategories(): LayoutPresetCategory[] (static) — Get all preset categories
  • static getAllPresets(): LayoutPreset[] (static) — Get all presets across all categories
  • static findPreset(id: string): LayoutPreset | undefined (static) — Find preset by ID
  • static findPresetsByTag(tag: string): LayoutPreset[] (static) — Find presets by tag
  • static findPresetsByAdapter(adapter: 'dagre' | 'elk'): LayoutPreset[] (static) — Find presets by adapter type
  • static searchPresets(query: string): LayoutPreset[] (static) — Search presets by name or description

LayoutQualityMetrics

Layout Quality Metrics Calculator

ts
class LayoutQualityMetrics

Methods

  • static assess( nodes: NodeModel[], links: LinkModel[], options: QualityAssessmentOptions = {} ): LayoutQualityResult (static) — Assess the quality of a layout

LayoutRegistry

The named-algorithm registry.

ts
class LayoutRegistry

Methods

  • register(engine: RegisteredLayout): () => void
  • get(name: string): RegisteredLayout | undefined
  • has(name: string): boolean
  • names(): string[] — Registered names, sorted — a stable list is part of being deterministic.
  • adapters(): Record<string, LayoutAdapter> — Name → adapter, for every registered engine that exposes one.

This is what nested (compound) layout resolves a container's algorithm against — so group.subgraphLayout = { algorithm: 'force' } works, and so does an algorithm an extension registered, rather than only the hard-coded dagre|elk pair.

LayoutService

Layout Service

Manages layout adapters and provides a unified API for applying layouts. Can be used as a singleton or instantiated per diagram.

ts
class LayoutService

Methods

  • constructor()
  • registerAdapter(adapter: LayoutAdapter): void — Register a custom layout adapter
  • getAdapter(name: string): LayoutAdapter | undefined — Get a registered adapter by name
  • getAdapterNames(): string[] — Get all registered adapter names
  • async applyLayout(diagram: DiagramModel, config: ApplyLayoutConfig): Promise<LayoutResult> — Apply layout to diagram

SpectralLayoutAdapter

Spectral Layout Adapter

Uses eigendecomposition of graph Laplacian for optimal layout.

ts
class SpectralLayoutAdapter implements LayoutAdapter

Properties

NameTypeDefaultDescription
name'spectral'Name of the layout adapter (e.g., 'dagre', 'elk')

Methods

  • async apply( nodes: NodeModel[], links: LinkModel[], options: Partial<SpectralLayoutOptions> = {} ): Promise<LayoutResult> — Apply spectral layout
  • async applyIncremental( nodes: NodeModel[], links: LinkModel[], incrementalOptions: any, layoutOptions?: Partial<SpectralLayoutOptions> ): Promise<LayoutResult & { incremental: any }> — Apply incremental layout
  • validateOptions(options: Partial<SpectralLayoutOptions>): boolean — Validate options

Was this page helpful?

Layout — classes — Grafloria