SVG to Canvas with d3.js

前端 未结 4 484
闹比i
闹比i 2020-11-28 09:07

Has anyone tried using a svg to canvas library when creating d3.js visualizations? I\'ve tried to use canvg.js and d3.js to convert svg to canvas from within an android 2.3

相关标签:
4条回答
  • 2020-11-28 09:20

    The answer by @ace is very good, however it doesn't handle the case of external CSS stylesheets. My example below will automatically style the generated image exactly how the original SVG looks, even if it's pulling styles form separate stylesheets.

    // 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 + '"/>');
    };
    

    And, to be complete, the button that calls the function:

    // save button
    d3.select('body')
        .append("button")
        .on("click",saveSVG)
        .attr('class', 'btn btn-success')
    
    0 讨论(0)
  • 2020-11-28 09:29

    I've not tried a library, but have rendered a d3-produced SVG to a canvas following this post on MDN.

    This code is a quick mish-mash of the MDN and some jQuery, that'll you'll need to tidy up, and it has no error- or platfrom-checking, but it works, and I hope it helps.

    $(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;
    
    0 讨论(0)
  • 2020-11-28 09:33

    Have you tried the same code on a browser supporting SVG to see if it's a problem with webview? Then try this example using canvg or this one using DOM serialization. For server-side rendering, you could start with this example for how to render it to canvas server-side using Node.js.

    0 讨论(0)
  • 2020-11-28 09:42

    Here's one way you could write your svg to canvas (and then save the result as a png or whatever):

    // 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
    };
    
    0 讨论(0)
提交回复
热议问题