Feature/minimap#276
Conversation
• A "minimap" toggle button (top-left, always visible over the plan canvas, very small) • A minimap panel (300×300 default, with close button "✕", header bar, and a Canvas for rendering) PlanViewerControl.axaml.cs — Added: 1. State fields: Static _minimapWidth/_minimapHeight (preserved in memory across plans, not on disk), drag/resize state, node mapping for minimap interaction 2. Toggle/Open/Close: MinimapToggle_Click(object?, RoutedEventArgs), OpenMinimapPanel(), CloseMinimapPanel() 3. Rendering (RenderMinimap()): • Branch areas: Each child subtree of the root gets a transparent colored rectangle (8 distinct colors cycling) behind its nodes • Edges: Scaled-down elbow connectors • Nodes: Small colored rectangles (red tint for expensive nodes) • Viewport box: Semi-transparent blue rectangle showing the visible portion of the plan 4. Interaction: • Click & drag on minimap to pan the plan viewer • Single click on a node centers the plan viewer on that node • Double click on a node zooms to ~1/3 viewport size and selects the node • Resize grip (bottom-right corner) allows resizing between 200×200 and 500×500 5. Live updates: Viewport box updates on scroll, zoom, pan, and mouse wheel zoom. Minimap re-renders on statement change. 6. Per-plan: Each PlanViewerControl instance has its own minimap state, so multiple open plans each have their own minimap.
2. Resize grip: Moved from the canvas (where it got destroyed on every re-render) to a permanent AXAML element — a Border with 3 diagonal lines in the bottom-right corner indicating resizability, wired to the existing resize handlers in the constructor 3. Node borders: Changed from EdgeBrush (dark grey #6B7280) to a new MinimapNodeBorderBrush (#A0A4AB — light grey) 4. Node content: Each minimap node now shows its operator icon (scaled to fit, ~70% of the node size, max 16px) 5. Default size: Changed from 300×300 to 400×400
…1D23, border #3A3D45, 5px thickness, same for header and canvas background 2. Selected node highlighting: When a node is selected in the plan viewer, the corresponding minimap node gets a blue selection border (SelectionBrush, 2px). The highlight persists through minimap re-renders and resets when a different node is selected. 3. Proportional edge thickness: Minimap edges now use the same logarithmic row-count formula as the plan viewer (Math.Log(rows) capped at 2–12), scaled down by the minimap scale factor, with a minimum of 0.5px.
Fixes:
1 _selectedNode cleared Added _selectedNode = null in both Clear() and RenderStatement()
2 Dead field removed Removed _minimapDragStart field and its assignment
3 Handlers wired once Moved MinimapCanvas.PointerPressed/Moved/Released subscriptions to constructor, removed per-render -=/+= cycle
4 Unused constant removed Removed MinimapDefaultSize
5 Guard added RenderMinimap() now returns early with if (!MinimapPanel.IsVisible) return; before doing any work
6 Correct brush restored Deselect now uses _minimapNodeBorderBrushCache (matches creation brush) instead of FindBrushResource("BorderBrush")
7 Branch colors extracted Moved to static readonly Color[] MinimapBranchColors field — no allocation per render
8 Node border brush cached Computed once per render cycle in RenderMinimap() and stored in _minimapNodeBorderBrushCache, reused for all non-expensive nodes
Code Review — Feature/minimapOverviewAdds an interactive minimap overlay to the plan viewer: floating panel toggled from a top-left button, renders a scaled-down view of the plan tree with branch coloring, viewport indicator, click-to-center / double-click-to-zoom, and drag-resize. State is per-instance for selection but The implementation is well-organized into a Issues1. Unrelated change to
|
…pExpensiveNodeBgBrush — no more per-node allocation in the render loop.
|
@erikdarlingdata : I don't have any plans with over 300 nodes on hand. Do you? |
|
Follow-up after the latest commits — most points are addressed:
One small thing on the };
- dialog.ShowDialog(this);
+
+ dialog.ShowDialog(this);
}A stray blank line plus the call indented 12 spaces instead of the original 8. Could you re-revert this hunk so it matches For the >300-node performance question: postponing is fine with me. Worst case the resize-drag re-render gets noticeable on a big plan and we throttle later. Not a blocker. |
|
The latest "align to main" commit (53e0a43) didn't fully revert the ```diff
Could you do a strict revert of those 3 lines to their state on |
Cleanup of cosmetic regression from #276: tabs were left on 3 lines around ShowError that don't match the surrounding 4-space-indented file. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Sorry, the git revert one file was done too late. |
Highlights since v1.8.0: - Minimap for plan navigation (#276) - Colored links by accuracy ratio divergence (#289) - Distinct parallelism subtype icons (#285, #288) - Query Store filter ordering fix (#287) - xunit v2 -> v3 migration (#278) - SqlClient 6 -> 7, ScriptDom 170 -> 180 (#279) - System.CommandLine GA (#280) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
What does this PR do?
Minimap for Plan Viewer
Adds an interactive minimap overlay to the plan viewer, providing a bird's-eye view of the entire execution plan for easier navigation in large plans. Each plan tab maintains its own independent minimap state.
Features
Toggle & Positioning
• Small "minimap" button always visible at the top-left corner of the plan canvas (4px margin)
• Click to open/close; minimap appears directly below the button as a floating overlay (ZIndex 10)
• Close button (✕) in the minimap header bar
• Minimap automatically closes when the plan is cleared
Rendering
• Entire plan tree rendered in miniature: nodes, elbow connector edges, and operator icons
• Nodes show their operator icon scaled to fit (up to 16px, hidden below 6px)
• Expensive nodes highlighted with red-tinted background and OrangeRed border
• Edge thickness is proportional to row counts using the same logarithmic formula as the main plan, scaled down to minimap coordinates
• Branch visualization: each child subtree of the root node gets a transparent colored background area (8 cycling colors) making it easy to distinguish plan branches at a glance
Viewport Indicator
• Semi-transparent accent-colored rectangle shows the currently visible portion of the plan
• Updates in real-time on scroll, pan (mouse drag / middle-click), and zoom (Ctrl+wheel, buttons, fit-to-view)
Navigation Interactions
• Click & drag on empty area: moves the plan viewer viewport to follow the pointer — the main plan scrolls in real-time
• Single click on a node: centers the plan viewer on that node
• Double click on a node: zooms to ~1/3 viewport size, centers on the node, and selects it (shows properties panel)
Selected Node Highlight
• When a node is selected in the main plan viewer (click or via properties), the corresponding minimap node is highlighted with the selection brush (blue, 2px border)
• Highlight persists through minimap re-renders and is correctly cleared on statement switch or plan clear
Resizing
• Diagonal grip lines in the bottom-right corner indicate resizability
• Drag the grip to resize between 200×200 (min) and 500×500 (max)
• Default size: 400×400
• Last used dimensions are preserved in memory (static fields) across plan tabs within the same session, but not persisted to disk
Theming
• All colors derived from theme resources (BackgroundBrush, BorderBrush, ForegroundBrush, AccentBrush, BackgroundLightBrush) — no hardcoded hex values except the decorative branch overlay palette
• Minimap panel border, header, and canvas background all follow the dark theme
• Viewport box fill/border derived from AccentBrush with alpha transparency
• Node border brush derived from ForegroundBrush at 50% opacity, cached per render cycle
Technical Notes
• The minimap wrapper Grid was inserted between the 5-column layout Grid and the PlanScrollViewer, changing the parent traversal path for column definition resolution (Parent instead of Parent)
• Canvas pointer handlers (PointerPressed/Moved/Released) are wired once in the constructor, not per render
• RenderMinimap() guards against deferred execution after panel close
• _selectedNode is properly cleared in both Clear() and RenderStatement() to prevent stale references
• Branch colors extracted to a static readonly Color[] to avoid per-render allocation
• Non-expensive node border brush is computed once per render cycle and cached in _minimapNodeBorderBrushCache
Which component(s) does this affect?
How was this tested?
Describe the testing you've done. Include:
Checklist
dotnet build -c Debug)dotnet test)