javascript - ¿Cómo puedo obtener png(base64) con imágenes dentro de svg en Google Charts?
google-visualization (3)
¿Cómo puedo obtener base64 con imagen dentro de svg? Mira este Fiddle que obtuve de otra pregunta. Si ve el segundo gráfico, no está generando la imagen que se superpone a la barra.
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())
Este ejemplo crea un contenedor de svg poblado por una imagen. En mi ejemplo, la imagen es una imagen svg, pero debería poder poner cualquier tipo de imagen (jpg, png, gif). El contenedor se crea primero y luego la imagen se crea dentro del contenedor.
// 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);
Para guardar este svg en un png, que mantiene la
<image>
vinculada, primero deberá codificar cada
href
<image>
en un dataURL.
Editar
Reescribí los fragmentos originales (que todavía se pueden encontrar en el historial de edición) .
-
Cambié las etiquetas
<image>
a<use>
. Esto da como resultado un uso de memoria mucho menor. -
También agregué un respaldo para IE11, que acepta codificar la imagen externa a la URL de datos, pero aún no puede convertir svg a png a través del lienzo. El respaldo reemplazará la etiqueta de destino
<img>
, con el lienzo. El último puede ser guardado por el usuario con un clic derecho. -
Algunas advertencias:
No funciona en Safari 7, y tal vez en otros navegadores webkit obsoletos. Es un error extraño, ya que funciona como un encanto en localhost, pero no lo hará en ninguna otra red (incluso en mi red doméstica, usando 192.168.xxx).
IE 9 y IE 10 no podrán convertir las imágenes externas a URL de datos, problema CORS.
// 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;
}
svg { border: 1px solid yellow; }
img { border: 1px solid green; }
canvas { border: 1px solid red; }
<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" />
Tenga en cuenta que cuando se convierte a
src
del elemento
img
retiene el
blue
background-color
blue
.
Intenta, después de
.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/