javascript - 如何使用 Javascript 获取完整的 Canvas 内容(甚至隐藏的内容)?

标签 javascript svg canvas export png

我目前正在开发一个 Javascript 项目,并且正在努力将整个 SVG 图像导出到 Canvas 上。到目前为止,我只能导出 Canvas 的可见部分,而无法导出“隐藏”部分。

如何捕获完整的 Canvas 内容? 有没有办法在不影响原始 Canvas 大小的情况下做到这一点?

我使用的是 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;
}

最佳答案

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

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);
}
svg{border: 1px solid blue}
canvas{border: 1px solid green}
<svg width="50" height="50" viewBox="0 0 50 50">
  <rect x="0" y="0" width="200" height="50" fill="#CCC"/>
</svg>

关于javascript - 如何使用 Javascript 获取完整的 Canvas 内容(甚至隐藏的内容)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50632567/

相关文章:

javascript - 同一对象上不同动画的单独属性

python - 从 python 中的 SVG 源在 GTK3 中绘制 SVG 图像

javascript - 如何更改 JavaScript Pong 游戏 onClick 的内部属性

javascript - 如何用特定颜色填充整个 Canvas ?

javascript - React/Redux : Component not redrawing despite correct dispatching and state change.(不涉及突变)

javascript - 如何将数组值插入对象?

css - Firefox 上 CSS 动画前后的 SVG 模糊

angular - SVG 模式在 Safari 中不起作用

javascript - Canvas,计算起始点20%在线

javascript - Ajax 请求时出现 500 内部服务器错误。不确定问题的根源