Skip to content

Commit a8f2c97

Browse files
committed
Minimap: fit viewport indicator within minimap bounds
The viewport indicator could extend past the minimap borders when the visible viewport was larger than the graph (zoomed out or small graph with a large editor window): scale was computed from graph bounds only, so a viewport of, say, 1200x800 world units rendering into a 180x135 minimap with scale=0.24 produced a 286x190 indicator rectangle — larger than the minimap itself. Scale now uses the union of graph bounds and the visible viewport as the content extent. When the viewport is inside the graph (zoomed in), the behavior is unchanged: content = graph, minimap shows the whole graph, indicator sits inside. When the viewport extends past the graph (zoomed out), the minimap "zooms out" to show both — the indicator always fits inside, and graph content appears smaller within it. Node rendering (both SVG path and fallback rectangles) and the click- to-navigate inverse transform also use the unified content origin so everything stays consistent.
1 parent 48520f1 commit a8f2c97

1 file changed

Lines changed: 27 additions & 17 deletions

File tree

node-editor-building-blocks.slint

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -349,23 +349,33 @@ export component Minimap inherits Rectangle {
349349
property <length> drag-threshold: 3px;
350350

351351
// === Coordinate Transformation ===
352-
property <length> graph-width: max(root.graph-max-x - root.graph-min-x, 1px);
353-
property <length> graph-height: max(root.graph-max-y - root.graph-min-y, 1px);
354-
property <length> available-width: root.minimap-width - 2 * root.minimap-padding;
355-
property <length> available-height: root.minimap-height - 2 * root.minimap-padding;
356-
property <float> scale: min(
357-
root.available-width / root.graph-width,
358-
root.available-height / root.graph-height);
359-
360-
// === Viewport in Graph Coordinates ===
352+
// Visible region in graph/world coordinates.
353+
// Derived from screen = pan + world * zoom, inverted at screen origin (0,0).
361354
property <length> visible-min-x: -root.viewport-x / root.viewport-zoom;
362355
property <length> visible-min-y: -root.viewport-y / root.viewport-zoom;
363356
property <length> visible-max-x: root.visible-min-x + (root.viewport-width / root.viewport-zoom);
364357
property <length> visible-max-y: root.visible-min-y + (root.viewport-height / root.viewport-zoom);
365358

359+
// Minimap content = union(graph bounds, visible viewport). Using the union
360+
// guarantees the viewport indicator always fits inside the minimap: when
361+
// the viewport is zoomed out past the graph, the minimap "zooms out" so
362+
// both the graph and the viewport are visible.
363+
property <length> content-min-x: min(root.graph-min-x, root.visible-min-x);
364+
property <length> content-min-y: min(root.graph-min-y, root.visible-min-y);
365+
property <length> content-max-x: max(root.graph-max-x, root.visible-max-x);
366+
property <length> content-max-y: max(root.graph-max-y, root.visible-max-y);
367+
property <length> content-width: max(root.content-max-x - root.content-min-x, 1px);
368+
property <length> content-height: max(root.content-max-y - root.content-min-y, 1px);
369+
370+
property <length> available-width: root.minimap-width - 2 * root.minimap-padding;
371+
property <length> available-height: root.minimap-height - 2 * root.minimap-padding;
372+
property <float> scale: min(
373+
root.available-width / root.content-width,
374+
root.available-height / root.content-height);
375+
366376
// === Viewport Indicator in Minimap Coordinates ===
367-
property <length> viewport-indicator-x: root.minimap-padding + (root.visible-min-x - root.graph-min-x) * root.scale;
368-
property <length> viewport-indicator-y: root.minimap-padding + (root.visible-min-y - root.graph-min-y) * root.scale;
377+
property <length> viewport-indicator-x: root.minimap-padding + (root.visible-min-x - root.content-min-x) * root.scale;
378+
property <length> viewport-indicator-y: root.minimap-padding + (root.visible-min-y - root.content-min-y) * root.scale;
369379
property <length> viewport-indicator-width: (root.visible-max-x - root.visible-min-x) * root.scale;
370380
property <length> viewport-indicator-height: (root.visible-max-y - root.visible-min-y) * root.scale;
371381

@@ -381,8 +391,8 @@ export component Minimap inherits Rectangle {
381391
property <string> computed-path: root.compute-nodes-path(
382392
root.path-version,
383393
root.scale,
384-
root.minimap-padding / 1px - (root.graph-min-x / 1px) * root.scale,
385-
root.minimap-padding / 1px - (root.graph-min-y / 1px) * root.scale);
394+
root.minimap-padding / 1px - (root.content-min-x / 1px) * root.scale,
395+
root.minimap-padding / 1px - (root.content-min-y / 1px) * root.scale);
386396

387397
// Use computed path, or nodes-path if provided externally
388398
property <string> effective-path: root.nodes-path != "" ? root.nodes-path : root.computed-path;
@@ -400,8 +410,8 @@ export component Minimap inherits Rectangle {
400410
// Fallback: individual rectangles (used when no path callback is set)
401411
if root.effective-path == "": Rectangle {
402412
for node in root.nodes: Rectangle {
403-
x: root.minimap-padding + (node.x - root.graph-min-x) * root.scale;
404-
y: root.minimap-padding + (node.y - root.graph-min-y) * root.scale;
413+
x: root.minimap-padding + (node.x - root.content-min-x) * root.scale;
414+
y: root.minimap-padding + (node.y - root.content-min-y) * root.scale;
405415
width: node.width * root.scale;
406416
height: node.height * root.scale;
407417
background: node.color.alpha > 0 ? node.color : root.minimap-node-color;
@@ -436,8 +446,8 @@ export component Minimap inherits Rectangle {
436446
if !root.internal-is-panning {
437447
// Treat as click: center viewport
438448
root.navigate-to(
439-
root.graph-min-x + ((self.mouse-x - root.minimap-padding) / root.scale),
440-
root.graph-min-y + ((self.mouse-y - root.minimap-padding) / root.scale));
449+
root.content-min-x + ((self.mouse-x - root.minimap-padding) / root.scale),
450+
root.content-min-y + ((self.mouse-y - root.minimap-padding) / root.scale));
441451
}
442452
root.internal-is-panning = false;
443453
}

0 commit comments

Comments
 (0)