如何使用Javascript获取完整的画布内容(甚至是隐藏的内容)?

时间:2018-05-31 20:49:31

标签: javascript svg canvas export png

我目前正在开发一个Javascript项目,我正在努力在画布上导出整个SVG图像。到目前为止,我只能导出画布的可见部分,而没有"隐藏"部分。

如何捕获完整的画布内容? 有没有办法在不弄乱原始画布尺寸的情况下做到这一点?

我正在使用D3.js V3

enter image description here 我的项目的屏幕截图

这是我的代码:

    var svgString;
    window.onload = function(){
    setTimeout(function() {

        exportSVG = document.getElementById("canvas");

        document.getElementById("canvas").style.fontFamily= "lato";
        document.getElementById("canvas").style.width= exportSVG.getBBox().width * 1;
        document.getElementById("canvas").style.height= exportSVG.getBBox().height * 1;

        svgString = getSVGString(exportSVG);
        console.log(exportSVG.getBBox().width + " / " + exportSVG.getBBox().height);
        svgString2Image(svgString, exportSVG.getBBox().width, exportSVG.getBBox().height, 'png', save); // passes Blob and filesize String to the callback
        console.log("svg export code loaded");
        // console.log(svgString.getBBox().width); document.getElementById("canvas").getBBox().width
    }, 5000);
};

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

// Below are the functions that handle actual exporting:
// getSVGString ( svgNode ) and svgString2Image( svgString, width, height, format, callback )
function getSVGString(svgNode) {
    svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink');
    var cssStyleText = getCSSStyles(svgNode);
    appendCSS(cssStyleText, svgNode);

    var serializer = new XMLSerializer();
    var svgString = serializer.serializeToString(svgNode);
    svgString = svgString.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace
    svgString = svgString.replace(/NS\d+:href/g, 'xlink:href'); // Safari NS namespace fix

    return svgString;

    function getCSSStyles(parentElement) {
        var selectorTextArr = [];

        // Add Parent element Id and Classes to the list
        selectorTextArr.push('#' + parentElement.id);
        for (var c = 0; c < parentElement.classList.length; c++)
            if (!contains('.' + parentElement.classList[c], selectorTextArr))
                selectorTextArr.push('.' + parentElement.classList[c]);

        // Add Children element Ids and Classes to the list
        var nodes = parentElement.getElementsByTagName("*");
        for (var i = 0; i < nodes.length; i++) {
            var id = nodes[i].id;
            if (!contains('#' + id, selectorTextArr))
                selectorTextArr.push('#' + id);

            var classes = nodes[i].classList;
            for (var c = 0; c < classes.length; c++)
                if (!contains('.' + classes[c], selectorTextArr))
                    selectorTextArr.push('.' + classes[c]);
        }

        // Extract CSS Rules
        var extractedCSSText = "";
        for (var 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;
            for (var r = 0; r < cssRules.length; r++) {
                if (contains(cssRules[r].selectorText, selectorTextArr))
                    extractedCSSText += cssRules[r].cssText;
            }
        }

        return extractedCSSText;
        function contains(str, arr) {
            return arr.indexOf(str) === -1 ? false : true;
        }
    }

    function appendCSS(cssText, element) {
        var styleElement = document.createElement("style");
        styleElement.setAttribute("type", "text/css");
        styleElement.innerHTML = cssText;
        var refNode = element.hasChildNodes() ? element.children[0] : null;
        element.insertBefore(styleElement, refNode);
    }
}

function svgString2Image(svgString, width, height, format, callback) {
    var format = format ? format : 'png';

    var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgString))); // Convert SVG string to data URL

    var canvas = document.createElement("canvas");
    var context = canvas.getContext("2d");

    canvas.width = width;
    canvas.height = height;

    var image = new Image();
    image.onload = function() {
        context.clearRect(0, 0, width, height);
        context.drawImage(image, 0, 0, width, height);

        canvas.toBlob(function(blob) {
            var filesize = Math.round(blob.length / 1024) + ' KB';
            if (callback) callback(blob, filesize);
        });


    };

    image.src = imgsrc;
}

1 个答案:

答案 0 :(得分:1)

只需更改<svg> viewBox属性,然后再将其序列化为字符串,以便显示所有内容:

&#13;
&#13;
var svg = document.querySelector('svg');
var toExport = svg.cloneNode(true); // avoids having to reset everything afterward
// grab its inner content BoundingBox
var bb = svg.getBBox();
// update its viewBox so it displays all its inner content
toExport.setAttribute('viewBox', bb.x + ' ' + bb.y + ' ' + bb.width + ' ' + bb.height);
toExport.setAttribute('width', bb.width);
toExport.setAttribute('height', bb.height);

var svgAsStr = new XMLSerializer().serializeToString(toExport);
var blob = new Blob([svgAsStr], {type: 'image/svg+xml'});
var img = new Image();
img.onload = drawToCanvas;
img.src = URL.createObjectURL(blob);

function drawToCanvas(evt) {
  var canvas = document.createElement('canvas');
  canvas.width = this.width;
  canvas.height = this.height;
  canvas.getContext('2d').drawImage(this, 0,0);
  document.body.appendChild(canvas);
}
&#13;
svg{border: 1px solid blue}
canvas{border: 1px solid green}
&#13;
<svg width="50" height="50" viewBox="0 0 50 50">
  <rect x="0" y="0" width="200" height="50" fill="#CCC"/>
</svg>
&#13;
&#13;
&#13;