I want to download a chart created with recharts
as a png image. I made it work if I write on the DOM. I would like to download the image instead. This is what I have so far thanks to this post:
I have a clickable element to download the png and a chart in a component:
return (
<div>
<h1
onClick={() => this.handleDownload()}
>
Download chart
</h1>
<LineChart
ref={(chart) => this.currentChart = chart}
width={500}
height={300}
data={data}
margin={{
top: 5, right: 30, left: 20, bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{ r: 8 }} />
<Line type="monotone" dataKey="uv" stroke="#82ca9d" />
</LineChart>
</div>
)
Whenever I click, I generate a canvas. Once I have an image thanks to the canvas, I could just write it in the DOM:
svgToPng = (svg, width, height) => {
return new Promise((resolve, reject) => {
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d');
// Set background to white
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, width, height);
let xml = new XMLSerializer().serializeToString(svg);
let dataUrl = 'data:image/svg+xml;utf8,' + encodeURIComponent(xml);
let img = new Image(width, height);
img.onload = () => {
ctx.drawImage(img, 0, 0);
let imageData = canvas.toDataURL('image/png', 1.0);
resolve(imageData)
}
img.onerror = () => reject();
img.src = dataUrl;
});
};
handleDownload = async () => {
const chart = this.currentChart
let chartSVG = ReactDOM.findDOMNode(chart).children[0]
const pngData = await this.svgToPng(chartSVG, 400, 500)
document.write('<img src="'+pngData+'"/>') // <------
}
I would like to download the image instead of appending it to the DOM.
I tried this approach:
to download the image you can place it in an <a> tag using download attribute (html5) : <a href="javascript:canvas.toDataURL('image/jpeg');" download="download" >Download as jpeg</a>
I placed an the a tag in the DOM:
<a href={aTag} download="download" >Download as jpeg</a>
where aTag is
:
const aTag = `'javascript:${this.state.imageData}.toDataURL('image/jpeg');'`
Basically, in my component I set a state with the canvas object:
class DownloadChart extends React.Component {
state = {
imageData: ''
}
async componentDidMount() {
await this.handleDownload()
}
I got rid of the document.write
instruction, so I just generate the canvas object, and append it to the href
attribute, whenever the component is mounted
<a href={aTag} download="download" >Download as png</a>
Any suggestions on how to achieve the download of a png image? I couldn't make it work with none of the two approaches.