I'm writing a bookmarklet that is supposed to take a screenshot of an SVG chart and save it as a PNG image. I'm testing this with the latest Chrome browser.
Here is the URL of the page containing the chart: https://data.oecd.org/gdp/real-gdp-forecast.htm The chart I want to capture and save as PNG is the large one in the top half of the page. It can be identified by the CSS class ddp-chart-inner
.
The code in the bookmarklet is here: https://pastebin.com/raw/cduvdC6e (pastebin because GitHub sets some CSP header that doesn't allow the code to be injected into another website).
(function() {
// this library is used for the download of the generated image
var fileSaverUrl = 'https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.2/FileSaver.min.js';
var d = document, b = d.body, fs = d.createElement('script');
fs.setAttribute('src', fileSaverUrl);
fs.onload = function() {
console.log('FileSaver loaded.');
var canvas = d.createElement("canvas");
canvas.height = '400';
canvas.width = '700';
b.appendChild(canvas);
var image = d.createElement("div");
image.id = 'png-container';
b.appendChild(image);
// this part comes from here: http://bl.ocks.org/biovisualize/8187844
var svgString = new XMLSerializer().serializeToString(d.getElementsByClassName('ddp-chart-inner')[0]);
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
ctx.drawImage(img, 0, 0);
var png = canvas.toDataURL("image/png");
document.querySelector('#png-container').innerHTML = '<img src="'+png+'"/>';
// that's what I want... it downloads a file that doesn't look like the chart ...
saveAs(png, 'test.png');
DOMURL.revokeObjectURL(png);
};
img.src = url;
}
b.appendChild(fs);
}).call(this);
This code is loaded via this bookmarklet:
javascript:(function(){ var d = document, b = d.body, s = d.createElement('script'); s.setAttribute('src', 'https://pastebin.com/raw/cduvdC6e?x=' + Math.random()); b.appendChild(s);}());
The result that I'm getting is this:
One can just about recognise the X axis labels rotated 45 degrees, but other than that ...
Note that I've started initially using the html2canvas
library but results weren't satisfying either.
Also, right now, no clean up is done such as removing the created elements, for example.
Having spoken to the developers, they said that the mix of HTML and SVG for these specific charts made it impossible to create the PNG client-side. It is indeed necessary to use puppeteer on the server to achieve what was asked.