Main state container for LiveFlow.
The state holds all nodes, edges, viewport information, and selection state. It provides CRUD operations for nodes and edges, as well as selection management.
Fields
:nodes- Map of node ID toLiveFlow.Nodestructs:edges- Map of edge ID toLiveFlow.Edgestructs:viewport- CurrentLiveFlow.Viewportstate:selected_nodes- Set of selected node IDs:selected_edges- Set of selected edge IDs
Examples
iex> state = LiveFlow.State.new()
iex> node = LiveFlow.Node.new("1", %{x: 0, y: 0}, %{label: "Start"})
iex> state = LiveFlow.State.add_node(state, node)
iex> Map.keys(state.nodes)
["1"]
Summary
Functions
Nodes ready to be drawn: position is replaced by the absolute position,
and nodes inside a hidden parent are hidden too.
Position of a node in flow coordinates. Child nodes store their position relative to their parent; this adds up the positions of all ancestors.
Adds an edge to the state.
Adds multiple edges to the state.
Adds a node to the state.
Adds multiple nodes to the state.
Calculates the bounding box of the nodes in flow coordinates.
Returns the direct children of a node (nodes whose parent_id is id).
Clears all selection (nodes and edges).
Edges connected to any of the given node IDs.
Deletes all selected nodes and edges (skipping those with deletable: false).
Number of ancestors of a node (0 for top-level nodes).
Returns the IDs of all descendants of a node (children, grandchildren, ...).
Deselects a node by ID.
Checks if an edge already exists between two nodes.
Gets all edges connected to a node.
Gets all edges as a list.
Gets an edge by ID.
Gets a node by ID.
Nodes with an edge pointing to id.
Nodes intersecting a node (by ID) or a rect %{x, y, width, height}.
Creates a new empty state.
Rectangle of a node in flow coordinates (absolute position and size).
Unmeasured nodes count as 100 x 40.
Gets all nodes as a list.
Nodes id has an edge to.
Reconnects one end of an edge to another node/handle.
Removes an edge by ID.
Removes multiple edges by ID.
Removes a node by ID, together with its child nodes (sub-flows) and every edge connected to any of them.
Removes multiple nodes by ID.
Selects all nodes and edges.
Selects an edge by ID.
Selects a node by ID.
Selects multiple nodes by ID.
Gets all selected edges.
Gets all selected nodes.
Moves a node into parent_id (or out of any parent with nil), keeping its
absolute position on screen.
Sets the viewport.
Updates an edge by ID with the given attributes.
Updates a node by ID with the given attributes or function.
Updates the viewport with the given values.
Types
@type t() :: %LiveFlow.State{ edges: %{required(String.t()) => LiveFlow.Edge.t()}, nodes: %{required(String.t()) => LiveFlow.Node.t()}, selected_edges: MapSet.t(String.t()), selected_nodes: MapSet.t(String.t()), viewport: LiveFlow.Viewport.t() }
Functions
@spec absolute_nodes(t()) :: %{required(String.t()) => LiveFlow.Node.t()}
Nodes ready to be drawn: position is replaced by the absolute position,
and nodes inside a hidden parent are hidden too.
@spec absolute_position(t(), LiveFlow.Node.t() | String.t()) :: %{x: number(), y: number()} | nil
Position of a node in flow coordinates. Child nodes store their position relative to their parent; this adds up the positions of all ancestors.
@spec add_edge(t(), LiveFlow.Edge.t()) :: t()
Adds an edge to the state.
@spec add_edges(t(), [LiveFlow.Edge.t()]) :: t()
Adds multiple edges to the state.
@spec add_node(t(), LiveFlow.Node.t()) :: t()
Adds a node to the state.
@spec add_nodes(t(), [LiveFlow.Node.t()]) :: t()
Adds multiple nodes to the state.
@spec bounds( t(), keyword() ) :: %{x: number(), y: number(), width: number(), height: number()} | nil
Calculates the bounding box of the nodes in flow coordinates.
Each node contributes its position plus its width/height (measured or explicitly set). Nodes without dimensions count as a point.
Options
:nodes- Only include these node IDs. Unknown IDs are ignored, so they never stretch the bounds to the origin.:include_hidden- Include hidden nodes (default:false)
Returns nil when no node matches.
Examples
iex> state = LiveFlow.State.new(nodes: [
...> LiveFlow.Node.new("a", %{x: 0, y: 0}, %{}, width: 100, height: 50),
...> LiveFlow.Node.new("b", %{x: 200, y: 100}, %{}, width: 50, height: 50)
...> ])
iex> LiveFlow.State.bounds(state)
%{x: 0.0, y: 0.0, width: 250.0, height: 150.0}
iex> LiveFlow.State.bounds(state, nodes: ["b", "missing"])
%{x: 200.0, y: 100.0, width: 50.0, height: 50.0}
@spec children(t(), String.t()) :: [LiveFlow.Node.t()]
Returns the direct children of a node (nodes whose parent_id is id).
Clears all selection (nodes and edges).
@spec connected_edges(t(), [String.t()]) :: [LiveFlow.Edge.t()]
Edges connected to any of the given node IDs.
Deletes all selected nodes and edges (skipping those with deletable: false).
@spec depth(t(), LiveFlow.Node.t()) :: non_neg_integer()
Number of ancestors of a node (0 for top-level nodes).
Returns the IDs of all descendants of a node (children, grandchildren, ...).
Deselects a node by ID.
Checks if an edge already exists between two nodes.
@spec edges_for_node(t(), String.t()) :: [LiveFlow.Edge.t()]
Gets all edges connected to a node.
@spec edges_list(t()) :: [LiveFlow.Edge.t()]
Gets all edges as a list.
@spec get_edge(t(), String.t()) :: LiveFlow.Edge.t() | nil
Gets an edge by ID.
@spec get_node(t(), String.t()) :: LiveFlow.Node.t() | nil
Gets a node by ID.
@spec incomers(t(), String.t()) :: [LiveFlow.Node.t()]
Nodes with an edge pointing to id.
@spec intersecting_nodes(t(), String.t() | map(), keyword()) :: [LiveFlow.Node.t()]
Nodes intersecting a node (by ID) or a rect %{x, y, width, height}.
Options
:partial- Count partial overlaps (default:true). Withfalseonly nodes fully inside the rect are returned.
Creates a new empty state.
Options
:nodes- Initial nodes (list or map):edges- Initial edges (list or map):viewport- Initial viewport
Examples
iex> LiveFlow.State.new()
%LiveFlow.State{nodes: %{}, edges: %{}}
iex> nodes = [LiveFlow.Node.new("1", %{x: 0, y: 0}, %{})]
iex> state = LiveFlow.State.new(nodes: nodes)
iex> Map.keys(state.nodes)
["1"]
@spec node_rect(t(), LiveFlow.Node.t() | String.t()) :: map() | nil
Rectangle of a node in flow coordinates (absolute position and size).
Unmeasured nodes count as 100 x 40.
@spec nodes_list(t()) :: [LiveFlow.Node.t()]
Gets all nodes as a list.
@spec outgoers(t(), String.t()) :: [LiveFlow.Node.t()]
Nodes id has an edge to.
Reconnects one end of an edge to another node/handle.
Accepts the params of the lf:reconnect_edge event pushed when the user
drags an edge endpoint ("edge_id", "end", "node_id", "handle_id").
Options
:replace_id- Give the edge a new ID (default:false):edge_id- ID (or function receiving the updated edge) used when:replace_idistrue. Defaults to a unique"e-<integer>"ID.
Examples
def handle_event("lf:reconnect_edge", params, socket) do
{:noreply, assign(socket, flow: State.reconnect_edge(socket.assigns.flow, params))}
end
Removes an edge by ID.
Removes multiple edges by ID.
Removes a node by ID, together with its child nodes (sub-flows) and every edge connected to any of them.
Removes multiple nodes by ID.
Selects all nodes and edges.
Selects an edge by ID.
Selects a node by ID.
Options
:multi- If true, adds to selection. If false, replaces selection (default:false)
Selects multiple nodes by ID.
@spec selected_edges_list(t()) :: [LiveFlow.Edge.t()]
Gets all selected edges.
@spec selected_nodes_list(t()) :: [LiveFlow.Node.t()]
Gets all selected nodes.
Moves a node into parent_id (or out of any parent with nil), keeping its
absolute position on screen.
@spec set_viewport(t(), LiveFlow.Viewport.t()) :: t()
Sets the viewport.
Updates an edge by ID with the given attributes.
@spec update_node( t(), String.t(), keyword() | (LiveFlow.Node.t() -> LiveFlow.Node.t()) ) :: t()
Updates a node by ID with the given attributes or function.
When passed a keyword list, updates the node with those attributes. When passed a function, applies the function to the node.
Updates the viewport with the given values.