1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
//! # egui_xyflow
//!
//! An interactive node-graph editor widget for
//! [egui](https://github.com/emilk/egui), inspired by
//! [xyflow](https://xyflow.com/) (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
//!
//! ```rust,no_run
//! 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:
//!
//! ```text
//! FlowState → FlowCanvas::show() → FlowEvents → apply changes → FlowState
//! ```
//!
//! 1. [`FlowState`] owns the graph: nodes, edges, viewport, config,
//! selection state.
//! 2. [`FlowCanvas`] renders the graph and processes input, returning
//! [`FlowEvents`] that describe what happened this frame (clicks,
//! drags, connections, selection changes, deletions, etc.).
//! 3. Most mutations are represented as [`NodeChange`] / [`EdgeChange`]
//! enum variants and applied atomically via
//! [`FlowState::apply_node_changes`] and
//! [`FlowState::apply_edge_changes`].
//!
//! ### Generic parameters
//!
//! The library is parameterised over two user-owned types:
//!
//! - `ND` — custom data attached to each [`Node`].
//! - `ED` — custom data attached to each [`Edge`].
//!
//! 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>`](render::node_renderer::NodeWidget) — implement
//! `size()` and `show()` for custom node rendering. Built-ins:
//! [`DefaultNodeWidget`] (for `Node<String>`) and [`UnitNodeWidget`]
//! (for `Node<()>`).
//! - [`EdgeWidget<ED>`](render::canvas::EdgeWidget) — implement to render
//! custom edge paths instead of the built-in [`EdgeType`] algorithms.
//! - [`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:
//!
//! ```rust,no_run
//! # use egui_xyflow::prelude::*;
//! use egui_xyflow::physics::*;
//!
//! # let mut state: FlowState<(), ()> = FlowState::new(FlowConfig::default());
//! 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)* — derive `Serialize` / `Deserialize` on
//! [`FlowState`], [`Node`], [`Edge`], and most config/viewport types.
//! Disable for no-std-adjacent builds or to drop the `serde`
//! dependency.
//!
//! ## Examples
//!
//! The repository ships with 17 runnable examples:
//!
//! ```text
//! 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 harness
//! ```
//!
//! See [the repo](https://github.com/avinkrisv/egui_xyflow) for the
//! complete list.
//!
//! ## Compatibility
//!
//! Built against `egui` 0.31. MSRV: 1.85 (edition 2024).
// ── Module tree ───────────────────────────────────────────────────────────────
// ── Top-level re-exports (most commonly used items) ──────────────────────────
// Configuration
pub use ;
// Core types
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
// State
pub use FlowState;
// Events
pub use FlowEvents;
// Render / widget
pub use ;
pub use MinimapInfo;
pub use ;
// Animation
pub use easing;
pub use ViewportAnimation;
// State helpers
pub use node_lookup;
// Graph utilities
pub use ;
pub use ;
// Edge path math
pub use ;
pub use ;
pub use ;
pub use get_straight_path;
// Interaction
pub use ResizeHandleKind;
// Physics is a distinct optional subsystem — callers opt in explicitly via
// `egui_xyflow::physics::*` rather than polluting the crate root / prelude.
// ── Prelude ───────────────────────────────────────────────────────────────────
/// Convenience glob import that brings the most commonly needed items into scope.
///
/// ```rust,no_run
/// use egui_xyflow::prelude::*;
/// ```