【问题标题】:SVG to Canvas with d3.js使用 d3.js 将 SVG 转为画布
【发布时间】:2012-07-19 00:58:35
【问题描述】:

有没有人在创建 d3.js 可视化时尝试使用 svg to canvas 库?我尝试使用 canvg.js 和 d3.js 从 android 2.3 应用程序 webview 中将 svg 转换为画布,但是当我调用时:

svg.selectAll(".axis")
    .data(d3.range(angle.domain()[1]))
    .enter().append("g")
    .attr("class", "axis")
    .attr("transform", function(d) { return "rotate(" + angle(d) * 180 / Math.PI + ")"; })
    .call(d3.svg.axis()
        .scale(radius.copy().range([-5, -outerRadius]))
        .ticks(5)
        .orient("left"))
    .append("text")
    .attr("y", 
        function (d) {
            if (window.innerWidth < 455){
                console.log("innerWidth less than 455: ",window.innerWidth);
                return -(window.innerHeight * .33);
            }
            else {
                console.log("innerWidth greater than 455: ",window.innerWidth);
                return -(window.innerHeight * .33);
            }
        })
    .attr("dy", ".71em")
    .attr("text-anchor", "middle")
    .text(function(d, i) { return capitalMeta[i]; })
    .attr("style","font-size:12px;");

我收到错误:未捕获的类型错误:无法调用方法 setProperty of null http://mbostock.github.com/d3/d3.js?2.5.0:1707

某种无头浏览器应用程序或服务器端 js 解析器可以工作吗?有没有人遇到过这种情况?

【问题讨论】:

    标签: javascript node.js select svg d3.js


    【解决方案1】:

    这是您可以将 svg 写入画布(然后将结果另存为 png 或其他格式)的一种方法:

    // Create an export button
    d3.select("body")
        .append("button")
        .html("Export")
        .on("click",svgToCanvas);
    
    var w = 100, // or whatever your svg width is
        h = 100;
    
    // Create the export function - this will just export 
    // the first svg element it finds
    function svgToCanvas(){
        // Select the first svg element
        var svg = d3.select("svg")[0][0],
            img = new Image(),
            serializer = new XMLSerializer(),
            svgStr = serializer.serializeToString(svg);
    
        img.src = 'data:image/svg+xml;base64,'+window.btoa(svgStr);
    
        // You could also use the actual string without base64 encoding it:
        //img.src = "data:image/svg+xml;utf8," + svgStr;
    
        var canvas = document.createElement("canvas");
        document.body.appendChild(canvas);
    
        canvas.width = w;
        canvas.height = h;
        canvas.getContext("2d").drawImage(img,0,0,w,h);
        // Now save as png or whatever
    };
    

    【讨论】:

    • 很好的答案!我还在下面添加了一个解决方案(基于您的),它从外部 CSS 样式表中提取样式。
    • @ace 能给我完整的代码吗,拜托,真的需要它
    • @ace ,也许是个 plnkr/fiddle
    【解决方案2】:

    @ace 的回答非常好,但是它不处理外部 CSS 样式表的情况。我下面的示例将自动为生成的图像设置原始 SVG 外观的样式,即使它从单独的样式表中提取样式也是如此。

    // when called, will open a new tab with the SVG
    // which can then be right-clicked and 'save as...'
    function saveSVG(){
    
        // get styles from all required stylesheets
        // http://www.coffeegnome.net/converting-svg-to-png-with-canvg/
        var style = "\n";
        var requiredSheets = ['phylogram_d3.css', 'open_sans.css']; // list of required CSS
        for (var i=0; i<document.styleSheets.length; i++) {
            var sheet = document.styleSheets[i];
            if (sheet.href) {
                var sheetName = sheet.href.split('/').pop();
                if (requiredSheets.indexOf(sheetName) != -1) {
                    var rules = sheet.rules;
                    if (rules) {
                        for (var j=0; j<rules.length; j++) {
                            style += (rules[j].cssText + '\n');
                        }
                    }
                }
            }
        }
    
        var svg = d3.select("svg"),
            img = new Image(),
            serializer = new XMLSerializer(),
    
        // prepend style to svg
        svg.insert('defs',":first-child")
        d3.select("svg defs")
            .append('style')
            .attr('type','text/css')
            .html(style);
    
    
        // generate IMG in new tab
        var svgStr = serializer.serializeToString(svg.node());
        img.src = 'data:image/svg+xml;base64,'+window.btoa(unescape(encodeURIComponent(svgStr)));
        window.open().document.write('<img src="' + img.src + '"/>');
    };
    

    而且,完整地说,调用函数的按钮:

    // save button
    d3.select('body')
        .append("button")
        .on("click",saveSVG)
        .attr('class', 'btn btn-success')
    

    【讨论】:

    • 这很有帮助,但是您的示例对 requiredSheets 和 document.styleSheets 感到困惑,这导致了我的一些错误。我通过删除var requiredSheets ...if(requiredSheets.indexOf ... 来修复它们(这意味着我可以删除var sheetName ...)。也就是说, requiredSheets 是不必要的,会导致错误,并且可以安全地删除。
    • @Constantino: heightwidth 从未使用过 - 为什么要为它们赋值?
    【解决方案3】:

    您是否在支持 SVG 的浏览器上尝试过相同的代码,看看是否是 webview 的问题?然后尝试this example 使用canvg 或this one 使用DOM 序列化。对于服务器端渲染,您可以从 this example 开始,了解如何使用 Node.js 将其渲染到画布服务器端。

    【讨论】:

      【解决方案4】:

      我没有尝试过库,但在 MDN 上的 this 帖子之后将 d3 生成的 SVG 渲染到画布上。

      这段代码是 MDN 和一些 jQuery 的快速混搭,你需要整理一下,它没有错误或平台检查,但它有效,我希望它有所帮助。

      $(document.body).append(
          '<canvas id="canvas" width="'+diameter+'" height="'+diameter+'"></canvas>'
      );
      
      // https://developer.mozilla.org/en/docs/HTML/Canvas/Drawing_DOM_objects_into_a_canvas
      var el = $($('svg')[0]);
      var svgMarkup = '<svg xmlns="http://www.w3.org/2000/svg"'
      + ' class="'  + el.attr('class') +'"'
      + ' width="'  + el.attr('width') +'"'
      + ' height="' + el.attr('height') +'"'
      + '>'
      + $('svg')[0].innerHTML.toString()+'</svg>';
      var canvas = document.getElementById("canvas");
      var ctx = canvas.getContext("2d");
      var DOMURL = this.URL || this.webkitURL || this;
      var img = new Image();
      var svg = new Blob([svgMarkup], {type: "image/svg+xml;charset=utf-8"});
      var url = DOMURL.createObjectURL(svg);
      img.onload = function() {
          ctx.drawImage(img, 0, 0);
          alert('ok');
          DOMURL.revokeObjectURL(url);
      };
      img.src = url;
      

      【讨论】:

        猜你喜欢
        • 2021-04-10
        • 2017-07-30
        • 2023-03-04
        • 2015-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-14
        • 1970-01-01
        相关资源
        最近更新 更多