From 762a9e8bcac169c316e3fae0c7df36676f4c105c Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 1 Jul 2026 14:26:11 +0200 Subject: [PATCH] Improve PDF viewer overlay synchronization Refactor `EnvelopeSenderEditorPage.razor` to enhance the structure and behavior of the PDF editor wrapper: - Add `class="pdf-editor-wrapper"` and update `overflow` to `auto`. - Update `DxPdfViewer`'s `CssClass` to `sender-editor-pdf-viewer`. - Introduce `OnAfterRenderAsync` to synchronize the overlay with the viewer. Add new styles in `envelope-viewer.css` for better layout: - Ensure `.pdf-editor-wrapper` and `.sender-editor-pdf-viewer` occupy full dimensions. - Center and align content within the PDF viewer. Enhance `envelope-editor.js` with `syncOverlayToPage`: - Dynamically adjust overlay position and size relative to the viewer. - Use `MutationObserver` and event listeners for real-time synchronization. - Handle delayed rendering with scheduled sync attempts. These changes improve overlay alignment, user experience, and code maintainability. --- .../Pages/EnvelopeSenderEditorPage.razor | 17 ++++- .../wwwroot/css/envelope-viewer.css | 27 +++++++ .../wwwroot/js/envelope-editor.js | 71 +++++++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor index fbc04868..c1cd9fca 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor @@ -147,15 +147,15 @@ else { @* PDF viewer + overlay wrapper *@ -
+
@* DxPdfViewer — zoom fixed to 1.0 for reliable coordinate mapping *@ + CssClass="sender-editor-pdf-viewer" /> @* Transparent overlay for click capture (active only in placement mode) *@
{ + const page = currentWrapper.querySelector(".dxbrv-report-preview-content"); + if (page) { + return page; + } + + return currentWrapper.querySelector(".dxbrv-report-preview-content-img") || + currentWrapper.querySelector("img.dxbrv-report-preview-content-img") || + currentWrapper.querySelector(".dxbrv-document-surface img"); + }; + + const sync = () => { + const currentWrapper = document.getElementById(wrapperId); + const currentOverlay = document.getElementById(overlayId); + + if (!currentWrapper || !currentOverlay) { + return; + } + + const target = findTarget(currentWrapper); + if (!target) { + currentOverlay.style.left = "0px"; + currentOverlay.style.top = "0px"; + currentOverlay.style.width = "0px"; + currentOverlay.style.height = "0px"; + return; + } + + const wrapperRect = currentWrapper.getBoundingClientRect(); + const targetRect = target.getBoundingClientRect(); + + currentOverlay.style.left = `${targetRect.left - wrapperRect.left + currentWrapper.scrollLeft}px`; + currentOverlay.style.top = `${targetRect.top - wrapperRect.top + currentWrapper.scrollTop}px`; + currentOverlay.style.width = `${targetRect.width}px`; + currentOverlay.style.height = `${targetRect.height}px`; + }; + + const scheduleSync = () => requestAnimationFrame(sync); + + const observer = new MutationObserver(scheduleSync); + observer.observe(wrapper, { childList: true, subtree: true, attributes: true }); + + wrapper.addEventListener("scroll", scheduleSync, { passive: true }); + window.addEventListener("resize", scheduleSync); + + window.envelopeEditor._overlaySyncState[overlayId] = { + sync, + observer + }; + + sync(); + setTimeout(sync, 50); + setTimeout(sync, 150); + setTimeout(sync, 400); } };