You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@hop.apache.org by "mahdi-chihaoui-speedykom (via GitHub)" <gi...@apache.org> on 2026/09/08 07:58:21 UTC
[I] [Bug]: Hop Web canvas overlay attaches to the wrong element (or none), leaving a blank graph (hop)
mahdi-chihaoui-speedykom opened a new issue, #8286:
URL: https://github.com/apache/hop/issues/8286
### Apache Hop version?
SNAPSHOT-20260908 — verified against main @ e6d9ef48f6; also in 2.19.0.
### Java version?
OpenJDK 21
### Operating system
Docker
### What happened?
<!--
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
Hop Web renders pipeline/workflow graphs as a server-rendered SVG snapshot placed in an
HTML overlay above the RAP canvas widget. The browser side must decide *which* DOM element
that overlay attaches to. The resolver guesses when its intended target is not yet in the
DOM, and the guess is unsound:
https://github.com/apache/hop/blob/e6d9ef48f6ebc834d57b7e6d59b9dfeb08a748b3/rap/src/main/resources/org/apache/hop/ui/hopgui/canvas-svg.js#L47-L73
```js
function findCanvasForWidget(canvasId) {
if (canvasId) {
var widgetElement = document.getElementById(canvasId);
if (widgetElement) {
if (widgetElement.tagName === "CANVAS") return widgetElement;
var nestedCanvas = widgetElement.querySelector("canvas");
if (nestedCanvas) return nestedCanvas;
}
}
return findVisibleGraphCanvas(); // <-- guesses
}
function findVisibleGraphCanvas() {
// returns the FIRST canvas in the document larger than 500x500
}
```
The server always sends the correct widget id (`CanvasSvgRendererHandler.updateRemoteObject`
sets `canvasId` before calling `attachListener`), so the guess is never *needed* — but it is
reached in two situations:
1. the widget element is not in the DOM yet (initial RAP layout), or
2. it is, but RAP has not yet lazily created its nested `<canvas>` (that element only appears
on the first GC draw).
In both cases control reaches `findVisibleGraphCanvas()`, whose only test is
`rect.width > 500 && rect.height > 500`. That single line produces three distinct bugs:
| Document state | Guess returns | Symptom |
|---|---|---|
| graph canvas absent, viewport large | the graph canvas | works *by accident* |
| graph canvas absent, a dialog is open | **the dialog's canvas** | graph SVG renders inside the dialog |
| graph canvas absent, viewport small | **`null`** | nothing renders at all |
**Row 3 is the most visible.** When no canvas in the document clears 500x500,
`_findAndAttachCanvas` retries 20 x 100 ms and then **gives up silently**:
https://github.com/apache/hop/blob/e6d9ef48f6ebc834d57b7e6d59b9dfeb08a748b3/rap/src/main/resources/org/apache/hop/ui/hopgui/canvas-svg.js#L384-L404
`_attachToCanvas` is never called, so there is no overlay, no `canvasRender` request, and no
console error — just a blank canvas. Enlarging the window or going fullscreen triggers an SWT
paint, which calls `attachListener` again; the canvas now clears 500x500 and the graph appears.
Note the threshold applies to the **canvas rect, not the window**: the perspective sidebar,
toolbar, tab bar and the `SashForm` the canvas shares with the execution/results panel all
subtract from it. So there is no clean window breakpoint, and dragging that sash reproduces
the blank canvas at a fixed window size.
The same resolver and the same 500x500 threshold are duplicated in `canvas-zoom.js`
(its comment reads "same approach as canvas-svg.js"), so mouse-wheel zoom is dead under the
same conditions:
https://github.com/apache/hop/blob/e6d9ef48f6ebc834d57b7e6d59b9dfeb08a748b3/rap/src/main/resources/org/apache/hop/ui/hopgui/canvas-zoom.js#L95-L118
This is not a server-side or authorization problem: `HopGuiPipelineGraph.paintControl` skips
only when a dimension is exactly `0`, and `PipelineCanvasSvgRenderer` has no size gate. The
snapshot is rendered and stored correctly; the browser simply never attaches it.
The overlay and its fallback were introduced in #7431 (issue #7430), which added
`canvas-svg.js`. The fallback was a reasonable safety net at the time; it has since become
the failure mode.
### Steps to reproduce
Blank canvas (row 3):
1. Open Hop Web in a browser window roughly 800x600 or smaller (or keep the window large and
drag the execution/results sash up until the canvas is under ~500 px tall).
2. Open any pipeline.
3. The canvas is blank. DevTools shows no `canvasRender` request and no error.
4. Maximise the window -> the graph appears. Shrink it again -> it *stays* rendered, because
the polling loop only re-syncs layout and never re-resolves the target.
That last asymmetry is the giveaway: a genuine small-canvas rendering bug would also break on
the shrink.
Graph inside a dialog (row 2):
1. Load a pipeline in a fresh session (embedding Hop Web in an iframe widens the window).
2. Open a transform dialog or the context/add-transform dialog while the graph is still
resolving.
3. The graph SVG is appended under the dialog's DOM subtree.
### Proposed fix
Resolve strictly from the server-provided widget id and delete the guess.
```js
/**
* Resolve the element the SVG overlay anchors to, strictly from the widget id the server
* sent. Returns null when the widget is not in the DOM yet; the caller retries. Never
* resolves to an unrelated canvas.
*/
function findCanvasForWidget(canvasId) {
if (!canvasId) return null;
var widgetElement = document.getElementById(canvasId);
if (!widgetElement) return null;
if (widgetElement.tagName === "CANVAS") return widgetElement;
// RAP creates the nested <canvas> lazily on the first GC draw. Prefer it so the overlay
// keeps its existing parent and geometry, but never treat its absence as a reason to
// look elsewhere.
return widgetElement.querySelector("canvas");
}
```
`findVisibleGraphCanvas()` can then be removed entirely — it becomes unreachable, since
`canvasId` is always set before `attachListener`.
Second, make exhaustion degrade instead of failing silently. In `_findAndAttachCanvas`, after
the retries, anchor to the widget element itself and warn:
```js
if (!canvas) {
if (attempts < maxAttempts) { setTimeout(tryFind, 100); return; }
var widget = self._canvasId ? document.getElementById(self._canvasId) : null;
if (widget) { self._attachToCanvas(widget); return; }
console.warn("hop.CanvasSvgRenderer: widget " + self._canvasId +
" never appeared; graph overlay not attached");
return;
}
```
Anchoring to the widget element is coordinate-safe: every mouse handler derives graph
coordinates as `event.clientX - this._canvas.getBoundingClientRect().left` against whichever
element `_canvas` points at, and never uses the target-relative `event.offsetX`.
`_syncOverlayLayout` reads its geometry from the same element, so the two stay consistent.
Apply both changes to `canvas-zoom.js` as well.
Incidentally, `canvas-zoom.js` line 86 (`setCanvas`) reads `properties.canvasId` while the
server sets the property as `"canvas"`. It is currently harmless because the registered
`propertyHandler.canvas` intercepts and `setCanvas` never runs, but it would null out
`_canvasId` and force the fallback on every update if it were ever wired up. Worth deleting
along with the equivalent dead `setCanvasId` in `canvas-svg.js`.
I have this fix working against 2.19.0 and am happy to open a PR.
### Possibly the same root cause
#8281 ("Hop Web gets confused when floating the results panel") may well be this bug: floating
the results panel resizes the graph canvas, and the reported behaviour of the graph
re-surfacing when the context dialog appears, and reappearing while a selection lasso is
dragged, both match repaint-triggered re-resolution. Worth cross-checking before treating them
as separate.
### Issue Priority
Priority: 2
### Issue Component
Component: Hop Web
--
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: issues-unsubscribe@hop.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [I] [Bug]: Hop Web canvas overlay attaches to the wrong element (or none), leaving a blank graph (hop)
Posted by "mattcasters (via GitHub)" <gi...@apache.org>.
mattcasters closed issue #8286: [Bug]: Hop Web canvas overlay attaches to the wrong element (or none), leaving a blank graph
URL: https://github.com/apache/hop/issues/8286
--
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: issues-unsubscribe@hop.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [I] [Bug]: Hop Web canvas overlay attaches to the wrong element (or none), leaving a blank graph (hop)
Posted by "mattcasters (via GitHub)" <gi...@apache.org>.
mattcasters commented on issue #8286:
URL: https://github.com/apache/hop/issues/8286#issuecomment-5589083993
Thanks for tracking this down. I failed to catch the underlying issue in #8281. Appreciate it.
--
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: issues-unsubscribe@hop.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org