D3js导出SVG为图像

7

我正在处理这个与D3js相关的折线图

我想将其保存为图像,并存储在与此示例相同的目录中。

d3.select('#saveButton').on('click', function(){
    var svgString = getSVGString(svg.node());
    svgString2Image( svgString, 2*width, 2*height, 'png', save ); // passes Blob and filesize String to the callback

    function save( dataBlob, filesize ){
        saveAs( dataBlob, 'D3 vis exported to PNG.png' ); // FileSaver.js 
function
    }
});

上述代码没有出现任何错误。

虽然我没有收到任何错误提示,但是当我点击按钮时,文件并没有下载。我错过了什么吗?谢谢!

2个回答

6
在您的代码示例中,您正在将g附加到您的svg上,并将其分配给变量svg:
var svg = d3.select("#priceWithMilestones")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform",
     "translate(" + margin.left + "," + margin.top + ")");

看起来getSVGString()期望的是根节点,而不是

var svgString = getSVGString(svg.node());

to

var svgString = getSVGString(d3.select('svg').node());

请保存。更新的代码片段:https://jsfiddle.net/c19664p3/8/

编辑:关于导出的样式,似乎在声明选择器时无法引用svg外部的选择器。此外,它看起来必须仅由id或类组成。请参见我的其他答案以获取更灵活的CSS规则导出器。

因此,将其更改为:

#priceWithMilestones .line {
  fill: none;
  stroke: #14da9e;
  stroke-width: 2px;
}

to:

.line {
  fill: none;
  stroke: #14da9e;
  stroke-width: 2px;
}

仅为SVG导出行样式。更新的代码片段: https://jsfiddle.net/c19664p3/10/


1
导出代码在导出 CSS 样式方面非常有野心,可以遍历样式表并将其附加到导出的 SVG 文本中。 - Steve
如何将导出背景更改为“白色”或其他颜色? - Tenz

3

看了一下getCSSStyles,它似乎只检查与根svg及其子元素的id或类完全匹配的规则。我认为这是一个更宽容的实现:

function getCSSStyles( parentElement ) {
    var nodesToCheck = [ parentElement ], i;

    // Add all the different nodes to check
    var childNodes = parentElement.getElementsByTagName("*");
    for (i = 0; i < childNodes.length; i++) {
        nodesToCheck.push(childNodes[i]);
    }

    // Extract CSS Rules
    var extractedCSSRules = [];
    for (i = 0; i < document.styleSheets.length; i++) {
        var s = document.styleSheets[i];

        try {
            if (!s.cssRules) continue;
        } catch( e ) {
            if (e.name !== 'SecurityError') throw e; // for Firefox
            continue;
        }

        var cssRules = s.cssRules;
        var ruleMatches;
        for (var r = 0; r < cssRules.length; r++) {
            ruleMatches = nodesToCheck.reduce(function (a, b) {
                return a || b.matches(cssRules[r].selectorText);
            }, false);
            if (ruleMatches)
                extractedCSSRules.push(cssRules[r].cssText);
        }
    }
    return extractedCSSRules.join(' ');
}

你仍然需要使用SVG内部的规则(例如,你仍然需要在CSS中将#priceWithMilestones .line更改为.line),但对于未来的项目,我认为它应该可以捕获更多的元素。
所有更改后的fiddle链接:https://jsfiddle.net/c19664p3/12/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接