mattcasters opened a new pull request, #7431:
URL: https://github.com/apache/hop/pull/7431

   # Issue #7430 — Hop Web Canvas Rendering: Reviewer Recap
   
   **Branch:** `issue-7430`  
   **Commit:** `010a23e8ae` — *issue #7430 : Improve canvas rendering in Hop 
Web*  
   **Scope:** 39 files changed, +3922 / −260 lines
   
   ## Problem
   
   Hop Web pipeline and workflow canvases were unreliable compared to the 
desktop Hop GUI:
   
   - Canvas could appear blank after a server/browser restart.
   - Transform/action icons were incorrectly scaled.
   - Graph content was vertically misaligned relative to the toolbar and 
overlay.
   - Dark-mode transform icons lacked the contrast treatment used on desktop.
   - Interactive feedback (drag, pan, selection, navigation minimap, name 
hover) was missing or broken because the visible layer is now server-rendered 
SVG, while legacy RAP `canvas.js` drew underneath a hidden canvas.
   - Pipeline execution could crash SVG rendering when the layout resized (e.g. 
execution pane opening), due to missing status-indicator images.
   - Name hover underline positioning on the client was fragile and misaligned 
with SVG text.
   
   ## Solution Overview
   
   Introduce a **server-side SVG rendering pipeline** for Hop Web that reuses 
the existing `PipelinePainter` / `WorkflowPainter` logic via `SvgGc`, paired 
with a **client overlay** (`canvas-svg.js`) for responsive interaction 
previews. Desktop (RCP) behavior is unchanged via a no-op `CanvasSvgFacadeImpl` 
in the `rcp` module.
   
   ```mermaid
   flowchart LR
       subgraph server [Hop Web Server]
           Graph[HopGuiPipelineGraph / HopGuiWorkflowGraph]
           Renderer[PipelineCanvasSvgRenderer / WorkflowCanvasSvgRenderer]
           Painter[PipelinePainter / WorkflowPainter]
           SvgGc[SvgGc]
           Registry[CanvasGraphRegistry]
           Service[CanvasRenderServiceHandler]
           Graph --> Renderer --> Painter --> SvgGc
           Renderer --> Registry
           Registry --> Service
       end
       subgraph client [Browser]
           Overlay[canvas-svg.js overlay]
           Legacy[canvas.js - interaction modes]
           Service -->|JSON: svg + areas + props| Overlay
           Overlay --> Legacy
       end
   ```
   
   ### Data flow
   
   1. Graph paint on web calls `CanvasSvgFacade.renderPipeline()` / 
`renderWorkflow()`.
   2. Renderer produces SVG XML plus `AreaOwner` click regions and canvas props 
(magnification, offsets, theme, viewPort, graphPort, etc.).
   3. Snapshot is stored in per-session `CanvasGraphRegistry` with a monotonic 
revision.
   4. `CanvasSvgRendererHandler` pushes `renderRevision` to the browser; client 
fetches via `CanvasRenderServiceHandler` (`?servicehandler=canvasRender`).
   5. Client injects SVG into an overlay div aligned on top of the RAP canvas; 
`canvas.js` continues to handle SWT event modes (drag, select, hop, pan).
   
   ---
   
   ## Changes by Area
   
   ### 1. Server-side SVG rendering (engine)
   
   | File | Purpose |
   |------|---------|
   | `PipelineCanvasSvgRenderer.java` | Renders pipeline graphs to SVG using 
`PipelinePainter` |
   | `WorkflowCanvasSvgRenderer.java` | Same for workflows |
   | `CanvasSvgRenderResult.java` | SVG string + area owners + view/graph ports 
|
   | `CanvasColorPalette.java` | Shared light/dark canvas color palette for 
`SvgGc` |
   | `SvgGc.java` | Major updates: dark mode palette, icon scale fix, dark-mode 
icon contrast, missing `SUCCESS`/`DATA` images, null-safe `drawImage`, 
`GRAPH_BOLD` font |
   | `BasePainter.java` | `isWebCanvasRendering()` helper (`gc instanceof 
SvgGc`) |
   | `PipelinePainter.java` / `WorkflowPainter.java` | **Web:** bold name on 
hover; **Desktop:** underline on hover (unchanged) |
   | `IGc.java` | Added `EFont.GRAPH_BOLD` |
   
   **Icon scaling fix:** `SvgGc.drawImage()` no longer double-applies 
magnification; embed scale uses logical size only (see `SvgGcIconScaleTest`).
   
   **Execution status crash fix:** `EImage.SUCCESS` (and `DATA`) were 
referenced by `PipelinePainter.drawTransformStatusIndicator()` but not 
registered in `SvgGc`. Added SVG assets and null guards in `drawImage()` 
overloads.
   
   ### 2. Dark mode icon contrast (core)
   
   | File | Purpose |
   |------|---------|
   | `SvgDarkModeContrast.java` | Shared clone-and-swap logic for SVG icon 
colors in dark mode |
   | `SvgDarkModeContrastTest.java` | Unit tests |
   | `SwtUniversalImageSvg.java` | Refactored to use shared contrast helper |
   
   `SvgGc` applies contrasting colors when `darkMode` is true, using 
`PropsUi.getContrastingColorStrings()` passed through the renderer context. 
Per-filename SVG document cache avoids repeated processing.
   
   ### 3. Hop Web integration (rap + ui)
   
   | File | Purpose |
   |------|---------|
   | `CanvasSvgFacade.java` | Platform abstraction (loaded via 
`ImplementationLoader`) |
   | `CanvasSvgFacadeImpl.java` (rap) | Web implementation: render, snapshot, 
notify client |
   | `CanvasSvgFacadeImpl.java` (rcp) | No-op stub for desktop |
   | `CanvasGraphRegistry.java` | Per-`UISession` registry (fixes blank canvas 
after restart — **not** a static global) |
   | `CanvasRenderServiceHandler.java` | HTTP endpoint serving cached SVG JSON |
   | `CanvasRenderSnapshot.java` | Revisioned snapshot model |
   | `CanvasSvgRendererHandler.java` | RAP remote object for client polling / 
revision push |
   | `CanvasInteractionHandler.java` | Hover notifications from client to 
server |
   | `AreaOwnerJsonSerializer.java` | Serializes click regions for client 
hit-testing |
   | `CanvasSvgHelper.java` | Utility to notify canvas ready from explorer 
perspective |
   | `HopGuiPipelineGraph.java` / `HopGuiWorkflowGraph.java` | Web paint path 
via SVG facade; `handleWebCanvasHover()` updates `mouseOverName` when 
`EnvironmentUtils.isWeb()` |
   | `HopGuiAbstractGraph.java` | `applyMouseOverNameHover()` — shared hover 
logic, fixes redraw when moving between two names |
   | `DragViewZoomBase.java` | Navigation minimap / viewport support in web 
props |
   | `CanvasFacadeImpl.java` / `CanvasZoomHandler.java` | Adjustments for 
coexistence with SVG overlay |
   | `ExplorerPerspective.java` | Notify SVG renderer when graphs open |
   | `HopWeb.java` / `HopWebEntryPoint.java` | Register `canvas-svg.js` and RAP 
data keys |
   
   ### 4. Client overlay (rap/resources)
   
   | File | Purpose |
   |------|---------|
   | `canvas-svg.js` | **New** (~1150 lines): SVG overlay, polling, interaction 
previews |
   | `canvas.js` | Minor coordinate fixes (`fx`/`fy`); still drives RAP 
interaction modes |
   
   **Client features in `canvas-svg.js`:**
   
   - SVG host overlay synced to canvas position (`_syncOverlayLayout`).
   - **Transform/action drag preview** — dashed selection rects follow cursor 
during drag.
   - **Pan preview** — middle-click or Ctrl+background drag; semi-transparent 
SVG + pan bounds outline.
   - **Navigation minimap drag** — blue viewport rectangle preview.
   - **Selection lasso** — dashed rectangle on background click-drag (visible 
above SVG; server still handles selection via `canvas.js` / graph logic).
   - **Name hover** — server re-renders bold text; client only sets pointer 
cursor (underline overlay removed).
   - Hover events forwarded to `CanvasInteractionHandler` for tooltips and 
`mouseOverName` updates.
   
   ### 5. Tests
   
   | Test | Covers |
   |------|--------|
   | `PipelineCanvasSvgRendererTest` | SVG output and click regions for a 
minimal pipeline |
   | `SvgGcIconScaleTest` | Icon embed scale independent of magnification 
parameter |
   | `SvgDarkModeContrastTest` | Dark mode color substitution |
   
   ### 6. Local development
   
   | File | Purpose |
   |------|---------|
   | `docker/run-hop-web-local.sh` | Convenience script to build and run Hop 
Web locally |
   | `.gitignore` | Ignores `docker/local-data/` |
   
   ---
   
   ## Behavioral Notes for Reviewers
   
   ### Desktop vs Hop Web divergence (intentional)
   
   | Behavior | Desktop (RCP) | Hop Web |
   |----------|---------------|---------|
   | Canvas rendering | `SwtGc` via `drawPipelineImage()` | `SvgGc` via 
`CanvasSvgFacade` |
   | Name hover affordance | Underline | **Bold** (`EFont.GRAPH_BOLD`) |
   | Interaction previews | `canvas.js` on visible canvas | `canvas-svg.js` 
effects layer + `canvas.js` modes |
   | `CanvasSvgFacade` | No-op (`rcp`) | Full implementation (`rap`) |
   
   Web/desktop split in painters uses `isWebCanvasRendering()` (`SvgGc` vs 
`SwtGc`), not `EnvironmentUtils` in the engine layer. 
`EnvironmentUtils.isWeb()` is used in graph classes for hover wiring.
   
   ### Session scoping
   
   `CanvasGraphRegistry` uses `SingletonUtil.getSessionInstance()` — each 
browser session gets its own snapshots and remote objects. This was critical to 
fix the post-restart blank canvas bug caused by stale static/global state.
   
   ### Revision / polling
   
   - Client polls every 500ms as a fallback.
   - `renderRevision` push triggers immediate fetch when the server redraws 
(e.g. on name hover).
   - Client periodically forces full refresh (`clientRev=0`) to recover missed 
updates.
   
   ### Vertical alignment fix
   
   - Pipeline graph toolbar attachment uses `FormAttachment(toolBar, 0)` 
instead of toolbar height offset.
   - Overlay layout sync matches canvas offset within parent composite.
   - `canvas.js` coordinate helpers no longer double-apply offset.
   
   ---
   
   ## How to Test Locally
   
   ```bash
   ./mvnw -pl ui,rap,engine,core -am clean package -DskipTests 
-Dspotless.check.skip=true -Drat.skip=true
   ./docker/run-hop-web-local.sh --skip-maven
   ```
   
   Hard-refresh the browser after deploy.
   
   ### Suggested manual test checklist
   
   - [ ] Open pipeline/workflow — graph renders, icons correct size
   - [ ] Restart Hop Web container — canvas still renders (not blank)
   - [ ] Dark mode — transform icons have readable contrast
   - [ ] Drag transform — preview rects track cursor; drop updates position
   - [ ] Middle-click / Ctrl+drag background — pan preview and release
   - [ ] Drag navigation minimap viewport — blue rectangle preview
   - [ ] Background click-drag — selection lasso visible; release selects 
transforms
   - [ ] Hover transform name — **bold** on web; click still opens edit 
(single-click mode)
   - [ ] Execute pipeline (e.g. `add-constants.hpl`) — no SVG NPE when 
execution pane resizes; success indicators render
   - [ ] Desktop Hop GUI — name hover still shows **underline**, not bold
   
   ---
   
   ## Review Focus Areas
   
   1. **Session lifecycle** — `CanvasGraphRegistry` register/unregister on 
graph open/close; no leaks across sessions.
   2. **Performance** — full SVG re-render on hover enter/leave; acceptable for 
typical graphs but worth watching on large pipelines.
   3. **Coordinate consistency** — screen vs graph coords across 
`canvas-svg.js`, `canvas.js`, and Java `AreaOwner` regions.
   4. **Null safety in `SvgGc.drawImage()`** — silent skip when image missing; 
confirm no visual gaps are acceptable vs logging.
   5. **Facade split** — `ImplementationLoader` resolves `rap` vs `rcp` 
`CanvasSvgFacadeImpl` correctly in both assemblies.
   6. **Apache license headers** — all new Java/JS files include standard ASF 
headers (RAT).
   
   ---
   
   ## File List (commit `010a23e8ae`)
   
   ```
   core/       SvgDarkModeContrast.java, SvgDarkModeContrastTest.java, 
test-icon.svg
   engine/     PipelineCanvasSvgRenderer, WorkflowCanvasSvgRenderer, 
CanvasColorPalette,
               CanvasSvgRenderResult, SvgGc, BasePainter, PipelinePainter, 
WorkflowPainter,
               IGc, SvgGcIconScaleTest, PipelineCanvasSvgRendererTest
   rap/        CanvasSvgFacadeImpl, CanvasGraphRegistry, 
CanvasRenderServiceHandler,
               CanvasSvgRendererHandler, CanvasInteractionHandler, 
AreaOwnerJsonSerializer,
               CanvasRenderSnapshot, canvas-svg.js, canvas.js, CanvasFacadeImpl,
               CanvasZoomHandler, HopWeb, HopWebEntryPoint
   rcp/        CanvasSvgFacadeImpl (no-op)
   ui/         CanvasSvgFacade, CanvasSvgHelper, HopGuiPipelineGraph, 
HopGuiWorkflowGraph,
               HopGuiAbstractGraph, SwtUniversalImageSvg, DragViewZoomBase, 
ExplorerPerspective,
               ConfigKeyboardShortcutsTab
   docker/     run-hop-web-local.sh
   .gitignore  docker/local-data/
   ```
   
   ---
   
   ## Summary
   
   This change replaces Hop Web's unreliable client-side canvas drawing with 
**server-rendered SVG** that shares the desktop painter code path, while 
preserving RAP-based mouse interaction through a layered architecture. 
Follow-up polish addressed alignment, dark mode, interaction previews, 
selection lasso, execution-time rendering crashes, and web-specific bold name 
hover — without altering desktop underline behavior.


-- 
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]

Reply via email to