Expand description
§egui_xyflow
An interactive node-graph editor widget for egui, inspired by xyflow (React Flow / Svelte Flow). Supports drag-and-drop nodes, handle-to-handle edge connections, pan/zoom, multi-select, resize, minimap, edge labels, and an optional force-directed layout subsystem.
§Quick start
use eframe::egui;
use egui_xyflow::prelude::*;
struct MyApp {
state: FlowState<String, ()>,
}
impl MyApp {
fn new() -> Self {
let mut state = FlowState::new(FlowConfig::default());
state.add_node(
Node::builder("1")
.position(egui::pos2(100.0, 100.0))
.data("Input".to_string())
.handle(NodeHandle::source(Position::Right))
.build(),
);
state.add_node(
Node::builder("2")
.position(egui::pos2(400.0, 100.0))
.data("Output".to_string())
.handle(NodeHandle::target(Position::Left))
.build(),
);
state.add_edge(Edge::builder("e1-2", "1", "2").label("flow"));
Self { state }
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
let events =
FlowCanvas::new(&mut self.state, &DefaultNodeWidget).show(ui);
for conn in &events.connections_made {
println!("new edge: {} -> {}", conn.source, conn.target);
}
});
}
}§Architecture
Every frame follows the same cycle:
FlowState → FlowCanvas::show() → FlowEvents → apply changes → FlowStateFlowStateowns the graph: nodes, edges, viewport, config, selection state.FlowCanvasrenders the graph and processes input, returningFlowEventsthat describe what happened this frame (clicks, drags, connections, selection changes, deletions, etc.).- Most mutations are represented as
NodeChange/EdgeChangeenum variants and applied atomically viaFlowState::apply_node_changesandFlowState::apply_edge_changes.
§Generic parameters
The library is parameterised over two user-owned types:
Use () when you don’t need custom data, or String for simple
labels, or a struct of your own.
§Coordinate spaces
Two coordinate systems convert via flow_to_screen and
screen_to_flow using a Transform:
- Flow space — graph coordinates you set on nodes. Unbounded.
- Screen space — pixel coordinates inside the canvas rect.
§Render order
Bottom-to-top: background → edges (with optional viewport culling) → connection drag line → nodes (z-ordered) → handles → resize handles → selection rectangle → minimap.
§Customisation points
NodeWidget<D>— implementsize()andshow()for custom node rendering. Built-ins:DefaultNodeWidget(forNode<String>) andUnitNodeWidget(forNode<()>).EdgeWidget<ED>— implement to render custom edge paths instead of the built-inEdgeTypealgorithms.ConnectionValidator— reject prospective connections (e.g. no self-loops, typed handles).FlowConfig— 60+ knobs for pan/zoom, selection, colour, edge defaults, handle appearance, grid snapping, animation, viewport culling, edge labels, etc.
§Physics (force-directed layout)
The physics module provides a D3-compatible force simulation
usable alongside (or instead of) hand-placed node positions:
use egui_xyflow::physics::*;
let mut sim = ForceSimulation::from_state(&state)
.add_force("charge", ManyBodyForce::new().strength(-30.0))
.add_force("links", LinkForce::from_state(&state).distance(30.0))
.add_force("position", PositionForce::new().strength(0.1))
.add_force("center", CenterForce::new());
// Each frame — `false` means the state was mutated, rebuild the sim.
if !sim.step(&mut state) {
sim = ForceSimulation::from_state(&state);
}The charge force uses a Barnes–Hut quadtree (θ = 0.9 by default), so
it scales roughly O(n log n) with node count. physics is not
re-exported from the prelude — import it explicitly.
§Feature flags
serde(default) — deriveSerialize/DeserializeonFlowState,Node,Edge, and most config/viewport types. Disable for no-std-adjacent builds or to drop theserdedependency.
§Examples
The repository ships with 17 runnable examples:
cargo run --example basic_flow # getting started
cargo run --example edge_labels # labels + viewport culling
cargo run --example data_pipeline # pipeline with validation
cargo run --example disjoint_force_graph # physics: citation network
cargo run --release --example physics_bench # physics timing harnessSee the repo for the complete list.
§Compatibility
Built against egui 0.31. MSRV: 1.85 (edition 2024).
Re-exports§
pub use config::BackgroundVariant;pub use config::FlowConfig;pub use config::ZIndexMode;pub use types::changes::EdgeChange;pub use types::changes::NodeChange;pub use types::connection::Connection;pub use types::connection::ConnectionMode;pub use types::connection::ConnectionState;pub use types::connection::EdgeInfo;pub use types::edge::AnchorEndpoint;pub use types::edge::Edge;pub use types::edge::EdgeAnchor;pub use types::edge::EdgeGlow;pub use types::edge::EdgeId;pub use types::edge::EdgeMarker;pub use types::edge::EdgePathResult;pub use types::edge::EdgePosition;pub use types::edge::EdgeStyle;pub use types::edge::EdgeType;pub use types::edge::MarkerType;pub use types::handle::Handle;pub use types::handle::HandleType;pub use types::handle::NodeHandle;pub use types::node::InternalNode;pub use types::node::Node;pub use types::node::NodeBuilder;pub use types::node::NodeExtent;pub use types::node::NodeHandleBounds;pub use types::node::NodeId;pub use types::node::NodeInternals;pub use types::position::CoordinateExtent;pub use types::position::Dimensions;pub use types::position::NodeOrigin;pub use types::position::Position;pub use types::position::SnapGrid;pub use types::position::Transform;pub use types::viewport::PanOnScrollMode;pub use types::viewport::SelectionMode;pub use types::viewport::Viewport;pub use state::flow_state::FlowState;pub use events::FlowEvents;pub use render::canvas::AllowAllConnections;pub use render::canvas::ConnectionValidator;pub use render::canvas::EdgeWidget;pub use render::canvas::FlowCanvas;pub use render::minimap::MinimapInfo;pub use render::node_renderer::DefaultNodeWidget;pub use render::node_renderer::NodeWidget;pub use render::node_renderer::UnitNodeWidget;pub use animation::easing;pub use animation::viewport_animation::ViewportAnimation;pub use state::node_lookup;pub use graph::node_position::flow_to_screen;pub use graph::node_position::screen_to_flow;pub use graph::node_position::snap_position;pub use graph::utils::get_connected_edges;pub use graph::utils::get_incomers;pub use graph::utils::get_nodes_bounds;pub use graph::utils::get_outgoers;pub use graph::utils::get_viewport_for_bounds;pub use edges::bezier::get_bezier_path;pub use edges::bezier::sample_bezier;pub use edges::positions::get_edge_position;pub use edges::positions::project_to_border;pub use edges::smooth_step::get_smooth_step_path;pub use edges::smooth_step::get_step_path;pub use edges::straight::get_straight_path;pub use interaction::resize::ResizeHandleKind;
Modules§
- animation
- Viewport animation with configurable easing functions.
- config
- Global configuration for the flow canvas.
- edges
- Edge path algorithms: Bezier, SmoothStep, Step, and Straight.
- events
- Per-frame event reporting for
FlowCanvas. - graph
- Graph utilities: coordinate transforms, bounds calculation, and neighbor queries.
- interaction
- Input handling: node dragging, pan/zoom, connection dragging, resize, and box selection.
- physics
- Force-directed physics simulation.
- prelude
- Convenience glob import that brings the most commonly needed items into scope.
- render
- Rendering subsystem: canvas orchestration, node/edge/handle/background renderers.
- state
- Graph state management:
flow_state::FlowState, change application, and node lookup helpers. - types
- Core data types for the flow graph.