I'm trying to draw on a PDF, for that I'll use Konva to draw but I need to load the PDF as an image on the canvas.
import React, { useState, useRef, useEffect } from "react";
import { Stage, Layer, Image, Rect } from "react-konva";
import pdfjsWorker from "react-pdf/node_modules/pdfjs-dist/build/pdf.worker.entry";
import { pdfjs } from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const CustomPdfReader = ({ url, width, template }) => {
const [pages, setPages] = useState([]);
const [rectangles, setRectangles] = useState([]);
useEffect(() => {
pdfjs.getDocument(url).promise
.then((doc) => {
const numPages = doc.numPages;
const promises = [];
for (let i = 1; i <= numPages; i++) {
promises.push(
doc.getPage(i)
.then((page) => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const scale = width / page.getViewport({ scale: 1 }).width;
const viewport = page.getViewport({ scale });
canvas.width = viewport.width;
canvas.height = viewport.height;
return page.render({ canvasContext: context, viewport }).promise;
})
.catch((error) => {
console.error("Error in getting or rendering a page:", error);
})
);
}
Promise.all(promises)
.then((canvases) => {
setPages(canvases.map((canvas) => canvas.toDataURL()));
})
.catch((error) => {
console.log(promises);
console.error("Error in resolving all promises:", error);
})
.finally(() => {
console.log("All promises are settled");
});
})
.catch((error) => {
console.error("Error in loading the PDF document:", error);
});
}, [url, width]);
// handle mouse events to draw rectangles on the stage
const stageRef = useRef();
const handleMouseDown = (e) => {
// get the mouse position relative to the stage
const stage = e.target.getStage();
const point = stage.getPointerPosition();
// create a new rectangle with initial position and size
const newRect = {
x: point.x,
y: point.y,
width: 0,
height: 0,
fill: "green",
opacity: 0.4,
};
// add the new rectangle to the rectangles state
setRectangles([...rectangles, newRect]);
};
const handleMouseMove = (e) => {
// get the mouse position relative to the stage
const stage = e.target.getStage();
const point = stage.getPointerPosition();
// update the last rectangle in the rectangles state with the new size
setRectangles((rectangles) => {
const lastRect = rectangles[rectangles.length - 1];
if (lastRect) {
return [
...rectangles.slice(0, -1),
{
...lastRect,
width: point.x - lastRect.x,
height: point.y - lastRect.y,
},
];
} else {
return rectangles;
}
});
};
const handleMouseUp = (e) => {
console.log(template);
console.log(rectangles);
};
return (
<div>
<Stage
ref={stageRef}
width={width}
height={window.innerHeight}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
>
<Layer>
{pages.map((page, i) => (
<Image key={i} image={page} />
))}
{rectangles.map((rect, i) => (
<Rect key={i} {...rect} />
))}
</Layer>
</Stage>
</div>
);
};
export default CustomPdfReader;
My issue is that react-pdf (or pdfjs) struggles with rendering the pages of a PDF in order, I tried using a promise to sorts that out but my promises are "[[PromiseResult]]:undefined" and I got an error "bundle.js:311 Error in resolving all promises: TypeError: Cannot read properties of undefined (reading 'toDataURL')" I'm struggling with this one