You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by sa...@apache.org on 2026/06/27 11:41:57 UTC
(spark) branch master updated: [SPARK-57631][WEBUI] Require modifier key for wheel-zoom on SQL plan DAG to restore page scrolling
This is an automated email from the ASF dual-hosted git repository.
sarutak pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new 9831817ab9dd [SPARK-57631][WEBUI] Require modifier key for wheel-zoom on SQL plan DAG to restore page scrolling
9831817ab9dd is described below
commit 9831817ab9dd8185d9fb0a9741b7623ae9869116
Author: Kousuke Saruta <sa...@amazon.co.jp>
AuthorDate: Sat Jun 27 20:41:45 2026 +0900
[SPARK-57631][WEBUI] Require modifier key for wheel-zoom on SQL plan DAG to restore page scrolling
### What changes were proposed in this pull request?
Require Ctrl (or Cmd on macOS, Super on Linux) + scroll wheel to zoom the SQL plan DAG on the `/SQL/execution` page. Unmodified scroll gestures now pass through for normal page scrolling.
Additionally, a transient overlay hint ("⌘ + scroll to zoom" on Mac, "Super + scroll to zoom" ,"Ctrl + scroll to zoom" otherwise) is shown when the user scrolls without the modifier key, following the same UX pattern as Google Maps.
### Why are the changes needed?
The DAG visualization occupies a 70vh viewport and captures all wheel events for zoom via d3-zoom. This makes it nearly impossible to scroll past the DAG without moving the cursor to the narrow margins on either side of the graph area. The problem is especially pronounced on pages with additional content below the DAG (e.g., when a node detail panel is not open).
### How does this fix work?
1. Added a `wheel` event type check in the `d3.zoom().filter()` to reject unmodified wheel events.
2. After `svg.call(planVizZoom)`, the d3-zoom wheel listener (registered with `{passive: false}`) is detached and replaced with a custom wrapper that only forwards Ctrl/Cmd+wheel to the original d3 handler. This ensures the browser's native scrolling is never blocked by d3's non-passive listener registration.
3. A CSS-animated hint overlay is shown on unmodified scroll to inform users how to zoom.
Notes:
- Trackpad pinch-to-zoom still works because browsers synthesize pinch gestures as `wheel` events with `ctrlKey: true`.
- Drag-to-pan behavior is unchanged.
- The `+`/`-` toolbar buttons and keyboard shortcuts continue to work as before.
### Does this PR introduce _any_ user-facing change?
Yes. Wheel-zoom on the SQL plan DAG now requires holding Ctrl (Cmd on Mac). Plain scroll gestures scroll the page. A hint overlay guides users to the new behavior.
### How was this patch tested?
Manual testing with Chrome and Firefox on macOS and Ubuntu, and Safari on macOS:
- Verified unmodified scroll scrolls the page past the DAG
- Verified Ctrl+scroll zooms the DAG
- Verified trackpad pinch zooms the DAG
- Verified drag-to-pan works as before
- Verified Hint overlay appears for 1.0s then enters a 3s cooldown before it can reappear
- Verified toolbar +/- buttons and keyboard shortcuts still work
https://github.com/user-attachments/assets/f2b856c5-9cb4-4128-bd60-df5990af47bb
### Was this patch authored or co-authored using generative AI tooling?
Kiro CLI / Claude
Closes #56694 from sarutak/fix-sql-dag-zoom-scroll-ux.
Authored-by: Kousuke Saruta <sa...@amazon.co.jp>
Signed-off-by: Kousuke Saruta <sa...@apache.org>
---
.../sql/execution/ui/static/spark-sql-viz.css | 20 +++++++++
.../spark/sql/execution/ui/static/spark-sql-viz.js | 48 ++++++++++++++++++++++
2 files changed, 68 insertions(+)
diff --git a/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.css b/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.css
index 738e70fdd127..7ca3ba9275da 100644
--- a/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.css
+++ b/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.css
@@ -243,3 +243,23 @@ svg g.cluster.search-dimmed {
.sql-cell-details[open] > summary {
margin-bottom: 0.25rem;
}
+
+/* Zoom hint overlay */
+.plan-viz-zoom-hint {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: rgba(0, 0, 0, 0.7);
+ color: #fff;
+ padding: 8px 16px;
+ border-radius: 6px;
+ font-size: 14px;
+ pointer-events: none;
+ opacity: 0;
+ transition: opacity 0.2s;
+ z-index: 10;
+}
+.plan-viz-zoom-hint.visible {
+ opacity: 1;
+}
\ No newline at end of file
diff --git a/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.js b/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.js
index 81d4562cbb35..7c1391c9d2b4 100644
--- a/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.js
+++ b/sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.js
@@ -765,6 +765,54 @@ function setupZoomAndPan(svg, zoomLayer) {
// provides the natural fit, and the zoom-layer has no transform, so no
// explicit transform is required here.
updateZoomLevelLabel(1);
+
+ // Remove d3-zoom's wheel listener (which is registered as non-passive and
+ // can block page scrolling) and replace it with a gated wrapper that only
+ // forwards Ctrl/Cmd+wheel to d3, letting unmodified scrolls pass through.
+ // "wheel.zoom" is d3-zoom's internal event namespace (stable since d3 v4).
+ // The null-guard below protects against future d3 changes.
+ var d3WheelHandler = svg.on("wheel.zoom");
+ svg.on("wheel.zoom", null);
+ svgNode.addEventListener("wheel", function (e) {
+ if (e.ctrlKey || e.metaKey) {
+ // Prevent the browser's native page zoom so only the DAG zooms.
+ e.preventDefault();
+ // Forward to d3-zoom's original handler for zoom behavior.
+ // Note: trackpad pinch gestures fire as wheel events with ctrlKey=true,
+ // so pinch-to-zoom still works as expected.
+ if (d3WheelHandler) d3WheelHandler.call(this, e);
+ } else {
+ // Let the event propagate naturally for page scrolling and show hint
+ showZoomHint();
+ }
+ }, {passive: false});
+}
+
+var zoomHintTimeout;
+var zoomHintCooldown = false;
+function showZoomHint() {
+ if (zoomHintCooldown) return;
+ var container = document.getElementById("plan-viz-graph");
+ if (!container) return;
+ var hint = document.getElementById("plan-viz-zoom-hint");
+ if (!hint) {
+ hint = document.createElement("div");
+ hint.id = "plan-viz-zoom-hint";
+ hint.className = "plan-viz-zoom-hint";
+ var platform = navigator.platform || navigator.userAgent;
+ var isMac = /Mac|iPhone|iPad/.test(platform);
+ var isLinux = /Linux/.test(platform);
+ var modKey = isMac ? "\u2318" : isLinux ? "Super" : "Ctrl";
+ hint.textContent = modKey + " + scroll to zoom";
+ container.appendChild(hint);
+ }
+ hint.classList.add("visible");
+ zoomHintCooldown = true;
+ clearTimeout(zoomHintTimeout);
+ zoomHintTimeout = setTimeout(function () {
+ hint.classList.remove("visible");
+ setTimeout(function () { zoomHintCooldown = false; }, 3000);
+ }, 1000);
}
function updateZoomLevelLabel(scale) {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org