ui-force_directed¶
Purpose¶
Force-graph layout component for visualizing state machines, agent diagrams, hierarchies, and entity-relationship networks. Binds to a single row containing a graph object (nodes, links); node and edge actions route through the canonical action enum (save_data_item, delete_data_item, close, custom:<name>).
When to use / when NOT¶
Use: network diagrams, state graphs, entity relationships, hierarchies.
NOT: per-entity graphs in modals. Binds by collection, reads rows[0] only; no inline $: resolution. Write each entity's graph to a dedicated collection, then bind the modal's force_directed filtered to that entity.
YAML shape¶
component: force_directed
data:
collection: ring_graph
state: ready
latest: true
filter: "$: nodes[type='claimant']"
config:
show_arrows: false
node_types:
claimant: { shape: circle, radius: 18, fill: "#ef4444", icon: user }
vendor: { shape: rounded_rect, auto_width: true, fill: "#f59e0b", icon: wrench }
on_node_click:
open: "$: node.type = 'claimant' ? 'claimant_modal' : 'vendor_modal'"
empty_message: "No data available"
charge_strength: -2000
Data & events¶
Graph structure (from row's data): {nodes: [{id, type, label?, data: {fill?}}], links: [{source, target, label?}]} (edges alias OK).
Per node: id (required), type (selects node_types), label (display; falls back to data.name/id), optional data.fill (hex override). Per link: source/target node ids, optional label.
Click handlers activate modals by string id only; modal descendants read node.<field>.
Config keys¶
Node rendering: node_types (map type → shape/radius/fill/stroke/icon/label_position/auto_width); shapes: circle, rounded_rect, rect, none. on_node_click: {open: string_modal_id}. Fills are raw hex (factory-owned category palette).
Physics: charge_strength (default -2000), charge_exponent (default 1.5), charge_max_distance (default Infinity; repulsion-only cutoff).
Edge geometry: arrow_offset_start (default 0; source inset), arrow_offset_end (default 0; target inset). passthrough: true ignores insets.
Other: empty_message, show_arrows.
Gotchas¶
- Insets & passthrough:
passthrough: trueon a node type ignores insets (connects at centre, no arrowhead). Insets are px, applied on top of node radius. - Charge falloff:
charge_max_distanceaffects only repulsion, not link/center/alignment forces. - Fills: raw hex, factory-owned category palette (not theme tokens). Component chrome (grid, selection ring) uses theme.
- Modal ids:
open:must be string id only; inline object form rejected.