CharDesk Docs

CharGraph layout

Ownership and constraints for source-to-cell graph layout.

HEAD a63778e

CharGraph layout

CharGraph routes diagrams by coordinate model, not Mermaid diagram name:

ModelDiagramsLayout owner
Directed relationshipsFlow, State, Class, and ERELK Layered
Time sequenceSequenceParticipant columns and message rows
Cartesian dataMermaid XY and Vega-Lite fencesCartesianChartSpec and D3 scales

The directed-graph pipeline is:

Mermaid AST -> diagram adapter -> LayoutGraph + presentation sidecar

LayoutGraph -> ELK Layered -> integer cell projection -> GridLayout

GridLayout + presentation sidecar -> CharScene

Mermaid support is a reliable subset. Preprocessing removes comments and splits top-level semicolon statements; a diagram renders only when every remaining statement is consumed. Invalid syntax, unsupported directives, subgraph-edge targets, and subgraph direction overrides preserve the complete source with a diagnostic. The diagnostic remains metadata and never replaces the preserved artifact body. Parsers must not return a partial AST. Sequence activation uses the participant lifeline itself: + activates the receiver and - deactivates the sender; standalone activate and deactivate commands share the same source-ordered timeline as messages, notes, and block boundaries. Both forms support nested intervals. Its sequence.activation style role defaults to the render theme's warning token independently of participant borders.

LayoutGraph owns measured rectangular nodes, containment, labels, directed edges, and rank constraints. It does not own Unicode glyphs, rounded corners, line styles, or UML markers. The sidecar owns node drawing, stroke appearance, and endpoint decoration, keyed by stable layout IDs. ELK owns layering, ordering, crossings, ports, and orthogonal bends. Cell projection owns integer coordinates, compact self-loops, route-aware labels, and topology validation. An independent edge cannot share a node port, marker cell, or collinear route cell; a perpendicular cell crossing remains valid. CharScene alone owns glyph composition. Scene layers decide which contribution is visible, while explicit connections and route bundles decide which contributions may share topology. Container borders sit above edges but never join them; node borders remain connective. Thick Mermaid edges use double-line topology while retaining ASCII arrow markers; CharScene resolves mixed single/double junctions at borders and crossings. A parallel Mermaid style-role canvas records visual meaning without affecting geometry. Serialization groups adjacent equal style roles into CharGraph fragments after layout and CJK-safe cell projection.

Flow assigns alignment priority from topology. On the SCC condensation graph, an edge with a multi-hop alternative is a shortcut; the longest remaining path is the visual backbone. ELK straightens that backbone while shortcuts use an outer corridor. When the remaining backbone is one chain containing every node, integer projection aligns its node centers on the cross axis before endpoint routing. Cycles and parallel edges remain ordinary relationships.

Flow edges opt into structured routing after cell projection. Only compatible, unlabelled fan-out or fan-in edges whose branch nodes occupy the same layer may share an explicit orthogonal bus. Labeled branches and cross-layer shortcuts remain independent. Labels competing at one endpoint reserve layout space; single-path labels remain route-placed. Mermaid edge labels reserve one blank cell on each horizontal side, so they do not visually merge with strokes, markers, or node borders. When continuous ELK attachments collapse onto one cell, Flow keeps the highest-priority aligned edge on the primary side and distributes other endpoint owners across free primary and perpendicular border cells. A bundle is one endpoint owner. Class and ER retain their diagram-specific port policies. A complete bipartite motif remains independent instead of being interpreted as overlapping fan buses. Larger cross-fans use independent ELK ports only when both sides compete and one side has at least three incident edges; ordinary decision fans keep their topology-aligned ports.

Marker cells are terminal and exclusive. After integer projection, invalid independent routes are repaired around nodes, marker corridors, and collinear routes before labels are placed and the scene is composed. Flow repair locks routes in topology-priority order, so lower-priority branches and shortcuts move around the backbone rather than deforming it. Readable Flow routes also prefer one visible line cell between an endpoint and its nearest bend. Strongly connected graphs skip DAG backbone priorities because they have no intrinsic forward path. Flow and State share terminal-corridor separation and stable route locking, and opt into readable routing: overlapping opposite endpoints share an axis when possible. Compact self-loops use two distinct node endpoints; multiple loops rotate across node sides so their routes and labels remain distinct. Route repair compares strict and relaxed orthogonal candidates by short legs, bends, length, area, then stable order instead of accepting the first feasible detour. Rounded glyphs therefore express real detours rather than search artifacts. Flow and State also opt into Brandes–Köpf balanced node placement; Class and ER retain ELK's automatic placement.

Flow presents every node as the same rounded card. Mermaid shape semantics are retained by a first-line marker inside that card; multiline continuation text aligns after the marker. node.border owns every structural node border, and flow.node.marker owns the Flow shape signal. Every structural edge consumes its source node's node.border, so line and arrow cannot diverge from that border. Legacy flow.node.border, edge.line, and edge.arrow inputs are ordered compatibility fallbacks, not output roles. Edge labels remain independent. Topology does not assign colors. XY series retain independent series.1–series.5 roles.

CartesianChartSpec is the renderer-facing chart contract. Linear axes retain numeric coordinates; band axes retain ordered categories. D3 owns domain, ticks, and scale projection; Unicode rendering owns integer-cell quantization and mark glyphs. Vega-Lite unit specs and flat layers adapt inline data.values into that contract. Unsupported URL data, transforms, facets, repeats, and concatenation preserve the fenced source with a diagnostic.

The shared layered renderer owns layout invocation, validation, group-edge-node composition order, route labels, cropping, and serialization. Diagram adapters may contribute node and endpoint painters but do not repeat those steps. Flow, State, Class, and ER use this contract. Class enables distributed ports and keeps UML compartments, namespaces, cardinalities, and relationship markers in its presentation sidecar. ER opts into one fixed-order ELK port per relationship endpoint, expands an entity only when its border lacks port capacity, and reserves the complete direction-aware crow's-foot marker corridor. ER labels are placed against the projected route, and self-relationships use the compact grid route. Its semantic relationships remain undirected while an optional Mermaid direction controls layout orientation; declaration order supplies stable orientation when no direction is declared. State preserves parser-level diagram identity, uses depth-first cycle breaking from its ranked pseudostates, and projects ELK attachment positions onto adaptive node ports: one attachment stays centered while a shared side remains distributed. Labels may be placed left or above the projected route; the final grid is translated back to a nonnegative origin. Feedback cycles therefore stay readable without inflating layer spacing. Initial and final pseudostates use the independent state.start and state.end semantic roles; their adjacent edges retain node.border. Sequence keeps its participant-column coordinate model and consumes the same scene-layer contract for lifelines, fragment borders, nodes, labels, and markers.

For a feasible layout, priorities are ordered rather than mixed into unstable weights: direction, crossings, bends, Manhattan edge length, area, then stable source order. Diagram-specific placement exceptions do not belong in the shared layout engine; add an adapter or use the correct coordinate model.

Flow, State, Class, and ER rendering is asynchronous because browser layout runs in a worker. Worker-less runtimes use the same ELK adapter inline. A layout or projection failure returns the existing Mermaid diagnostic fallback; the old placement algorithm is not a fallback path.

On this page