服务器端d3 - 将SVG编码为Base64映像

Edd*_*Edd 0 javascript svg node.js d3.js

我正在尝试将D3图表编码为base64图像,以便在HTML电子邮件中使用

到目前为止,我有:

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);
});
Run Code Online (Sandbox Code Playgroud)

这会输出SVG html,这很有用但是我还想要第二个响应字段encoded,它应该包含我可以在我的HTML电子邮件中使用的类似下面的内容:

"encoded": "data:image/png;base64,iVBORw0KGgoAAAANSUhEU...etc"
Run Code Online (Sandbox Code Playgroud)

我该如何编码这个SVG?如果可能的话,我想避免任何文件写入,直接从SVG到编码图像.此外,我知道您可以在电子邮件中使用SVG,但我更倾向于使用编码图像格式.谢谢!

gue*_*314 7

设置"xmlns"在根属性<svg>节点"http://www.w3.org/2000/svg"<svg>内节点document或与.attr().

data URI计划包括

data:[<media type>][;base64],<data>
Run Code Online (Sandbox Code Playgroud)

既然我们知道<media type>将要image/svg+xml和我们想要base64表示结果数据,我们可以定义一个变量,我们将连接它的base64表示<svg>.

let data = "data:image/svg+xml;base64,";
Run Code Online (Sandbox Code Playgroud)

然后,我们得到.outerHTML<svg>元素

// optionally preceded by `XML` declaration `<?xml version="1.0" standalone="yes"?>`
let svgString = svg[0][0].outerHTML; 
Run Code Online (Sandbox Code Playgroud)

btoa()使用svgStringas参数调用

如果数据包含代码点大于U + 00FF的任何字符,则该btoa(data方法必须抛出" InvalidCharacterError " DOMException.否则,用户代理必须将数据转换为八位字节序列,其第n个八位字节是数据的第n个字符的代码点的八位表示,然后必须将base64算法应用于该八位字节序列,并返回结果.[RFC4648]

let base64 = window.btoa(svgString);
// concatenate `data` and `base64`
let dataURI = data + base64;

response.send({
                "html": window.d3.select("body").html(),
                "encoded": dataURI
             });
Run Code Online (Sandbox Code Playgroud)

let svg = window.d3.select("svg")
  .attr("xmlns", "http://www.w3.org/2000/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");

let data = "data:image/svg+xml;base64,";
let svgString = svg[0][0].outerHTML;
let base64 = window.btoa(svgString);
let dataURI = data + base64;

console.log(dataURI);

document.querySelector("iframe").src = dataURI;
Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v3.min.js"></script>
<svg></svg>
<iframe></iframe>
Run Code Online (Sandbox Code Playgroud)


Edd*_*Edd 5

完整的解决方案,使用 NodeJS 构建 d3 图表并将其转换为编码的 PNG,而不使用文件存储(大多数云托管所必需的)

let express = require('express');
let app = express();

let jsdom = require('jsdom');
let Buffer = require('buffer').Buffer;
let svg2png = require('svg2png');

app.post('/chart', function (request, response) {
    try {
        jsdom.env(
            "<svg id=\"svg\"></svg>",
            ['http://d3js.org/d3.v3.min.js'],
            function (err, window) {
                let svg = window.d3.select("svg")
                    .attr("width", 100)
                    .attr("height", 100)
                    .attr("xmlns", "http://www.w3.org/2000/svg");

                svg.append("rect")
                    .attr("x", 10)
                    .attr("y", 10)
                    .attr("width", 80)
                    .attr("height", 80)
                    .style("fill", "orange");

                let data = "data:image/png;base64,";
                let svgString = svg[0][0].outerHTML;
                let buffer = new Buffer("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + svgString);
                let promise = svg2png(buffer, {width: 300, height: 400}); // This options block is optional but height and width should be specified on the SVG HTML otherwise
                promise.then(buffer => {
                    let dataURI = data + buffer.toString('base64');
                    response.set('Content-Type', 'application/json');
                    response.send({
                        "html": svgString,
                        "encoded": dataURI
                    });
                });
            }
        );
    } catch (err) {
        console.warn(err);
    }
});

// Run Server
let port = process.env.PORT || 8305;
let server = app.listen(port, function () {
    let host = server.address().address || 'localhost';
    console.log('Example app listening at http://%s:%s', host, port);
});
Run Code Online (Sandbox Code Playgroud)

响应中的字段encoded可以在 HTML 电子邮件中使用:

<img src="{encoded-value}"/>
Run Code Online (Sandbox Code Playgroud)

例如

<img src="data:image/png;base64,iVBORw0KGgoAAA..."/>
Run Code Online (Sandbox Code Playgroud)