I am using fabric.js in react application . The scenario i was trying is i want to export the Entire canvas as image but below are the issues im getting
- Canvas is resetting after pressing export button.
- After zoomed or panned the i am unable to export the content which is outside viewport . I am able to export only which is viewable on screen .But i need to export entire object which are placed on the canvas irrespective of zoomed and pan .
below is my code
import React, { useEffect, useRef, useState } from 'react';
import { fabric } from 'fabric';
function CanvasComponent() {
const canvasRef = useRef(null);
const [fabricCanvas, setFabricCanvas] = useState(null);
const [zoom, setZoom] = useState(1);
useEffect(() => {
const initCanvas = new fabric.Canvas(canvasRef.current);
setFabricCanvas(initCanvas);
// Set initial canvas size based on window
const updateCanvasSize = () => {
if (initCanvas) {
const width = window.innerWidth;
const height = window.innerHeight;
initCanvas.setWidth(width);
initCanvas.setHeight(height);
initCanvas.renderAll();
}
};
updateCanvasSize();
// Add random objects
const rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 60,
height: 70
});
const circle = new fabric.Circle({
left: 200,
top: 200,
fill: 'green',
radius: 50
});
initCanvas.add(rect, circle);
// Add event listener for window resize
window.addEventListener('resize', updateCanvasSize);
// Clean up the event listener on component unmount
return () => {
window.removeEventListener('resize', updateCanvasSize);
};
}, []);
useEffect(() => {
if (fabricCanvas) {
fabricCanvas.setZoom(zoom);
fabricCanvas.renderAll();
}
}, [zoom, fabricCanvas]);
const handleExport = () => {
if (fabricCanvas) {
// Store the current content of the canvas
const originalData = fabricCanvas.toDataURL();
// Fill the canvas with a white background
const ctx = fabricCanvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, fabricCanvas.width, fabricCanvas.height);
// Draw the original content on top of the white background
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0);
// Now export the canvas with the white background
const dataURL = fabricCanvas.toDataURL('image/png');
const link = document.createElement('a');
link.href = dataURL;
let file_name = (Math.random() + 1).toString(36).substring(7);
link.download = `canvas_export_${file_name}.png`;
link.click();
// Restore the original content of the canvas
fabricCanvas.clear();
fabricCanvas.setBackgroundImage(originalData, fabricCanvas.renderAll.bind(fabricCanvas), {
originX: 'left',
originY: 'top'
});
};
img.src = originalData;
}
};
return (
<div>
<input
type="range"
min="0.1"
max="2"
step="0.1"
value={zoom}
onChange={(e) => setZoom(parseFloat(e.target.value))}
/>
<button onClick={handleExport}>Export Canvas</button>
<canvas ref={canvasRef}></canvas>
</div>
);
}
export default CanvasComponent;
2
Answers
I solved the presented issues by updating handleExport function and adding useEffect to update the dimensions of the Canvas based on zooming value.
First, it selects the canvas element using
document.getElementsByTagName('canvas'
).The getElementsByTagName function returns a collection of elements with the given tag name, so using [0] at the end ensures we target the first canvas element.
The
toDataURL()
method is then called on the canvas to convert it into a data URL string representing the image.Next, we create a new window using window.open(‘about:blank’) and assign it to the w variable. This new window will be used to display the image.
A new Image object is created and assigned to the image variable.
The src property of the Image object is set to the canvas data URL obtained earlier.
We use setTimeout to delay the execution of the next step by 0 milliseconds. This ensures that the image has finished loading before attempting to write it to the new window.
Finally, within the setTimeout function, we write the HTML representation of the image (image.outerHTML) to the document of the new window
(w.document.write(...)).
This causes the image to display in the new window once it has finished loading.By following this approach, you can export a canvas element as an image in JavaScript.
Example:
it will open new tab where you can see canvas as an image
to simply download you can use anchor tag as you used.