Introduced a signature input feature in `ReportViewer.razor` to allow users to draw a signature on a canvas and embed it into reports before exporting as a signed PDF. - Added a canvas (`receiver-signature-pad`) and buttons for clearing, applying, and exporting signatures. - Injected `IJSRuntime` for JavaScript interop and added methods for signature handling (`ClearSignatureAsync`, `ApplySignatureAsync`, `ExportSignedPdfAsync`). - Embedded the signature as an image and label in the report's bottom margin. - Added `receiver-signature.js` to manage the signature pad, including drawing, clearing, and exporting the signature as a Base64 image. - Updated `index.html` to include the new JavaScript file. - Displayed validation messages for missing or invalid signatures.
87 lines
2.6 KiB
JavaScript
87 lines
2.6 KiB
JavaScript
window.receiverSignature = (() => {
|
|
const pads = new Map();
|
|
|
|
function getPosition(canvas, event) {
|
|
const rect = canvas.getBoundingClientRect();
|
|
const source = event.touches && event.touches.length ? event.touches[0] : event;
|
|
return {
|
|
x: (source.clientX - rect.left) * (canvas.width / rect.width),
|
|
y: (source.clientY - rect.top) * (canvas.height / rect.height)
|
|
};
|
|
}
|
|
|
|
function initialize(canvasId) {
|
|
const canvas = document.getElementById(canvasId);
|
|
if (!canvas || pads.has(canvasId))
|
|
return;
|
|
|
|
const context = canvas.getContext('2d');
|
|
context.lineWidth = 2.5;
|
|
context.lineCap = 'round';
|
|
context.lineJoin = 'round';
|
|
context.strokeStyle = '#111';
|
|
|
|
const state = { drawing: false, hasSignature: false };
|
|
pads.set(canvasId, state);
|
|
|
|
const start = event => {
|
|
event.preventDefault();
|
|
const pos = getPosition(canvas, event);
|
|
state.drawing = true;
|
|
context.beginPath();
|
|
context.moveTo(pos.x, pos.y);
|
|
};
|
|
|
|
const move = event => {
|
|
if (!state.drawing)
|
|
return;
|
|
|
|
event.preventDefault();
|
|
const pos = getPosition(canvas, event);
|
|
context.lineTo(pos.x, pos.y);
|
|
context.stroke();
|
|
state.hasSignature = true;
|
|
};
|
|
|
|
const end = event => {
|
|
if (!state.drawing)
|
|
return;
|
|
|
|
event.preventDefault();
|
|
state.drawing = false;
|
|
};
|
|
|
|
canvas.addEventListener('mousedown', start);
|
|
canvas.addEventListener('mousemove', move);
|
|
window.addEventListener('mouseup', end);
|
|
canvas.addEventListener('touchstart', start, { passive: false });
|
|
canvas.addEventListener('touchmove', move, { passive: false });
|
|
canvas.addEventListener('touchend', end, { passive: false });
|
|
}
|
|
|
|
function clear(canvasId) {
|
|
const canvas = document.getElementById(canvasId);
|
|
const state = pads.get(canvasId);
|
|
if (!canvas || !state)
|
|
return;
|
|
|
|
canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
|
|
state.hasSignature = false;
|
|
}
|
|
|
|
function getDataUrl(canvasId) {
|
|
const canvas = document.getElementById(canvasId);
|
|
const state = pads.get(canvasId);
|
|
if (!canvas || !state || !state.hasSignature)
|
|
return null;
|
|
|
|
return canvas.toDataURL('image/png');
|
|
}
|
|
|
|
return {
|
|
initialize,
|
|
clear,
|
|
getDataUrl
|
|
};
|
|
})();
|