Graph editing is more than creating a connector.
Users need to select connectors, inspect them, remove them, reroute them, label them, click them reliably, and edit bends. LivePanels renders connector items in the world SVG item projection and exposes command helpers for the surrounding application controls.
Connector Selection
The built-in connector path and hit path include ordinary item selection attrs. Clicking a rendered connector selects the connector item through the canvas selection command protocol.
External controls that target one connector item can use the ordinary selection helpers:
<button {select_item_attrs(connector)}>Select</button>
<button {include_item_attrs(connector)}>Add to selection</button>
<button {toggle_item_selection_attrs(connector)}>Toggle</button>Graph-scoped controls can still use graph selection helpers:
<button {graph_select_connector_attrs(connector)}>Select</button>
<button {graph_include_connector_attrs(connector)}>Add to selection</button>
<button {graph_toggle_connector_selection_attrs(connector)}>Toggle</button>Select every visible graph item and connector:
<button {graph_select_all_attrs()}>Select graph</button>Server equivalent:
socket = LivePanels.Graph.select_all!(socket)Graph selection shares the same actor-scoped selection model as item selection.
Style Selection State
Rendered connector groups expose:
data-livepanels-selected="true"when the connector item is selected;data-livepanels-connector-selection="selected"when the connector itself is selected;data-livepanels-connector-selection="related"when a selected graph item is one of the connector endpoints;data-livepanels-connector-selection="unrelated"when another graph item is selected.
Style those attrs in application CSS:
.graph-canvas
[data-livepanels-connector-selection="related"]
.livepanels-connector-path {
stroke-width: 4px;
}
.graph-canvas
[data-livepanels-connector-selection="unrelated"]
.livepanels-connector-path {
opacity: 0.28;
}Hit Targets
The renderer emits an invisible hit path after the visible path:
<path
class="livepanels-connector-hit-path"
data-livepanels-connector-hit-target="true"
>Style it only when you need to inspect or debug hit geometry. The runtime keeps the hit path in the connector item stream so replacement and shared updates do not require host code.
Labels
If labels are connector presentation, put them on the connector:
connector =
LivePanels.Item.Connector.connection(
from: LivePanels.Item.Connector.endpoint("extract", "out"),
to: LivePanels.Item.Connector.endpoint("load", "in"),
label: "rows",
role: :data
)Update labels through the graph command path:
socket =
LivePanels.Graph.edit!(socket, connector_id,
label: "customer_id",
role: :foreign_key
)If labels come from product data, resolve them before creating or updating the connector and store the value in connector presentation.
Routes
Supported connector routes:
:bezier;:orthogonal;:straight.
Store route presentation on the connector:
socket =
LivePanels.Graph.edit!(socket, connector_id,
route: :orthogonal,
direction: :horizontal
)LivePanels.Graph.connect!/2 accepts route options for new connectors:
socket =
LivePanels.Graph.connect!(socket,
from: {"extract", "out"},
to: {"load", "in"},
route: :orthogonal,
direction: :horizontal
)DOM connection controls can pass route fields through complete_connector_attrs/3:
<button
{complete_connector_attrs(context.item, port,
"phx-value-route": "orthogonal",
"phx-value-direction": "horizontal"
)}
>
{port.label}
</button>Route choice should live on the connector item when it should persist, stream, or be shared with other participants.
Connector Bends
Connectors can carry bend presentation:
connector =
LivePanels.Item.Connector.connection(
from: LivePanels.Item.Connector.endpoint("source", "out"),
to: LivePanels.Item.Connector.endpoint("target", "in"),
bends: [%{x: 120, y: 80}]
)When a connector item is selected, the renderer emits bend handles for its bend
points. Browser bend updates use the graph update_connector_bends command and
stream back through the connector item.
Connector Inspectors
A connector inspector reads selected item ids and looks up connector items:
selection = LivePanels.Canvas.Read.selection(socket)
selected_item_ids = LivePanels.Canvas.Selection.selected_item_ids(selection)
state = LivePanels.Canvas.Read.state(socket)
selected_connectors =
Enum.filter(LivePanels.Graph.connectors(state), fn connector ->
MapSet.member?(selected_item_ids, connector.id)
end)Use the inspector for product fields. Use graph commands for runtime changes.
Removing Selected Graph Elements
The ordinary remove-selected command can remove selected items and connectors:
<button {remove_selected_attrs()}>Remove</button>Or remove one connector:
<button {disconnect_attrs(connector)}>Remove connector</button>When an item is removed, graph pruning removes or rejects connectors that can no longer resolve.