yaooqinn commented on code in PR #55769:
URL: https://github.com/apache/spark/pull/55769#discussion_r3209733559


##########
sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.js:
##########
@@ -694,12 +713,118 @@ function rerenderWithDetailedLabels() {
   setupTooltipForSparkPlanNode(g);
   resizeSvg(svg);
   postprocessForAdditionalMetrics();
+  setupZoomAndPan(svg, zoomLayer);
+}
+
+/* ---------------------- *
+ * | Zoom and pan        | *
+ * ---------------------- */
+
+/*
+ * Wire d3-zoom to the SVG: apply transforms to the inner zoom-layer group,
+ * fit the graph to the viewport on load, and bind toolbar/keyboard controls.
+ */
+function setupZoomAndPan(svg, zoomLayer) {
+  var svgNode = svg.node();
+  if (!svgNode || !zoomLayer || zoomLayer.empty()) return;
+
+  planVizZoom = d3.zoom()
+    .scaleExtent([PlanVizConstants.zoomMin, PlanVizConstants.zoomMax])
+    .filter(function (event) {
+      // Suppress pan/zoom when the user interacts with HTML labels
+      // (foreignObject) so text inside metrics tables remains selectable.
+      // Also ignore right-click to leave the browser context menu intact.
+      if (event.button === 2) return false;
+      var target = event.target;
+      while (target && target !== svgNode) {
+        if (target.nodeName === "foreignObject") return false;
+        target = target.parentNode;
+      }
+      return true;
+    })
+    .on("start", function () { svg.classed("grabbing", true); })
+    .on("zoom", function (event) {
+      zoomLayer.attr("transform", event.transform);
+      updateZoomLevelLabel(event.transform.k);
+    })
+    .on("end", function () { svg.classed("grabbing", false); });
+
+  svg.call(planVizZoom);
+
+  // Fit the graph to the viewport on initial render.
+  fitToViewport(svg);
+}
+
+/* Compute the transform that fits the current viewBox content into the SVG's
+ * displayed size, then apply it via d3-zoom. The SVG's viewBox already maps
+ * content to fit the displayed area (preserveAspectRatio="xMidYMid meet" by
+ * default), so the identity transform is the natural fit. */
+function fitToViewport(svgArg) {
+  var svg = svgArg || planVizContainer().select("svg");
+  if (!svg || svg.empty() || !planVizZoom) return;
+  svg.call(planVizZoom.transform, d3.zoomIdentity);
+}

Review Comment:
   You're right, this is overengineered. Pushed 
[`280e7aa9e77`](https://github.com/apache/spark/pull/55769/commits/280e7aa9e77ec90197cdb47acff84e2ba8be7d57)
 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.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to