Refactor PDF editor styles and add throttling logic
Refactored `SenderPdfImageEditor.razor` to use culture-invariant formatting for dynamic styles and introduced the `GetPageCanvasStyle` method for calculating `aspect-ratio` and `cursor` styles. Enhanced layout control with additional CSS properties. Updated `envelope-editor.js` to include a throttling mechanism for mouse movement events using `_moveThrottle` and `requestAnimationFrame`. Added `getClickCoordsOnPdfPageThrottled` with a promise-based approach to improve performance during rapid interactions.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
@using EnvelopeGenerator.Application.Resources
|
@using EnvelopeGenerator.Application.Resources
|
||||||
@using EnvelopeGenerator.Application.Common.Dto
|
@using EnvelopeGenerator.Application.Common.Dto
|
||||||
|
@using System.Globalization
|
||||||
@using Microsoft.Extensions.Localization
|
@using Microsoft.Extensions.Localization
|
||||||
@inject IStringLocalizer<Resource> UiLocalizer
|
@inject IStringLocalizer<Resource> UiLocalizer
|
||||||
@inject IJSRuntime JSRuntime
|
@inject IJSRuntime JSRuntime
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
data-page-height-pt="@heightPt">
|
data-page-height-pt="@heightPt">
|
||||||
<div class="sender-image-editor__page-canvas"
|
<div class="sender-image-editor__page-canvas"
|
||||||
data-editor-page-canvas="@pageNumber"
|
data-editor-page-canvas="@pageNumber"
|
||||||
style="@( _isDragging ? "cursor:grabbing;" : string.Empty)">
|
style="@GetPageCanvasStyle(widthPt, heightPt)">
|
||||||
@if (!string.IsNullOrWhiteSpace(pagePreview?.ImageDataUrl))
|
@if (!string.IsNullOrWhiteSpace(pagePreview?.ImageDataUrl))
|
||||||
{
|
{
|
||||||
<img class="sender-image-editor__page-image"
|
<img class="sender-image-editor__page-image"
|
||||||
@@ -117,15 +118,40 @@
|
|||||||
var widthPercent = (127.44 / pageWidthPt) * 100.0;
|
var widthPercent = (127.44 / pageWidthPt) * 100.0;
|
||||||
var heightPercent = (141.12 / pageHeightPt) * 100.0;
|
var heightPercent = (141.12 / pageHeightPt) * 100.0;
|
||||||
|
|
||||||
|
var left = leftPercent.ToString("F4", CultureInfo.InvariantCulture);
|
||||||
|
var top = topPercent.ToString("F4", CultureInfo.InvariantCulture);
|
||||||
|
var width = widthPercent.ToString("F4", CultureInfo.InvariantCulture);
|
||||||
|
var height = heightPercent.ToString("F4", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
return string.Join(' ',
|
return string.Join(' ',
|
||||||
$"left:{leftPercent:F4}%;",
|
"position:absolute;",
|
||||||
$"top:{topPercent:F4}%;",
|
$"left:{left}%;",
|
||||||
$"width:{widthPercent:F4}%;",
|
$"top:{top}%;",
|
||||||
$"height:{heightPercent:F4}%;",
|
$"width:{width}%;",
|
||||||
|
$"height:{height}%;",
|
||||||
|
"border:2px solid;",
|
||||||
|
"border-radius:8px;",
|
||||||
|
"display:flex;",
|
||||||
|
"align-items:flex-start;",
|
||||||
|
"justify-content:space-between;",
|
||||||
|
"gap:0.35rem;",
|
||||||
|
"padding:0.2rem 0.3rem;",
|
||||||
|
"overflow:hidden;",
|
||||||
|
"z-index:30;",
|
||||||
$"border-color:{field.Color};",
|
$"border-color:{field.Color};",
|
||||||
$"background-color:{field.Color}22;");
|
$"background-color:{field.Color}22;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetPageCanvasStyle(double pageWidthPt, double pageHeightPt)
|
||||||
|
{
|
||||||
|
var ratio = pageHeightPt <= 0 ? 595.0 / 842.0 : pageWidthPt / pageHeightPt;
|
||||||
|
var ratioText = ratio.ToString("F6", CultureInfo.InvariantCulture);
|
||||||
|
var cursor = _isDragging
|
||||||
|
? "grabbing"
|
||||||
|
: (IsPlacementMode ? "crosshair" : "default");
|
||||||
|
return $"aspect-ratio:{ratioText};cursor:{cursor};";
|
||||||
|
}
|
||||||
|
|
||||||
private async Task HandleClickAsync(MouseEventArgs args)
|
private async Task HandleClickAsync(MouseEventArgs args)
|
||||||
{
|
{
|
||||||
if (EditorClick.HasDelegate)
|
if (EditorClick.HasDelegate)
|
||||||
@@ -182,7 +208,7 @@
|
|||||||
await MoveField.InvokeAsync(new SenderPdfFieldMoveRequest(_draggedFieldIndex.Value, pageNumber, xPt, yPt));
|
await MoveField.InvokeAsync(new SenderPdfFieldMoveRequest(_draggedFieldIndex.Value, pageNumber, xPt, yPt));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEditorMouseUp(MouseEventArgs _)
|
private void OnEditorMouseUp(MouseEventArgs args)
|
||||||
{
|
{
|
||||||
_draggedFieldIndex = null;
|
_draggedFieldIndex = null;
|
||||||
_isDragging = false;
|
_isDragging = false;
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
window.envelopeEditor = {
|
window.envelopeEditor = {
|
||||||
|
|
||||||
|
_moveThrottle: {
|
||||||
|
rafId: 0,
|
||||||
|
latest: null,
|
||||||
|
waiters: []
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the click position normalised to [0,1] relative to the rendered PDF page
|
* Returns the click position normalised to [0,1] relative to the rendered PDF page
|
||||||
* element inside DxPdfViewer (or DxReportViewer as fallback).
|
* element inside DxPdfViewer (or DxReportViewer as fallback).
|
||||||
@@ -93,5 +99,33 @@ window.envelopeEditor = {
|
|||||||
pageIndex: targetIndex,
|
pageIndex: targetIndex,
|
||||||
pageNumber: parseInt(targetPage.getAttribute('data-editor-page') || String(targetIndex + 1), 10)
|
pageNumber: parseInt(targetPage.getAttribute('data-editor-page') || String(targetIndex + 1), 10)
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
getClickCoordsOnPdfPageThrottled: function (viewerCssClass, clientX, clientY) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const state = window.envelopeEditor._moveThrottle;
|
||||||
|
state.latest = { viewerCssClass, clientX, clientY };
|
||||||
|
state.waiters.push(resolve);
|
||||||
|
|
||||||
|
if (state.rafId !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.rafId = window.requestAnimationFrame(() => {
|
||||||
|
state.rafId = 0;
|
||||||
|
|
||||||
|
const args = state.latest;
|
||||||
|
state.latest = null;
|
||||||
|
|
||||||
|
const result = args
|
||||||
|
? window.envelopeEditor.getClickCoordsOnPdfPage(args.viewerCssClass, args.clientX, args.clientY)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const waiters = state.waiters.splice(0, state.waiters.length);
|
||||||
|
for (const waiter of waiters) {
|
||||||
|
waiter(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user