如何在Google Charts中获取svg内部图像的png(base64)?

时间:2015-04-30 18:30:05

标签: javascript svg google-visualization

如何在svg中获取带有图像的base64?检查我从另一个问题得到的Fiddle。如果您看到第二个图形,则它不会生成覆盖条形图像的图像。

var chart = new google.visualization.ColumnChart(document.getElementById('chart_survey'));

$("[fill='#FFFFFF']").each(function( index, element ) {
    var svgimg = document.createElementNS('http://www.w3.org/2000/svg','image');
    svgimg.setAttributeNS(null,'x',element.x.baseVal.value);
    svgimg.setAttributeNS(null,'y',element.y.baseVal.value);
    svgimg.setAttributeNS(null,'width',element.width.baseVal.value);
    svgimg.setAttributeNS(null,'height',element.height.baseVal.value);
    svgimg.setAttributeNS(null,'preserveAspectRatio','none');
    svgimg.setAttributeNS('http://www.w3.org/1999/xlink','href', '${application.contextPath}/images/textura/patt.gif');
    $(element).parent().append(svgimg);
});

$('#test').val(chart.getImageURI())

4 个答案:

答案 0 :(得分:2)

为了将此svg保存到保留链接<image>的png,您必须将每个<image> href编码为dataURL第一。

修改

我重写了原始片段(仍可在编辑历史记录中找到)

  • 我将<image>代码更改为<use>。这导致内存使用量小得多。

  • 我还为IE11添加了一个后备,它接受将外部图像编码为数据URL,但仍无法通过画面将svg转换为png。 后备将使用画布替换目标<img>标记。用户可以通过右键单击保存更晚的内容。

  • 一些警告:
    它在Safari 7中不起作用,也可能在其他过时的webkit浏览器中起作用。这是一个奇怪的错误,因为它确实像localhost中的魅力一样,但在任何其他网络上都没有(甚至在我的家庭网络上,使用192.168.xxx)。 IE 9&amp; IE 10将无法​​将外部图像转换为数据URL,CORS问题。

&#13;
&#13;
// What to do with the result (either data URL or directly the canvas if tainted)
var callback = function(d, isTainted) {
  if (!isTainted) {
    $('#chartImg')[0].src = d;
  } else
    $('#chartImg')[0].parentNode.replaceChild(d, $('#chartImg')[0]);
};
// The url of the external image (must be cross-origin compliant)
var extURL = 'https://dl.dropboxusercontent.com/s/13dv8vzmrlcmla2/tex2.jpg';

google.load('visualization', '1', {
  packages: ['corechart']
})

var encodeCall = getbase64URI.bind(this, extURL, callback);
google.setOnLoadCallback(encodeCall);



// Google Chart part
function drawVisualizationDaily(imgUrl, callback, isTainted) {

  var data = google.visualization.arrayToDataTable([
    ['Daily', 'Sales'],
    ['Mon', 4],
    ['Tue', 6],
    ['Wed', 6],
    ['Thu', 5],
    ['Fri', 3],
    ['Sat', 7],
    ['Sun', 7]
  ]);

  var chart = new google.visualization.ColumnChart(document.getElementById('visualization'));

  chart.draw(data, {
    title: "Daily Sales",
    width: 500,
    height: 400,
    hAxis: {
      title: "Daily"
    }
  });

  // Link to chart's svg element
  var svgNode = chart.ea.querySelector('svg');
  // Create a symbol for our image
  var symbol = document.createElementNS('http://www.w3.org/2000/svg', 'symbol');
  // An svg wrapper to allow size changing with <use>
  symbol.setAttributeNS(null, 'viewBox', '0,0,10,10');
  symbol.setAttributeNS(null, 'preserveAspectRatio', 'none');
  symbol.id = 'background';
  // And the actual image, with our encoded image
  var img = document.createElementNS('http://www.w3.org/2000/svg', 'image');
  img.setAttributeNS(null, 'preserveAspectRatio', 'none');
  img.setAttributeNS(null, 'width', '100%');
  img.setAttributeNS(null, 'height', '100%');
  img.setAttributeNS('http://www.w3.org/1999/xlink', 'href', imgUrl);

  symbol.appendChild(img);
  svgNode.appendChild(symbol);

  var blueRects = $("[fill='#3366cc']");
  var max = blueRects.length - 1;
  blueRects.each(function(index, element) {
    var svgimg = document.createElementNS('http://www.w3.org/2000/svg', 'use');
    svgimg.setAttributeNS(null, 'x', element.x.baseVal.value);
    svgimg.setAttributeNS(null, 'y', element.y.baseVal.value);
    svgimg.setAttributeNS(null, 'width', element.width.baseVal.value);
    svgimg.setAttributeNS(null, 'height', element.height.baseVal.value);
    svgimg.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#background');
    svgNode.appendChild(svgimg);

    if (index === max && !isTainted) // no need to call it if we don't have our dataURL encoded images
    // a load event would be better but it doesn't fire in IE ...
      setTimeout(exportSVG.bind(this, svgNode, callback, isTainted), 200);
  });
}

function exportSVG(svgNode, callback, isTainted) {

  var svgData = (new XMLSerializer()).serializeToString(svgNode);

  var img = new Image();
  img.onload = function() {
    var canvas = document.createElement('canvas');
    canvas.width = svgNode.getAttribute('width');
    canvas.height = svgNode.getAttribute('height');
    canvas.getContext('2d').drawImage(this, 0, 0);
    var data, isTainted;
    try {
      data = canvas.toDataURL();
    } catch (e) {
      data = canvas;
      isTainted = true;
    }
    callback(data, isTainted);
  }
  img.src = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);
}

// A simple function to convert an images's url to base64 data URL
function getbase64URI(url, callback) {
  var img = new Image();
  img.crossOrigin = "Anonymous";
  img.onload = function() {
    var c = document.createElement('canvas');
    c.width = this.width;
    c.height = this.height;
    c.getContext('2d').drawImage(this, 0, 0);
    var isTainted;
    try {
      c.toDataURL();
    } catch (e) {
      isTainted = true;
    }
    // if the canvas is tainted, return the url
    var output = (isTainted) ? url : c.toDataURL();
    drawVisualizationDaily(output, callback, isTainted);
  }
  img.src = url;
}
&#13;
svg    { border: 1px solid yellow; }
img    { border: 1px solid green;  }
canvas { border: 1px solid red;    }
&#13;
<script src="http://www.google.com/jsapi?.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="visualization"></div>
Right-click this image to save it:
<br>
<img id="chartImg" />
&#13;
&#13;
&#13;

答案 1 :(得分:0)

此示例创建一个由图像填充的svg容器。在我的例子中,图像是一个svg图像,但你应该能够放入任何类型的图像(jpg,png,gif)。首先创建容器,然后在容器内创建图像。

 // create svg
                var svg = document.createElementNS('http://www.w3.org/2000/svg','svg');
                svg.setAttribute('class','shadowed handle_icon_sensors');
                svg.setAttribute('height','25');
                svg.setAttribute('width','25');
                svg.setAttribute('id',idAttr);
                svg.setAttribute('z-index','21000');
                document.getElementById("zones_container").appendChild(svg);

            // create svg image
            var svgimg = document.createElementNS('http://www.w3.org/2000/svg','image');
            svgimg.setAttribute('height','25');
            svgimg.setAttribute('width','25');
            svgimg.setAttributeNS('http://www.w3.org/1999/xlink','href','svg/icon_sensorYellow.svg');
            svgimg.setAttribute('x','0');
            svgimg.setAttribute('y','0');
            document.getElementById(idAttr).appendChild(svgimg);

答案 2 :(得分:0)

注意,转换为src img个元素时保留blue background-color

.each()

之后尝试
// set namespace attributes
var svg = $("svg").attr({
    "xmlns": "http://www.w3.org/2000/svg",
    "xmlns:xlink": "http://www.w3.org/1999/xlink"
})[0];

// create `data URI` of `svg`
var dataURI = "data:image/svg+xml;charset=utf-8;base64," + btoa(svg.outerHTML.trim());    

// post `svg` as `data URI` to server
$.post("/path/to/server/", {
    html: dataURI
}, "html")
    .then(function (data) {
    // do stuff
    // `svg` `data URI`
    console.log(data);

}, function (jqxhr, textStatus, errorThrown) {
    console.log(textStatus, errorThrown);
});

jsfiddle http://jsfiddle.net/R8A8P/58/

答案 3 :(得分:0)

这个 html 在反应中起作用

 <a
    href={chart.getImageURI()}
    download="chart.png">
    getImage
  </a>