2023-05-07 22:39:34 +02:00
|
|
|
const DraggableUtils = {
|
|
|
|
|
|
|
|
boxDragContainer: document.getElementById('box-drag-container'),
|
|
|
|
pdfCanvas: document.getElementById('pdf-canvas'),
|
|
|
|
nextId: 0,
|
|
|
|
pdfDoc: null,
|
|
|
|
pageIndex: 0,
|
2023-05-08 19:06:34 +02:00
|
|
|
documentsMap: new Map(),
|
2023-05-07 22:39:34 +02:00
|
|
|
|
|
|
|
init() {
|
|
|
|
interact('.draggable-canvas')
|
|
|
|
.draggable({
|
|
|
|
listeners: {
|
|
|
|
move: (event) => {
|
|
|
|
const target = event.target;
|
|
|
|
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
|
|
|
|
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
|
|
|
|
|
|
|
|
target.style.transform = `translate(${x}px, ${y}px)`;
|
|
|
|
target.setAttribute('data-x', x);
|
|
|
|
target.setAttribute('data-y', y);
|
|
|
|
|
|
|
|
this.onInteraction(target);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.resizable({
|
2023-06-08 21:25:55 +02:00
|
|
|
edges: { left: true, right: true, bottom: true, top: true },
|
|
|
|
listeners: {
|
|
|
|
move: (event) => {
|
|
|
|
var target = event.target
|
|
|
|
var x = (parseFloat(target.getAttribute('data-x')) || 0)
|
|
|
|
var y = (parseFloat(target.getAttribute('data-y')) || 0)
|
2023-05-07 22:39:34 +02:00
|
|
|
|
2023-06-08 21:25:55 +02:00
|
|
|
// check if control key is pressed
|
|
|
|
if (event.ctrlKey) {
|
|
|
|
const aspectRatio = target.offsetWidth / target.offsetHeight;
|
|
|
|
// preserve aspect ratio
|
|
|
|
let width = event.rect.width;
|
|
|
|
let height = event.rect.height;
|
2023-05-07 22:39:34 +02:00
|
|
|
|
2023-06-08 21:25:55 +02:00
|
|
|
if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) {
|
|
|
|
height = width / aspectRatio;
|
|
|
|
} else {
|
|
|
|
width = height * aspectRatio;
|
|
|
|
}
|
2023-05-07 22:39:34 +02:00
|
|
|
|
2023-06-08 21:25:55 +02:00
|
|
|
event.rect.width = width;
|
|
|
|
event.rect.height = height;
|
|
|
|
}
|
2023-05-07 22:39:34 +02:00
|
|
|
|
2023-06-08 21:25:55 +02:00
|
|
|
target.style.width = event.rect.width + 'px'
|
|
|
|
target.style.height = event.rect.height + 'px'
|
|
|
|
|
|
|
|
// translate when resizing from top or left edges
|
|
|
|
x += event.deltaRect.left
|
|
|
|
y += event.deltaRect.top
|
|
|
|
|
|
|
|
target.style.transform = 'translate(' + x + 'px,' + y + 'px)'
|
|
|
|
|
|
|
|
target.setAttribute('data-x', x)
|
|
|
|
target.setAttribute('data-y', y)
|
|
|
|
target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height)
|
|
|
|
|
|
|
|
this.onInteraction(target);
|
|
|
|
},
|
|
|
|
},
|
2023-05-07 22:39:34 +02:00
|
|
|
|
|
|
|
modifiers: [
|
|
|
|
interact.modifiers.restrictSize({
|
2023-06-08 21:25:55 +02:00
|
|
|
min: { width: 5, height: 5 },
|
2023-05-07 22:39:34 +02:00
|
|
|
}),
|
|
|
|
],
|
|
|
|
inertia: true,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
onInteraction(target) {
|
|
|
|
this.boxDragContainer.appendChild(target);
|
|
|
|
},
|
|
|
|
|
|
|
|
createDraggableCanvas() {
|
|
|
|
const createdCanvas = document.createElement('canvas');
|
|
|
|
createdCanvas.id = `draggable-canvas-${this.nextId++}`;
|
|
|
|
createdCanvas.classList.add("draggable-canvas");
|
|
|
|
|
|
|
|
const x = 0;
|
2023-05-08 03:23:45 +02:00
|
|
|
const y = 20;
|
2023-05-07 22:39:34 +02:00
|
|
|
createdCanvas.style.transform = `translate(${x}px, ${y}px)`;
|
|
|
|
createdCanvas.setAttribute('data-x', x);
|
|
|
|
createdCanvas.setAttribute('data-y', y);
|
|
|
|
|
|
|
|
createdCanvas.onclick = e => this.onInteraction(e.target);
|
|
|
|
|
|
|
|
this.boxDragContainer.appendChild(createdCanvas);
|
|
|
|
return createdCanvas;
|
|
|
|
},
|
|
|
|
createDraggableCanvasFromUrl(dataUrl) {
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
var myImage = new Image();
|
|
|
|
myImage.src = dataUrl;
|
|
|
|
myImage.onload = () => {
|
|
|
|
var createdCanvas = this.createDraggableCanvas();
|
|
|
|
|
|
|
|
createdCanvas.width = myImage.width;
|
|
|
|
createdCanvas.height = myImage.height;
|
|
|
|
|
|
|
|
const imgAspect = myImage.width / myImage.height;
|
|
|
|
const pdfAspect = this.boxDragContainer.offsetWidth / this.boxDragContainer.offsetHeight;
|
|
|
|
|
|
|
|
var scaleMultiplier;
|
|
|
|
if (imgAspect > pdfAspect) {
|
|
|
|
scaleMultiplier = this.boxDragContainer.offsetWidth / myImage.width;
|
|
|
|
} else {
|
|
|
|
scaleMultiplier = this.boxDragContainer.offsetHeight / myImage.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
var newWidth = createdCanvas.width;
|
|
|
|
var newHeight = createdCanvas.height;
|
|
|
|
if (scaleMultiplier < 1) {
|
|
|
|
newWidth = newWidth * scaleMultiplier;
|
|
|
|
newHeight = newHeight * scaleMultiplier;
|
|
|
|
}
|
|
|
|
|
|
|
|
createdCanvas.style.width = newWidth+"px";
|
|
|
|
createdCanvas.style.height = newHeight+"px";
|
|
|
|
|
|
|
|
var myContext = createdCanvas.getContext("2d");
|
|
|
|
myContext.drawImage(myImage,0,0);
|
|
|
|
resolve(createdCanvas);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
2023-05-08 19:06:34 +02:00
|
|
|
deleteAllDraggableCanvases() {
|
|
|
|
this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach(el => el.remove());
|
|
|
|
},
|
2023-05-07 22:39:34 +02:00
|
|
|
deleteDraggableCanvas(element) {
|
2023-05-08 11:36:39 +02:00
|
|
|
if (element) {
|
|
|
|
element.remove();
|
|
|
|
}
|
2023-05-07 22:39:34 +02:00
|
|
|
},
|
|
|
|
getLastInteracted() {
|
|
|
|
return this.boxDragContainer.querySelector(".draggable-canvas:last-of-type");
|
|
|
|
},
|
|
|
|
|
2023-05-08 19:06:34 +02:00
|
|
|
storePageContents() {
|
|
|
|
var pagesMap = this.documentsMap.get(this.pdfDoc);
|
|
|
|
if (!pagesMap) {
|
|
|
|
pagesMap = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")];
|
|
|
|
const draggablesData = elements.map(el => {return{element:el, offsetWidth:el.offsetWidth, offsetHeight:el.offsetHeight}});
|
|
|
|
elements.forEach(el => this.boxDragContainer.removeChild(el));
|
|
|
|
|
|
|
|
pagesMap[this.pageIndex] = draggablesData;
|
|
|
|
pagesMap[this.pageIndex+"-offsetWidth"] = this.pdfCanvas.offsetWidth;
|
|
|
|
pagesMap[this.pageIndex+"-offsetHeight"] = this.pdfCanvas.offsetHeight;
|
|
|
|
|
|
|
|
this.documentsMap.set(this.pdfDoc, pagesMap);
|
|
|
|
},
|
|
|
|
loadPageContents() {
|
|
|
|
var pagesMap = this.documentsMap.get(this.pdfDoc);
|
|
|
|
this.deleteAllDraggableCanvases();
|
|
|
|
if (!pagesMap) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const draggablesData = pagesMap[this.pageIndex];
|
|
|
|
if (draggablesData) {
|
|
|
|
draggablesData.forEach(draggableData => this.boxDragContainer.appendChild(draggableData.element));
|
|
|
|
}
|
|
|
|
|
|
|
|
this.documentsMap.set(this.pdfDoc, pagesMap);
|
|
|
|
},
|
|
|
|
|
2023-05-07 22:39:34 +02:00
|
|
|
async renderPage(pdfDocument, pageIdx) {
|
|
|
|
this.pdfDoc = pdfDocument ? pdfDocument : this.pdfDoc;
|
|
|
|
this.pageIndex = pageIdx;
|
2023-05-08 19:06:34 +02:00
|
|
|
|
|
|
|
// persist
|
2023-05-07 22:39:34 +02:00
|
|
|
const page = await this.pdfDoc.getPage(this.pageIndex+1);
|
|
|
|
|
|
|
|
// set the canvas size to the size of the page
|
|
|
|
if (page.rotate == 90 || page.rotate == 270) {
|
|
|
|
this.pdfCanvas.width = page.view[3];
|
|
|
|
this.pdfCanvas.height = page.view[2];
|
|
|
|
} else {
|
|
|
|
this.pdfCanvas.width = page.view[2];
|
|
|
|
this.pdfCanvas.height = page.view[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
// render the page onto the canvas
|
|
|
|
var renderContext = {
|
|
|
|
canvasContext: this.pdfCanvas.getContext("2d"),
|
|
|
|
viewport: page.getViewport({ scale: 1 })
|
|
|
|
};
|
|
|
|
await page.render(renderContext).promise;
|
|
|
|
|
|
|
|
//return pdfCanvas.toDataURL();
|
|
|
|
},
|
|
|
|
async incrementPage() {
|
|
|
|
if (this.pageIndex < this.pdfDoc.numPages-1) {
|
2023-05-08 19:06:34 +02:00
|
|
|
this.storePageContents();
|
|
|
|
await this.renderPage(this.pdfDoc, this.pageIndex+1);
|
|
|
|
this.loadPageContents();
|
2023-05-07 22:39:34 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
async decrementPage() {
|
|
|
|
if (this.pageIndex > 0) {
|
2023-05-08 19:06:34 +02:00
|
|
|
this.storePageContents();
|
|
|
|
await this.renderPage(this.pdfDoc, this.pageIndex-1);
|
|
|
|
this.loadPageContents();
|
2023-05-07 22:39:34 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
parseTransform(element) {
|
2023-05-08 19:06:34 +02:00
|
|
|
|
2023-05-07 22:39:34 +02:00
|
|
|
},
|
|
|
|
async getOverlayedPdfDocument() {
|
|
|
|
const pdfBytes = await this.pdfDoc.getData();
|
2023-06-21 00:49:53 +02:00
|
|
|
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { ignoreEncryption: true });
|
2023-05-08 19:06:34 +02:00
|
|
|
this.storePageContents();
|
2023-05-07 22:39:34 +02:00
|
|
|
|
2023-05-08 19:06:34 +02:00
|
|
|
const pagesMap = this.documentsMap.get(this.pdfDoc);
|
|
|
|
for (let pageIdx in pagesMap) {
|
|
|
|
if (pageIdx.includes("offset")) {
|
|
|
|
continue;
|
2023-05-07 22:39:34 +02:00
|
|
|
}
|
2023-05-08 19:06:34 +02:00
|
|
|
console.log(typeof pageIdx);
|
|
|
|
|
|
|
|
const page = pdfDocModified.getPage(parseInt(pageIdx));
|
|
|
|
const draggablesData = pagesMap[pageIdx];
|
|
|
|
const offsetWidth = pagesMap[pageIdx+"-offsetWidth"];
|
|
|
|
const offsetHeight = pagesMap[pageIdx+"-offsetHeight"];
|
2023-05-07 22:39:34 +02:00
|
|
|
|
2023-05-08 19:06:34 +02:00
|
|
|
for (const draggableData of draggablesData) {
|
|
|
|
// embed the draggable canvas
|
|
|
|
const draggableElement = draggableData.element;
|
|
|
|
const response = await fetch(draggableElement.toDataURL());
|
|
|
|
const draggableImgBytes = await response.arrayBuffer();
|
|
|
|
const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes);
|
|
|
|
|
|
|
|
// calculate the position in the pdf document
|
|
|
|
const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, '');
|
|
|
|
const transformComponents = tansform.split(",");
|
|
|
|
const draggablePositionPixels = {
|
|
|
|
x: parseFloat(transformComponents[0]),
|
|
|
|
y: parseFloat(transformComponents[1]),
|
|
|
|
width: draggableData.offsetWidth,
|
|
|
|
height: draggableData.offsetHeight,
|
|
|
|
};
|
|
|
|
const draggablePositionRelative = {
|
|
|
|
x: draggablePositionPixels.x / offsetWidth,
|
|
|
|
y: draggablePositionPixels.y / offsetHeight,
|
|
|
|
width: draggablePositionPixels.width / offsetWidth,
|
|
|
|
height: draggablePositionPixels.height / offsetHeight,
|
|
|
|
}
|
|
|
|
const draggablePositionPdf = {
|
|
|
|
x: draggablePositionRelative.x * page.getWidth(),
|
|
|
|
y: draggablePositionRelative.y * page.getHeight(),
|
|
|
|
width: draggablePositionRelative.width * page.getWidth(),
|
|
|
|
height: draggablePositionRelative.height * page.getHeight(),
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw the image
|
|
|
|
page.drawImage(pdfImageObject, {
|
|
|
|
x: draggablePositionPdf.x,
|
|
|
|
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
|
|
|
|
width: draggablePositionPdf.width,
|
|
|
|
height: draggablePositionPdf.height,
|
|
|
|
});
|
|
|
|
}
|
2023-05-07 22:39:34 +02:00
|
|
|
}
|
|
|
|
|
2023-05-08 19:06:34 +02:00
|
|
|
this.loadPageContents();
|
2023-05-07 22:39:34 +02:00
|
|
|
return pdfDocModified;
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
|
|
DraggableUtils.init();
|
|
|
|
});
|