2024-07-18 17:16:19 +02:00

203 lines
5.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<button :disabled="!userSignatureZones" @click="confirm_sign">
Confirmer la signature
</button>
<button :disabled="!userSignatureZones" @click="undo_sign">
Supprimer la signature
</button>
</div>
<div v-if="pageCount > 1">
<button :disabled="page <= 1" @click="turn_page(-1)"></button>
{{ page }} / {{ pageCount }}
<button :disabled="page >= pageCount" @click="turn_page(1)"></button>
</div>
<canvas id="canvas"></canvas>
</template>
<script setup lang="ts">
import { ref, Ref } from "vue";
import { Signature, SignatureZone } from "../../types";
import * as pdfjsLib from "pdfjs-dist";
import {
PDFDocumentProxy,
PDFPageProxy,
} from "pdfjs-dist/types/src/display/api";
// @ts-ignore
import * as PdfWorker from "pdfjs-dist/build/pdf.worker.mjs";
console.log(PdfWorker); // incredible but this is needed
// import { PdfWorker } from 'pdfjs-dist/build/pdf.worker.mjs'
// pdfjsLib.GlobalWorkerOptions.workerSrc = PdfWorker;
import {
build_download_info_link,
download_and_decrypt_doc,
} from "../StoredObjectButton/helpers";
pdfjsLib.GlobalWorkerOptions.workerSrc = "pdfjs-dist/build/pdf.worker.mjs";
const page: Ref<number> = ref(1);
const pageCount: Ref<number> = ref(0);
let userSignatureZones: Ref<null | SignatureZone> = ref(null);
let pdfSource: Ref<string> = ref("");
let pdf = {} as PDFDocumentProxy;
declare global {
interface Window {
signature: Signature;
}
}
const signature = window.signature;
const urlInfo = build_download_info_link(signature.storedObject.filename);
const mount_pdf = async (url: string) => {
const loadingTask = pdfjsLib.getDocument(url);
pdf = await loadingTask.promise;
pageCount.value = pdf.numPages;
await set_page(1);
};
const get_render_context = (pdfPage: PDFPageProxy) => {
const scale = 1;
const viewport = pdfPage.getViewport({ scale });
const canvas = document.querySelectorAll("canvas")[0] as HTMLCanvasElement;
const context = canvas.getContext("2d") as CanvasRenderingContext2D;
canvas.height = viewport.height;
canvas.width = viewport.width;
return {
canvasContext: context,
viewport: viewport,
};
};
const set_page = async (page: number) => {
const pdfPage = await pdf.getPage(page);
const renderContext = get_render_context(pdfPage);
await pdfPage.render(renderContext);
};
async function download_and_open(): Promise<Blob> {
let raw;
try {
raw = await download_and_decrypt_doc(
urlInfo,
signature.storedObject.keyInfos,
new Uint8Array(signature.storedObject.iv)
);
} catch (e) {
console.error("error while downloading and decrypting document", e);
throw e;
}
await mount_pdf(URL.createObjectURL(raw));
init_pdf();
return raw;
}
const init_pdf = () => {
const canvas = document.querySelectorAll("canvas")[0] as HTMLCanvasElement;
canvas.addEventListener(
"pointerup",
(e: PointerEvent) => canvas_click(e, canvas),
false
);
setTimeout(() => add_zones(page.value), 800);
};
const hit_signature = (
zone: SignatureZone,
xy: number[],
canvasWidth: number,
canvasHeight: number
) => {
const scaleXToCanvas = (x: number) => (x * canvasWidth) / zone.pageWidth;
const scaleYToCanvas = (y: number) => (y * canvasHeight) / zone.pageHeight;
return (
scaleXToCanvas(zone.x) < xy[0] &&
xy[0] < scaleXToCanvas(zone.x + zone.width) &&
scaleYToCanvas(zone.y) < xy[1] &&
xy[1] < scaleYToCanvas(zone.y + zone.height)
);
};
const canvas_click = (e: PointerEvent, canvas: HTMLCanvasElement) =>
signature.zones
.filter((z) => z.page === page.value)
.map((z) => {
if (
hit_signature(z, [e.offsetX, e.offsetY], canvas.width, canvas.height)
) {
const ctx = canvas.getContext("2d");
if (ctx) {
draw_zone(z, ctx, canvas.width, canvas.height, true);
}
userSignatureZones.value = z;
}
});
const turn_page = async (upOrDown: number) => {
userSignatureZones.value = null;
page.value = page.value + upOrDown;
await set_page(page.value);
setTimeout(() => add_zones(page.value), 200);
};
const draw_zone = (
zone: SignatureZone,
ctx: CanvasRenderingContext2D,
canvasWidth: number,
canvasHeight: number,
selected = false,
) => {
const scaleXToCanvas = (x: number) =>
Math.round((x * canvasWidth) / zone.pageWidth);
const scaleYToCanvas = (y: number) =>
Math.round((y * canvasHeight) / zone.pageHeight);
ctx.strokeStyle = selected ? "orange " : "yellow";
ctx.lineWidth = 10;
ctx.lineJoin = "bevel";
ctx.strokeRect(
scaleXToCanvas(zone.x),
scaleYToCanvas(zone.y),
scaleXToCanvas(zone.width),
scaleYToCanvas(zone.height)
);
};
const add_zones = (page: number) => {
const canvas = document.querySelectorAll("canvas")[0];
const ctx = canvas.getContext("2d");
if (ctx) {
signature.zones
.filter((z) => z.page === page)
.map((z) => draw_zone(z, ctx, canvas.width, canvas.height));
}
};
const confirm_sign = () => {
console.log(userSignatureZones.value);
//TODO POST userSignatureZones to backend
};
const undo_sign = async () => {
const canvas = document.querySelectorAll("canvas")[0];
const ctx = canvas.getContext("2d");
if (ctx && userSignatureZones.value) {
draw_zone(userSignatureZones.value, ctx, canvas.width, canvas.height);
//another option is to reload the canvas
//await set_page(page.value);
//setTimeout(() => add_zones(page.value), 200);
}
userSignatureZones.value = null;
};
download_and_open();
</script>
<style lang="scss">
</style>