'Draw rectangle in canvas with loaded pdf file using pdf.js
I am trying to draw rectangle over a pdf file. When I draw rectangle in pdf, rectangle not draw properly.
I want to draw only one rectangle at a time, when I draw new rectangle the old rectangle should be remove, but it is not happening.
Here is my code:
Rendering code of pdf (Rendering is working properly)
function pdfFile (file) {
pdfjsLib.workerSrc = 'pdf.worker.js';
pdfjsLib.getDocument(file).promise.then(function(pdfDoc) {
pdf = pdfDoc;
document.getElementById('page_count').textContent = pdfDoc.numPages;
showButtonGroup(pdf);
renderPage(pageNum);
});
}
function renderPage(num) {
pageRendering = true;
pdf.getPage(num).then(function(page) {
var viewport = page.getViewport({scale: scale});
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function() {
pageRendering = false;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
document.getElementById('page_num').textContent = num;
}
Mouse move function not working properly
function mouseMove(e) {
if (drag) {
ctx.putImageData(pdfPages[pageNum], 0, 0);
ctx.clearRect(rect.startX, rect.startY, rect.w, rect.h);
rect.w = ((e.pageX - x) - this.offsetLeft) - rect.startX;
rect.h = ((e.pageY - y) - this.offsetTop) - rect.startY;
ctx.strokeStyle = color;
ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);
Object.assign(data, {
x: rect.startX,
y: rect.startY,
w: rect.w,
h: rect.h
})
console.log(data);
}
}
Note
Solution 1:[1]
Please check the below, need to clear the existing rectangle before creating new
function renderPage(num) {
pageRendering = true;
pdf.getPage(num).then(function (page) {
var viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function () {
pageRendering = false;
//You need to clear the existing rectangle
pdfPages[num] = ctx.getImageData(0, 0, canvas.width, canvas.height);
//Now you can draw new rectangle
drawRectangle(10, 10, 100, 50);
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
function drawRectangle(x, y, w, h) {
ctx.strokeStyle = color;
ctx.strokeRect(x, y, w, h);
}
Solution 2:[2]
The other way to do selectable rectangles on canvas in react using pdf.js is by keeping original canvas saved using toDataURL() and then after clearRect use canvas.draw() to draw your canvas with the base64 image saved earlier.
import React, { useEffect, useState, useRef, useCallback } from "react";
import pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
import * as pdfjsLib from "pdfjs-dist/build/pdf";
export default function CustomPdfReader({ url }) {
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const canvasRef = useRef();
const [pdfRef, setPdfRef] = useState("");
const currentPage = 1;
const zoomScale = 1;
const rotateAngle = 0;
var pdf_image = "";
const renderPage = useCallback(
(pageNum, pdf = pdfRef) => {
pdf &&
pdf.getPage(pageNum).then(function (page) {
const viewport = page.getViewport({ scale: zoomScale, rotation: rotateAngle });
const canvas = canvasRef.current;
canvas.height = viewport?.height;
canvas.width = viewport?.width;
const renderContext = {
canvasContext: canvas?.getContext("2d"),
viewport: viewport,
textContent: pdfRef,
};
page.render(renderContext);
});
},
[pdfRef, url]
);
useEffect(() => {
if (url.slice(-4).toLowerCase() === ".pdf") {
renderPage(currentPage, pdfRef);
} else {
setPdfRef("");
}
}, [pdfRef, renderPage, url]);
useEffect(() => {
const loadingTask = pdfjsLib.getDocument(url);
loadingTask.promise.then(
(loadedPdf) => {
setPdfRef(loadedPdf);
},
function (reason) {
console.error(reason);
}
);
}, [url]);
var cursorInCanvas = false;
var canvasOfDoc = canvasRef?.current;
var ctx;
var startX;
var startY;
var offsetX;
var offsetY;
const saveInitialCanvas = () => {
if (canvasOfDoc?.getContext) {
var canvasPic = new Image();
canvasPic.src = canvasOfDoc.toDataURL();
pdf_image = canvasPic;
}
};
useEffect(() => {
if (canvasOfDoc) {
ctx = canvasOfDoc.getContext("2d");
var canvasOffset = canvasOfDoc.getBoundingClientRect();
offsetX = canvasOffset.left;
offsetY = canvasOffset.top;
}
}, [canvasOfDoc, pdfRef, renderPage, url]);
function handleMouseIn(e) {
if (typeof pdf_image == "string") {
saveInitialCanvas();
}
e.preventDefault();
e.stopPropagation();
startX = ((e.offsetX * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;
startY = ((e.offsetY * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;
cursorInCanvas = true;
}
function handleMouseOut(e) {
e.preventDefault();
e.stopPropagation();
cursorInCanvas = false;
}
function handleMouseMove(e) {
e.preventDefault();
e.stopPropagation();
if (!cursorInCanvas) {
return;
}
let mouseX = ((e.offsetX * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;
let mouseY = ((e.offsetY * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;
var width = mouseX - startX;
var height = mouseY - startY;
if (ctx) {
ctx?.clearRect(0, 0, canvasOfDoc.width, canvasOfDoc.height);
ctx?.drawImage(pdf_image, 0, 0);
ctx.beginPath();
ctx.rect(startX, startY, width, height);
ctx.strokeStyle = "#1B9AFF";
ctx.lineWidth = 1;
ctx.stroke();
}
}
canvasOfDoc?.addEventListener("mousedown", function (e) {
handleMouseIn(e);
});
canvasOfDoc?.addEventListener("mousemove", function (e) {
handleMouseMove(e);
});
canvasOfDoc?.addEventListener("mouseup", function (e) {
handleMouseOut(e);
});
canvasOfDoc?.addEventListener("mouseout", function (e) {
handleMouseOut(e);
});
return (
<>
<canvas id="pdf-doc" ref={canvasRef} />
</>
);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |


