Skip to content

Commit 0fce2ad

Browse files
committed
fix: zoom-to-fit after sugiyama layout
After running the layout algorithm, automatically adjust zoom and pan so the entire graph fits in the viewport. Without this, large layouts would position nodes off-screen (the 2500-node stress test produces a ~17,760px wide graph at zoom=1). Applied to both the sugiyama and sugiyama-stress-test examples.
1 parent 1eacff1 commit 0fce2ad

4 files changed

Lines changed: 52 additions & 1 deletion

File tree

examples/sugiyama-stress-test/src/main.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,30 @@ fn main() {
103103
}
104104
}
105105

106+
// Zoom to fit the layout
106107
if let Some(w) = w.upgrade() {
108+
let (mut min_x, mut min_y) = (f32::MAX, f32::MAX);
109+
let (mut max_x, mut max_y) = (f32::MIN, f32::MIN);
110+
for i in 0..nodes.row_count() {
111+
if let Some(n) = nodes.row_data(i) {
112+
min_x = min_x.min(n.x);
113+
min_y = min_y.min(n.y);
114+
max_x = max_x.max(n.x + 120.0);
115+
max_y = max_y.max(n.y + 60.0);
116+
}
117+
}
118+
if min_x < max_x {
119+
let margin = 40.0;
120+
let graph_w = (max_x - min_x) + margin * 2.0;
121+
let graph_h = (max_y - min_y) + margin * 2.0;
122+
let viewport_w = w.get_width_();
123+
let viewport_h = w.get_height_() - 40.0;
124+
let zoom = (viewport_w / graph_w).min(viewport_h / graph_h).clamp(0.1, 3.0);
125+
w.set_zoom(zoom);
126+
w.set_pan_x(-(min_x - margin) * zoom);
127+
w.set_pan_y(-(min_y - margin) * zoom);
128+
}
129+
107130
let geom_ver = w.global::<GeometryVersion>();
108131
geom_ver.set_version(geom_ver.get_version() + 1);
109132
}

examples/sugiyama-stress-test/ui/sugiyama-stress-test.slint

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ export component MainWindow inherits Window {
6767
in property <[NodeData]> nodes;
6868
in property <[LinkData]> links <=> editor.links;
6969
in-out property <string> grid_commands <=> editor.grid-commands;
70+
in-out property <float> zoom <=> editor.zoom;
71+
in-out property <length> pan-x <=> editor.pan-x;
72+
in-out property <length> pan-y <=> editor.pan-y;
7073

7174
out property <float> width_: self.width / 1px;
7275
out property <float> height_: self.height / 1px;

examples/sugiyama/src/main.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,30 @@ fn main() {
104104
}
105105
}
106106

107-
// Increment version to trigger link recalculation
107+
// Zoom to fit the layout
108108
if let Some(w) = w.upgrade() {
109+
let (mut min_x, mut min_y) = (f32::MAX, f32::MAX);
110+
let (mut max_x, mut max_y) = (f32::MIN, f32::MIN);
111+
for i in 0..nodes.row_count() {
112+
if let Some(n) = nodes.row_data(i) {
113+
min_x = min_x.min(n.x);
114+
min_y = min_y.min(n.y);
115+
max_x = max_x.max(n.x + 120.0);
116+
max_y = max_y.max(n.y + 60.0);
117+
}
118+
}
119+
if min_x < max_x {
120+
let margin = 40.0;
121+
let graph_w = (max_x - min_x) + margin * 2.0;
122+
let graph_h = (max_y - min_y) + margin * 2.0;
123+
let viewport_w = w.get_width_();
124+
let viewport_h = w.get_height_() - 40.0; // button bar
125+
let zoom = (viewport_w / graph_w).min(viewport_h / graph_h).clamp(0.1, 3.0);
126+
w.set_zoom(zoom);
127+
w.set_pan_x(-(min_x - margin) * zoom);
128+
w.set_pan_y(-(min_y - margin) * zoom);
129+
}
130+
109131
let geom_ver = w.global::<GeometryVersion>();
110132
geom_ver.set_version(geom_ver.get_version() + 1);
111133
}

examples/sugiyama/ui/sugiyama.slint

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ export component MainWindow inherits Window {
6969
in property <[NodeData]> nodes;
7070
in property <[LinkData]> links <=> editor.links;
7171
in-out property <string> grid_commands <=> editor.grid-commands;
72+
in-out property <float> zoom <=> editor.zoom;
73+
in-out property <length> pan-x <=> editor.pan-x;
74+
in-out property <length> pan-y <=> editor.pan-y;
7275

7376
out property <float> width_: self.width / 1px;
7477
out property <float> height_: self.height / 1px;

0 commit comments

Comments
 (0)