使用链接图像导出js / d3可视化

时间:2017-11-19 14:44:38

标签: javascript d3.js canvas

我对D3很新(所以我的问题可能有点愚蠢)并且正在进行可视化,我想将其导出到png。我是这样做的:http://bl.ocks.org/Rokotyan/0556f8facbaf344507cdc45dc3622177

我在造型等方面遇到了一些问题,但是内嵌样式解决了这个问题。

我现在遇到的问题是我在SVG中使用的png图像没有出现在我导出到png的画布中。

我已经进行了相当多的实验,没有达到预期的效果。

下面的代码将png放在SVG上:

svg.selectAll("svg")
     .data(inputdata)
     .enter()
     .append("svg:image")
     .attr("xlink:href", "image_1.png")
     .attr("x", function(d) {
        return (d.X_Coordinate);})
     .attr("y", function(d) {
        return (d.Y_Coordinate);})
    .attr("width", image_width)
    .attr("height", image_height)
     ;

d3.selectAll("svg").attr({'xmlns': 'http://www.w3.org/2000/svg','xmlns:xmlns:xlink': 'http://www.w3.org/1999/xlink'});

1 个答案:

答案 0 :(得分:0)

您需要对images as base64进行编码。因此,借用this excellent answer中的一些代码并将其与您链接的示例放在一起:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>How to properly export SVG D3 visualization to PNG or JPEG</title>
  <meta charset="utf-8">
  <script src="https://cdn.rawgit.com/eligrey/canvas-toBlob.js/f1a01896135ab378aa5c0118eadd81da55e698d8/canvas-toBlob.js"></script>
  <script src="https://cdn.rawgit.com/eligrey/FileSaver.js/e9d941381475b5df8b7d7691013401e171014e89/FileSaver.min.js"></script>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <style type="text/css">
    .blendCircle {
      mix-blend-mode: multiply;
    }
  </style>
</head>

<body>
  <div>
    <button id='saveButton'>Export my D3 visualization to PNG</button>
  </div>
  <script type="text/javascript">
    var width = 200,
      height = 200;

    var svg = d3.select('body').append('svg')
      .attr('width', width)
      .attr('height', height);

    svg
      .append("svg:image")
      .each(function() {
        toDataURL(
          'https://i.imgur.com/1kqZEq2.jpg',
          (dataUrl) => {
            d3.select(this).attr("xlink:href", dataUrl);
          }
        )
      })
      .attr("width", width)
      .attr("height", height);

    function toDataURL(src, callback, outputFormat) {
      var img = new Image();
      img.crossOrigin = 'Anonymous';
      img.onload = function() {
        var canvas = document.createElement('CANVAS');
        var ctx = canvas.getContext('2d');
        var dataURL;
        canvas.height = this.naturalHeight;
        canvas.width = this.naturalWidth;
        ctx.drawImage(this, 0, 0);
        dataURL = canvas.toDataURL(outputFormat);
        callback(dataURL);
      };
      img.src = src;
      if (img.complete || img.complete === undefined) {
        img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
        img.src = src;
      }
    }

    // Set-up the export button
    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
      }
    });

    // 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;
    }
  </script>
</body>

</html>