So I'm trying to document print multiple fabric images. Here is the preparation process. I see a blank window. I can provide additional information on request. Some sort of async logic I'm missing out maybe ?
1- I initialize a canvas from each canvas object (looping over an array of canvases - each canvas object has an image and possibly multiple textbox objects)
2- I then use toDataURL() and create image element for each, attach the src to img
3- I loop over the images and append them to printWindow.
const handleCustomPrint = () => {
const div = document.querySelector('.print-content');
for (let i = 0; i < canvasArrayToBePrinted.length; i++) {
const canvas = new fabric.Canvas(`${i}`)
canvas.loadFromJSON(canvasArrayToBePrinted[i], () => {
const img = canvas.toDataURL({
format: 'jpeg',
quality: 0.75
});
const singleImg = `<img src=${img} class='image-content' />`
div.innerHTML += singleImg;
});
}
console.log(div);
var windowUrl = 'about:blank';
var uniqueName = new Date();
var windowName = 'Print' + uniqueName.getTime();
var printWindow = window.open(windowUrl, windowName, 'left=50000,top=50000,width=1000000,height=10000');
printWindow.document.write(div.innerHTML);
printWindow.document.close();
printWindow.onload = function() {
printWindow.focus();
printWindow.print();
printWindow.close();
}
return true;
};
EDIT: OK. I think I'm getting close. But still can't see nothing.
This is the output of console.log(div)
<div class="print-content">
<img src="data:image/jpeg;base64,/9j/4AAQSkZJ..." class="img-content"/>
<img src="data:image/jpeg;base64,/9j/4AAQSkZJ..." class="img-content"/>
</div>
This is the CSS for targeting print styles
@media all {
.img-content {
display: none !important;
}
.print-content {
display: none !important;
}
}
@media print {
.print-content {
display: block !important;
}
.img-print {
display: block !important;
}
}
Preparing canvases (loadFromJSON callback is the indicator that indicates whether the canvas is initialized with all its objects (images/textboxes) attached to it... )
const PrintContent = React.forwardRef((props, ref) => {
const { canvasData, setIsPrintReady, shouldExcludeImage } = props;
const [preparedCanvases, setPreparedCanvases] = React.useState({ prepared: 0, total: canvasData.length });
const incrementPrepared = () => setPreparedCanvases(prev => ({ ...prev, prepared: prev.prepared + 1 }));
const imageToBePrinted = canvasData && canvasData.length && canvasData[0].objects.find(o => o.type === 'image');
const { width, height } = imageToBePrinted;
React.useEffect(() => {
if (preparedCanvases.prepared === preparedCanvases.total) {
setIsPrintReady(true);
}
}, [preparedCanvases, setIsPrintReady])
return (
<div className="content-to-be-printed" ref={ref}>
{
props.canvasData && props.canvasData.length && props.canvasData.map((singleCanvas, idx) => {
return <SingleCanvasData
key={`${idx}--canvas`}
singleCanvas={singleCanvas}
index={idx}
incrementPrepared={incrementPrepared}
imgWidth={width}
imgHeight={height}
shouldExcludeImage={shouldExcludeImage}
/>
})
}
</div>
)
});
const SingleCanvasData = ({ singleCanvas, index, incrementPrepared, imgWidth, imgHeight, shouldExcludeImage }) => {
const [canvas, setCanvas] = React.useState("");
const [once, setOnce] = React.useState(true);
React.useEffect(() => {
const initCanvas = () =>
new fabric.Canvas(`${index}`, {
height: imgHeight,
width: imgWidth,
preserveObjectStacking: true
});
setCanvas(initCanvas());
}, [index, imgHeight, imgWidth]);
React.useEffect(() => {
if (once && canvas) {
let canvasWithoutImage;
if(!shouldExcludeImage) {
canvasWithoutImage = {...singleCanvas, objects: singleCanvas.objects.filter(o => o.type !== 'image')};
}
canvas.loadFromJSON(canvasWithoutImage || singleCanvas, () => {
incrementPrepared();
});
setOnce(false);
}
}, [canvas, incrementPrepared, once, singleCanvas, shouldExcludeImage]);
return (
<canvas
style={{ width: 'auto', height: 'auto' }}
className="single-canvas"
id={index}
key={`canvas-${index}`}>
</canvas>
)
}
export default PrintContent
Parent
{
canPrint && (
<PrintContent
canvasData={canvasArrayToBePrinted}
setIsPrintReady={setIsPrintReady}
ref={componentRef}
shouldExcludeImage={shouldExcludeImage} />
)
}
useReactToPrint hook (attach ref to the component you want to print (in my case its forwardRef because I'm passing ref down to a component) - you can also declare print styles via props - super nifty) that allows you to print a react component (react-to-print)
const handlePrint = useReactToPrint({
pageStyle: `
@page { size: ${pageSize.widthPX}px ${pageSize.heightPX}px; margin: 0mm; }
`,
content: () => componentRef.current,
onAfterPrint: () => handleResetPrintModal()
});
Enable print button when print is ready
<button disabled={!isPrintReady || !pageSize.widthPX}
onClick={handlePrint}
className='btn-primary btn-success'>
Print
</button>