Skip to content

[SPARK-56792][SQL] Support pan and zoom for SQL plan visualization#55769

Closed
yaooqinn wants to merge 2 commits into
apache:masterfrom
yaooqinn:SPARK-56792
Closed

[SPARK-56792][SQL] Support pan and zoom for SQL plan visualization#55769
yaooqinn wants to merge 2 commits into
apache:masterfrom
yaooqinn:SPARK-56792

Conversation

@yaooqinn
Copy link
Copy Markdown
Member

@yaooqinn yaooqinn commented May 8, 2026

What changes were proposed in this pull request?

Add pan and zoom controls to the SQL execution plan visualization rendered
on the SQL tab's execution detail page.

The SVG that hosts the dagre-d3 plan now lives inside a fixed-height
viewport (70vh) and is wrapped in an inner <g class="zoom-layer">.
A d3.zoom() behavior is attached to the SVG and applies its transform
to the zoom-layer; the viewBox keeps performing the natural fit. A small
floating toolbar in the top-right offers - / current % / + buttons,
and + / - / 0 keyboard shortcuts work whenever the cursor is over
the plan area.

Notes:

  • Pan/zoom is suppressed when the user interacts with HTML labels
    (<foreignObject>) so metric tables in detailed mode remain
    selectable.
  • The SVG download is now insulated from the user's current view: the
    cloned SVG resets the zoom-layer transform and uses the viewBox as
    its own width/height so external viewers render at the natural
    plan size, matching the previous download behavior.
  • Detailed-mode rerender reuses the same setup so zoom/pan keeps working
    after toggling "Show metrics in graph nodes".

Why are the changes needed?

Spark plans frequently grow large enough that the previous fit-the-page
SVG becomes hard to read: clusters wrap, scroll bars chase the cursor,
and zooming the browser distorts the surrounding page. Standard
pan/zoom on the plan itself is the conventional way to navigate large
DAGs and is a building block for further plan-viz work under
SPARK-55760.

Does this PR introduce any user-facing change?

Yes. The SQL tab's plan visualization has a fixed-height viewport with
new zoom controls (toolbar + wheel + drag-to-pan + keyboard).

How was this patch tested?

  • build/sbt sql/Test/compile
  • build/sbt sql/scalastyle sql/Test/scalastyle
  • dev/lint-js on the SQL static resources directory

Was this patch authored or co-authored using generative AI tooling?

Generated-by: GitHub Copilot CLI 1.0.44 with Claude Opus 4.7

### What changes were proposed in this pull request?

Add pan and zoom controls to the SQL execution plan visualization rendered
on the SQL tab's execution detail page.

The SVG that hosts the dagre-d3 plan now lives inside a fixed-height
viewport (70vh) and is wrapped in an inner `<g class="zoom-layer">`.
A `d3.zoom()` behavior is attached to the SVG and applies its transform
to the zoom-layer; the viewBox keeps performing the natural fit. A small
floating toolbar in the top-right offers `-` / current % / `+` buttons,
and `+` / `-` / `0` keyboard shortcuts work whenever the cursor is over
the plan area.

Notes:
- Pan/zoom is suppressed when the user interacts with HTML labels
  (`<foreignObject>`) so metric tables in detailed mode remain
  selectable.
- The SVG download is now insulated from the user's current view: the
  cloned SVG resets the zoom-layer transform and uses the viewBox as
  its own `width`/`height` so external viewers render at the natural
  plan size, matching the previous download behavior.
- Detailed-mode rerender reuses the same setup so zoom/pan keeps working
  after toggling "Show metrics in graph nodes".

### Why are the changes needed?

Spark plans frequently grow large enough that the previous fit-the-page
SVG becomes hard to read: clusters wrap, scroll bars chase the cursor,
and zooming the browser distorts the surrounding page. Standard
pan/zoom on the plan itself is the conventional way to navigate large
DAGs and is a building block for further plan-viz work under
SPARK-55760.

### Does this PR introduce _any_ user-facing change?

Yes. The SQL tab's plan visualization has a fixed-height viewport with
new zoom controls (toolbar + wheel + drag-to-pan + keyboard).

### How was this patch tested?

- `build/sbt sql/Test/compile`
- `build/sbt sql/scalastyle sql/Test/scalastyle`
- `dev/lint-js` on the SQL static resources directory

### Was this patch authored or co-authored using generative AI tooling?

Generated-by: GitHub Copilot CLI 1.0.44 with Claude Opus 4.7

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@dongjoon-hyun dongjoon-hyun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Could you provide a screenshot, @yaooqinn ?

var svg = svgArg || planVizContainer().select("svg");
if (!svg || svg.empty() || !planVizZoom) return;
svg.call(planVizZoom.transform, d3.zoomIdentity);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that d3.zoomIdentity, what is the difference from invoking updateZoomLevelLabel(1) directly instead of fitToViewport?

Is it for simply invoking event to update label somehow?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, this is overengineered. Pushed 280e7aa9e77 to drop fitToViewport and call updateZoomLevelLabel(1) directly.

setupZoomAndPan is invoked on a freshly created <svg> (both render paths do selectAll("svg").remove() before appending), so:

  1. svg.call(planVizZoom) auto-initializes svgNode.__zoom to d3.zoomIdentity.
  2. The just-appended zoom-layer <g> has no transform attribute, and the SVG's viewBox with the default preserveAspectRatio="xMidYMid meet" already provides the natural fit.

So svg.call(planVizZoom.transform, d3.zoomIdentity) was firing a zoom event whose only observable effect was setting the toolbar label to 100%. Calling updateZoomLevelLabel(1) directly is equivalent and clearer.

@yaooqinn
Copy link
Copy Markdown
Member Author

yaooqinn commented May 8, 2026

@dongjoon-hyun sure, let me run a demo on my laptop, but it could be not that obvious to take a look at the screenshot for an animation

@yaooqinn
Copy link
Copy Markdown
Member Author

yaooqinn commented May 8, 2026

Recording.2026-05-08.232958.mp4

…elLabel

Per review feedback: with the fresh SVG that setupZoomAndPan binds to,
d3-zoom auto-initializes __zoom to identity on `svg.call(zoom)`, the
zoom-layer has no transform attribute, and the SVG viewBox plus the
default `preserveAspectRatio="xMidYMid meet"` already provides the
natural fit. The previous `fitToViewport` helper therefore just fired
a zoom event whose only observable effect was setting the toolbar label
to 100%. Replace the call with `updateZoomLevelLabel(1)` directly and
remove the helper.

Generated-by: GitHub Copilot CLI 1.0.44 with Claude Opus 4.7

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@yaooqinn yaooqinn closed this in ce31445 May 9, 2026
yaooqinn added a commit that referenced this pull request May 9, 2026
### What changes were proposed in this pull request?

Add pan and zoom controls to the SQL execution plan visualization rendered
on the SQL tab's execution detail page.

The SVG that hosts the dagre-d3 plan now lives inside a fixed-height
viewport (70vh) and is wrapped in an inner `<g class="zoom-layer">`.
A `d3.zoom()` behavior is attached to the SVG and applies its transform
to the zoom-layer; the viewBox keeps performing the natural fit. A small
floating toolbar in the top-right offers `-` / current % / `+` buttons,
and `+` / `-` / `0` keyboard shortcuts work whenever the cursor is over
the plan area.

Notes:
- Pan/zoom is suppressed when the user interacts with HTML labels
  (`<foreignObject>`) so metric tables in detailed mode remain
  selectable.
- The SVG download is now insulated from the user's current view: the
  cloned SVG resets the zoom-layer transform and uses the viewBox as
  its own `width`/`height` so external viewers render at the natural
  plan size, matching the previous download behavior.
- Detailed-mode rerender reuses the same setup so zoom/pan keeps working
  after toggling "Show metrics in graph nodes".

### Why are the changes needed?

Spark plans frequently grow large enough that the previous fit-the-page
SVG becomes hard to read: clusters wrap, scroll bars chase the cursor,
and zooming the browser distorts the surrounding page. Standard
pan/zoom on the plan itself is the conventional way to navigate large
DAGs and is a building block for further plan-viz work under
SPARK-55760.

### Does this PR introduce _any_ user-facing change?

Yes. The SQL tab's plan visualization has a fixed-height viewport with
new zoom controls (toolbar + wheel + drag-to-pan + keyboard).

### How was this patch tested?

- `build/sbt sql/Test/compile`
- `build/sbt sql/scalastyle sql/Test/scalastyle`
- `dev/lint-js` on the SQL static resources directory

### Was this patch authored or co-authored using generative AI tooling?

Generated-by: GitHub Copilot CLI 1.0.44 with Claude Opus 4.7

Closes #55769 from yaooqinn/SPARK-56792.

Authored-by: Kent Yao <yao@apache.org>
Signed-off-by: Kent Yao <yao@apache.org>
(cherry picked from commit ce31445)
Signed-off-by: Kent Yao <yao@apache.org>
yaooqinn added a commit that referenced this pull request May 9, 2026
### What changes were proposed in this pull request?

Add pan and zoom controls to the SQL execution plan visualization rendered
on the SQL tab's execution detail page.

The SVG that hosts the dagre-d3 plan now lives inside a fixed-height
viewport (70vh) and is wrapped in an inner `<g class="zoom-layer">`.
A `d3.zoom()` behavior is attached to the SVG and applies its transform
to the zoom-layer; the viewBox keeps performing the natural fit. A small
floating toolbar in the top-right offers `-` / current % / `+` buttons,
and `+` / `-` / `0` keyboard shortcuts work whenever the cursor is over
the plan area.

Notes:
- Pan/zoom is suppressed when the user interacts with HTML labels
  (`<foreignObject>`) so metric tables in detailed mode remain
  selectable.
- The SVG download is now insulated from the user's current view: the
  cloned SVG resets the zoom-layer transform and uses the viewBox as
  its own `width`/`height` so external viewers render at the natural
  plan size, matching the previous download behavior.
- Detailed-mode rerender reuses the same setup so zoom/pan keeps working
  after toggling "Show metrics in graph nodes".

### Why are the changes needed?

Spark plans frequently grow large enough that the previous fit-the-page
SVG becomes hard to read: clusters wrap, scroll bars chase the cursor,
and zooming the browser distorts the surrounding page. Standard
pan/zoom on the plan itself is the conventional way to navigate large
DAGs and is a building block for further plan-viz work under
SPARK-55760.

### Does this PR introduce _any_ user-facing change?

Yes. The SQL tab's plan visualization has a fixed-height viewport with
new zoom controls (toolbar + wheel + drag-to-pan + keyboard).

### How was this patch tested?

- `build/sbt sql/Test/compile`
- `build/sbt sql/scalastyle sql/Test/scalastyle`
- `dev/lint-js` on the SQL static resources directory

### Was this patch authored or co-authored using generative AI tooling?

Generated-by: GitHub Copilot CLI 1.0.44 with Claude Opus 4.7

Closes #55769 from yaooqinn/SPARK-56792.

Authored-by: Kent Yao <yao@apache.org>
Signed-off-by: Kent Yao <yao@apache.org>
(cherry picked from commit ce31445)
Signed-off-by: Kent Yao <yao@apache.org>
@yaooqinn yaooqinn deleted the SPARK-56792 branch May 9, 2026 04:28
@yaooqinn
Copy link
Copy Markdown
Member Author

yaooqinn commented May 9, 2026

Merge to master/4.x/4.2, thank you @sarutak @dongjoon-hyun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants