Integrate DxPdfViewer and remove custom zoom controls

Replaced custom zoom controls in `EnvelopeReceiverPage.razor` with the built-in zoom functionality of the `DevExpress.Blazor.PdfViewer` component (`DxPdfViewer`).

- Removed custom zoom buttons, slider, and JavaScript zoom logic.
- Introduced `_viewerZoomLevel` to align with `DxPdfViewer.ZoomLevel`.
- Synchronized zoom state using `ZoomLevelChanged` to update `_currentZoom`.
- Updated overlay redraw logic to react to viewer zoom changes.
- Modified `FitToWidth` and `SetZoom` methods to work with `DxPdfViewer`.
- Updated documentation to reflect integration decisions and findings.

These changes simplify zoom handling, reduce UI redundancy, and ensure proper synchronization between the viewer and overlay logic.
This commit is contained in:
2026-06-29 14:08:51 +02:00
parent 1ac7188466
commit 03367ebc4a
3 changed files with 109 additions and 47 deletions

View File

@@ -223,27 +223,6 @@
</button>
</div>
<div class="pdf-toolbar__divider"></div>
<div class="pdf-toolbar__section pdf-toolbar__zoom-section">
<button class="pdf-toolbar__btn" @onclick="ZoomOut" disabled="@(_currentZoom <= 50)" title="Verkleinern">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0zM4 6a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1H4z" />
</svg>
</button>
<div class="pdf-toolbar__zoom-slider-container">
<input type="range" class="pdf-toolbar__zoom-slider" min="50" max="300" step="@(PdfViewerOptions.Value.ZoomStepPercentage)" value="@_currentZoom" @oninput="OnZoomSliderChanged" title="@(_currentZoom)%" />
<div class="pdf-toolbar__zoom-label">@(_currentZoom)%</div>
</div>
<button class="pdf-toolbar__btn" @onclick="ZoomIn" disabled="@(_currentZoom >= 300)" title="Vergrößern">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0zM6.5 3a.5.5 0 0 0-1 0v2.5H3a.5.5 0 0 0 0 1h2.5V9a.5.5 0 0 0 1 0V6.5H9a.5.5 0 0 0 0-1H6.5V3z" />
</svg>
</button>
</div>
<div class="pdf-toolbar__divider"></div>
@if (_totalSignatures > 0)
{
<div class="pdf-toolbar__section">
@@ -351,9 +330,11 @@
<div id="pdf-dx-viewer-host" class="envelope-dx-viewer-host">
@if (_pdfDocumentContent is not null && _pdfDocumentContent.Length > 0)
{
<DxPdfViewer CssClass="envelope-dx-pdf-viewer"
<DxPdfViewer @ref="_pdfViewer"
CssClass="envelope-dx-pdf-viewer"
DocumentContent="@_pdfDocumentContent"
ZoomLevel="@_currentZoom"
ZoomLevel="@_viewerZoomLevel"
ZoomLevelChanged="OnViewerZoomLevelChanged"
IsSinglePagePreview="true" />
}
<div id="pdf-signature-layer" class="pdf-signature-layer pdf-signature-layer--dx"></div>
@@ -558,9 +539,11 @@
int _currentPage = 1;
int _totalPages = 0;
int _currentZoom = 150;
double _viewerZoomLevel = 1.5;
bool _showThumbnails = true;
bool _isLoggingOut = false;
DotNetObjectReference<EnvelopeReceiverPage>? _dotNetRef;
DxPdfViewer? _pdfViewer;
IReadOnlyList<SignatureDto> _signatures = [];
EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver.EnvelopeReceiverDto? _envelopeReceiver;
ClaimsPrincipal? _receiverUser;
@@ -766,6 +749,21 @@
await SetZoom(requestedZoom);
}
async Task OnViewerZoomLevelChanged(double newZoomLevel)
{
_viewerZoomLevel = newZoomLevel;
if (newZoomLevel > 0)
{
_currentZoom = (int)Math.Round(newZoomLevel * 100, MidpointRounding.AwayFromZero);
}
await JSRuntime.InvokeVoidAsync("pdfViewer.setViewState", _currentPage, _currentZoom);
await Task.Delay(150);
await RenderSignatureButtonsAsync();
await InvokeAsync(StateHasChanged);
}
async Task NextPage()
{
if (_currentPage >= _totalPages)
@@ -799,7 +797,12 @@
async Task SetZoom(int percentage)
{
_currentZoom = Math.Clamp(percentage, 50, 300);
await ApplyViewerStateAsync();
_viewerZoomLevel = _currentZoom / 100d;
await InvokeAsync(StateHasChanged);
await JSRuntime.InvokeVoidAsync("pdfViewer.setViewState", _currentPage, _currentZoom);
await Task.Delay(150);
await RenderSignatureButtonsAsync();
}
async Task OnZoomSliderChanged(ChangeEventArgs e)
@@ -824,8 +827,13 @@
async Task FitToWidth()
{
_viewerZoomLevel = -2;
_currentZoom = 150;
await ApplyViewerStateAsync();
await InvokeAsync(StateHasChanged);
await JSRuntime.InvokeVoidAsync("pdfViewer.setViewState", _currentPage, _currentZoom);
await Task.Delay(150);
await RenderSignatureButtonsAsync();
}
async Task ToggleThumbnails()
@@ -1191,6 +1199,11 @@
if (!_pdfLoaded)
return;
if (_viewerZoomLevel > 0)
{
_viewerZoomLevel = _currentZoom / 100d;
}
await InvokeAsync(StateHasChanged);
await JSRuntime.InvokeVoidAsync("pdfViewer.setViewState", _currentPage, _currentZoom);
await Task.Delay(150);

View File

@@ -78,28 +78,6 @@ window.pdfViewer = {
return;
}
if (!this.wheelHandler) {
this.wheelHandler = async (e) => {
if (!(e.ctrlKey || e.metaKey) || !this.dotNetReference) {
return;
}
e.preventDefault();
const step = this.qualityOptions.zoomStepPercentage;
const nextZoom = e.deltaY < 0
? Math.min(this.currentZoom + step, 300)
: Math.max(this.currentZoom - step, 50);
if (nextZoom !== this.currentZoom) {
this.currentZoom = nextZoom;
await this.dotNetReference.invokeMethodAsync('OnZoomGestureRequested', nextZoom);
}
};
host.addEventListener('wheel', this.wheelHandler, { passive: false });
}
if (!this.resizeObserver && typeof ResizeObserver !== 'undefined') {
this.resizeObserver = new ResizeObserver(() => this.requestOverlayRefresh());
this.resizeObserver.observe(host);