Add interactive signature buttons to PDF viewer

Introduced functionality to render interactive signature buttons on the PDF viewer. Added support for fetching and displaying signature data (`SignatureDto`) dynamically based on the current page.

- Added `@using` directives in `EnvelopeViewer.razor` for required namespaces.
- Introduced `_signatures` field to store signature data.
- Updated `OnInitializedAsync` to fetch and process signatures.
- Implemented `RenderSignatureButtonsAsync` to dynamically render buttons.
- Added `[JSInvokable]` method `OnSignatureButtonClick` for button events.
- Updated CSS to style `pdf-signature-layer` and `signature-button`.
- Enhanced `pdf-viewer.js` with methods to render and clear buttons.
- Ensured buttons respond to zoom and page navigation changes.
- Added error handling and logging for signature rendering.

These changes improve user interaction by enabling signing functionality directly on the PDF viewer.
This commit is contained in:
2026-06-07 12:43:36 +02:00
parent b888c85937
commit 2f73e4f6da
3 changed files with 205 additions and 2 deletions

View File

@@ -1,4 +1,6 @@
@page "/envelope/{EnvelopeKey}"
@using EnvelopeGenerator.ReceiverUI.Models
@using EnvelopeGenerator.ReceiverUI.Models.Constants
@using EnvelopeGenerator.ReceiverUI.Services
@using Microsoft.Extensions.Options
@using EnvelopeGenerator.ReceiverUI.Options
@@ -155,6 +157,7 @@
<div class="pdf-page-container">
<canvas id="pdf-canvas" class="pdf-canvas"></canvas>
<div id="pdf-text-layer" class="pdf-text-layer"></div>
<div id="pdf-signature-layer" class="pdf-signature-layer"></div>
</div>
</div>
</div>
@@ -186,6 +189,7 @@ int _totalPages = 0;
int _currentZoom = 150;
bool _showThumbnails = true;
DotNetObjectReference<EnvelopeViewer>? _dotNetRef;
IReadOnlyList<SignatureDto> _signatures = [];
// Resizable splitter state
int _thumbnailWidth = 260;
@@ -195,7 +199,7 @@ int _resizeStartWidth = 0;
const int MinThumbnailWidth = 150;
const int MaxThumbnailWidth = 400;
protected override async Task OnInitializedAsync() {
protected override async Task OnInitializedAsync() {
if (string.IsNullOrWhiteSpace(EnvelopeKey)) {
_errorMessage = "Envelope-Schlüssel fehlt.";
_isLoading = false;
@@ -213,8 +217,9 @@ protected override async Task OnInitializedAsync() {
}
var signatures = await SignatureService.GetAsync(EnvelopeKey);
_signatures = signatures.Convert(UnitOfLength.Point);
await JSRuntime.InvokeVoidAsync("console.log", signatures);
await JSRuntime.InvokeVoidAsync("console.log", "Loaded signatures:", _signatures);
} catch (Exception ex) {
_errorMessage = $"Fehler: {ex.Message}";
@@ -269,11 +274,15 @@ protected override async Task OnInitializedAsync() {
// Attach resize listeners
await JSRuntime.InvokeVoidAsync("pdfViewer.attachResizeListeners", _dotNetRef);
await InvokeAsync(StateHasChanged);
// Wait for DOM to be ready, then render thumbnails
await Task.Delay(100);
await RenderThumbnailsAsync();
// Render signature buttons
await RenderSignatureButtonsAsync();
}
} catch (Exception ex) {
_errorMessage = $"PDF.js Fehler: {ex.Message}";
@@ -287,17 +296,23 @@ protected override async Task OnInitializedAsync() {
{
_currentZoom = (int)(scale * 100);
await InvokeAsync(StateHasChanged);
// Re-render signature buttons when zoom changes
await Task.Delay(100);
await RenderSignatureButtonsAsync();
}
async Task NextPage() {
if (await JSRuntime.InvokeAsync<bool>("pdfViewer.nextPage")) {
_currentPage = await JSRuntime.InvokeAsync<int>("pdfViewer.getCurrentPage");
await RenderSignatureButtonsAsync();
}
}
async Task PreviousPage() {
if (await JSRuntime.InvokeAsync<bool>("pdfViewer.previousPage")) {
_currentPage = await JSRuntime.InvokeAsync<int>("pdfViewer.getCurrentPage");
await RenderSignatureButtonsAsync();
}
}
@@ -355,9 +370,25 @@ protected override async Task OnInitializedAsync() {
async Task GoToPageFromThumbnail(int pageNum) {
if (await JSRuntime.InvokeAsync<bool>("pdfViewer.goToPage", pageNum)) {
_currentPage = pageNum;
await RenderSignatureButtonsAsync();
}
}
async Task RenderSignatureButtonsAsync() {
if (_signatures.Count == 0 || !_pdfLoaded) return;
try {
await JSRuntime.InvokeVoidAsync("pdfViewer.renderSignatureButtons", _signatures, _currentPage, _dotNetRef);
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine($"Signature button rendering error: {ex.Message}");
}
}
[JSInvokable]
public void OnSignatureButtonClick(int signatureId) {
Console.WriteLine($"Signature #{signatureId} signed");
}
async Task RenderThumbnailsAsync() {
try {
var delay = PdfViewerOptions.Value.ThumbnailRenderDelay;