LiveFlow.Layout (LiveFlow v0.3.2)

Copy Markdown View Source

Layout helpers.

Layouts work on top-level nodes by default (child nodes keep their position relative to their parent). Pass nodes: ids to restrict them.

Summary

Functions

Applies a %{id => %{x, y}} map (or list of {id, position}) to the flow.

Force-directed layout (Fruchterman-Reingold), similar to d3-force.

Prepares serializable layout data from the current flow state.

Prepares serializable layout data for the client-side tree layout algorithm.

Moves overlapping nodes apart (siblings only: child nodes are compared with the other children of the same parent).

Layered layout for trees and DAGs (similar to dagre / d3-hierarchy).

Functions

apply_positions(flow, positions)

@spec apply_positions(LiveFlow.State.t(), map() | list()) :: LiveFlow.State.t()

Applies a %{id => %{x, y}} map (or list of {id, position}) to the flow.

force(flow, opts \\ [])

@spec force(
  LiveFlow.State.t(),
  keyword()
) :: %{required(String.t()) => %{x: float(), y: float()}}

Force-directed layout (Fruchterman-Reingold), similar to d3-force.

Starts from the current positions and is deterministic.

Options

  • :iterations - Simulation steps (default: 300)
  • :distance - Ideal edge length (default: 200)
  • :fixed - Node IDs that keep their position (default: [])
  • :nodes - Only lay out these node IDs (default: top-level nodes)

prepare_layout_data(flow, opts \\ %{})

@spec prepare_layout_data(LiveFlow.State.t(), map()) :: map()

Prepares serializable layout data from the current flow state.

Returns a map with nodes (list of id/width/height maps) and edges (list of id/source/target maps) suitable for sending to the client-side ELK layout engine via push_event. The app must register ELK first (mix live_flow.gen.elk).

Options (string keys, e.g. straight from event params)

  • "direction" - "DOWN", "RIGHT", "UP" or "LEFT" (default: "DOWN")
  • "options" - Extra ELK layout options, e.g. %{"elk.algorithm" => "mrtree"}
  • "flow_id" - Only the flow with this DOM id runs the layout

Examples

push_event(socket, "lf:layout_data", Layout.prepare_layout_data(flow, %{"direction" => "RIGHT"}))

prepare_tree_layout_data(flow, opts \\ %{})

@spec prepare_tree_layout_data(LiveFlow.State.t(), map()) :: map()

Prepares serializable layout data for the client-side tree layout algorithm.

Similar to prepare_layout_data/2 but outputs options compatible with the pure JS tree layout engine (direction: TB/LR, nodeSpacing, levelSpacing). Push it as lf:tree_layout_data; no ELK needed.

Options (string keys)

  • "direction" - "TB" or "LR" (default: "TB")
  • "flow_id" - Only the flow with this DOM id runs the layout

resolve_collisions(flow, opts \\ [])

@spec resolve_collisions(
  LiveFlow.State.t(),
  keyword()
) :: %{required(String.t()) => %{x: float(), y: float()}}

Moves overlapping nodes apart (siblings only: child nodes are compared with the other children of the same parent).

Returns the new positions of the nodes that moved.

Options

  • :margin - Minimum gap between nodes (default: 10)
  • :max_iterations - (default: 50)
  • :fixed - Node IDs that never move, e.g. the node just dropped (default: [])

tree(flow, opts \\ [])

@spec tree(
  LiveFlow.State.t(),
  keyword()
) :: %{required(String.t()) => %{x: float(), y: float()}}

Layered layout for trees and DAGs (similar to dagre / d3-hierarchy).

Nodes are ranked by their longest path from a root, ordered inside each rank to reduce crossings, and placed close to the center of their parents.

Options

  • :direction - :tb (top to bottom) or :lr (left to right) (default: :tb)
  • :node_spacing - Space between nodes of the same rank (default: 40)
  • :rank_spacing - Space between ranks (default: 80)
  • :nodes - Only lay out these node IDs (default: top-level nodes)
  • :origin - {x, y} of the top-left corner (default: {0, 0})