I'm trying to encode a D3 chart as a base64 image for use in HTML emails
So far I have:
var express = require('express');
var app = express();
var jsdom = require('jsdom');
app.get('/chart', function (request, response) {
try {
jsdom.env(
"<html><body><svg id=\"svg\"></svg></body></html>",
['http://d3js.org/d3.v3.min.js'],
function (err, window) {
var svg = window.d3.select("svg")
.attr("width", 100)
.attr("height", 100);
svg.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 80)
.attr("height", 80)
.style("fill", "orange");
var encoded = ...; // How do I now encode this?
response.send({
"html": window.d3.select("body").html(),
"encoded": encoded
});
}
);
} catch (err) {
console.error(err);
}
});
// Run Server
var port = process.env.PORT || 8305;
var server = app.listen(port, function () {
var host = server.address().address;
console.log('App listening at http://%s:%s', host, port);
});
This outputs the SVG html which is useful however I would also like a second response field encoded
which should contain something like below that I can use in my HTML email:
"encoded": "data:image/png;base64,iVBORw0KGgoAAAANSUhEU...etc"
How do I encode this SVG? I would like to avoid any file writing if possible and go straight from SVG to encoded image. Also, I'm aware you can use SVGs in emails but I would much rather it be in an encoded image format. Thanks!
Set the
"xmlns"
attribute at root<svg>
node to"http://www.w3.org/2000/svg"
at<svg>
node withindocument
or with.attr()
.The
data URI
scheme consists ofSince we know that the
<media type>
will beimage/svg+xml
and that we wantbase64
representation of resulting data, we can define a variable to which we will concatenatebase64
representation of<svg>
.Then we get the
.outerHTML
of<svg>
elementCall
btoa()
withsvgString
as parameterFull solution which builds a d3 chart using NodeJS and converts it to an encoded PNG without using file storage (neccessary for most cloud hosting)
The
encoded
field in the response can be used in a HTML email using:e.g
In order to send it as a png image, you would first have to rasterize the svg, which is the actual problem. This has been answered in several places, but this one contains a number of good solutions. You should probably use imagemagick for the conversion. Since you want to avoid writing to an intermediate file, that answer suggests you can pipe the svg contents to the converter's stdin.
The received buffer could probably be directly encoded to base64.