javascript - tamaño - svg movimiento
cómo guardar/exportar SVG en línea con estilo css desde el navegador al archivo de imagen (4)
Tengo una aplicación web que está generando gráficos SVG en línea en el cliente sobre la marcha en función de la interacción del usuario. El gráfico se define en parte por los atributos de los elementos y en parte por las clases de CSS y los ID.
Me gustaría poder proporcionar una opción para que el cliente guarde una copia del SVG en línea como un mapa de bits o un archivo de imagen .svg. Es importante que todos los estilos se apliquen desde los archivos de estilo css externos. ¿Cómo puedo proporcionar esta funcionalidad para guardar como .svg o bitmap (.gif) preferiblemente en el navegador usando javascript o en el servidor con node.js?
Creo que lo que generalmente falta en estas explicaciones sobre este tema, es el hecho de que un archivo ".svg" es en realidad solo el marcado en un archivo de texto.
Así que obtenga los contenidos svg del dom, luego guarde un archivo de texto con el nombre de archivo ".svg".
var text = $(''#svg-container'').html();
text = text.slice(text.indexOf("<svg"),indexOf("/svg>")+4);
var pom = document.createElement(''a'');
pom.setAttribute(''href'', ''data:text/plain;charset=utf-8,'' + encodeURIComponent(text));
pom.setAttribute(''download'', "image.svg");
pom.style.display = ''none'';
document.body.appendChild(pom);
pom.click();
document.body.removeChild(pom);
Si, por ejemplo, illustrator le está dando un error como "SVG inválido, valide svg antes de continuar". Luego, vuelva a verificar el contenido del archivo descargado, y asegúrese de que no haya ninguna s o nada innecesario, y que text.slice(text.indexOf("<svg"),indexOf("/svg>")+4);
No cortó nada importante.
Deberá establecer explícitamente los estilos css calculados como propiedades de estilo dom SVG para cada elemento SVG antes de guardarlo. Aquí hay un ejemplo:
<html>
<body>
<!-- in this example the inline svg has black backgroud-->
<svg id="svg" xmlns="http://www.w3.org/2000/svg" version="1.1" height="190">
<polygon id="polygon" points="100,10 40,180 190,60 10,60 160,180" style="stroke:purple;stroke-width:5;">
</svg>
<style>
/* the external svg style makes svg shape background red */
polygon
{
fill:red;
}
</style>
<svg id="emptysvg" xmlns="http://www.w3.org/2000/svg" version="1.1" height="2"/>
<br/>
image original:
<canvas id="canvasOriginal" height="190" width="190" ></canvas>
<br/>
image computed:
<canvas id="canvasComputed" height="190" width="190" ></canvas>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/StackBlur.js"></script>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script>
<script src="http://www.nihilogic.dk/labs/canvas2image/canvas2image.js"></script>
<script type="text/javascript">
var svg = $(''#svg'')[0];
var canvasOriginal = $(''#canvasOriginal'')[0];
var ctxOriginal = canvasOriginal.getContext(''2d'');
var canvasComputed=$(''#canvasComputed'')[0];
var ctxConverted=canvasComputed.getContext("2d");
// this saves the inline svg to canvas without external css
canvg(''canvasOriginal'', new XMLSerializer().serializeToString(svg));
// we need to calculate the difference between the empty svg and ours
var emptySvgDeclarationComputed = getComputedStyle($(''#emptysvg'')[0]);
function explicitlySetStyle (element) {
var cSSStyleDeclarationComputed = getComputedStyle(element);
var i, len, key, value;
var computedStyleStr = "";
for (i=0, len=cSSStyleDeclarationComputed.length; i<len; i++) {
key=cSSStyleDeclarationComputed[i];
value=cSSStyleDeclarationComputed.getPropertyValue(key);
if (value!==emptySvgDeclarationComputed.getPropertyValue(key)) {
computedStyleStr+=key+":"+value+";";
}
}
element.setAttribute(''style'', computedStyleStr);
}
function traverse(obj){
var tree = [];
tree.push(obj);
if (obj.hasChildNodes()) {
var child = obj.firstChild;
while (child) {
if (child.nodeType === 1 && child.nodeName != ''SCRIPT''){
tree.push(child);
}
child = child.nextSibling;
}
}
return tree;
}
// hardcode computed css styles inside svg
var allElements = traverse(svg);
var i = allElements.length;
while (i--){
explicitlySetStyle(allElements[i]);
}
// this saves the inline svg to canvas with computed styles
canvg(''canvasComputed'', new XMLSerializer().serializeToString(svg));
$("canvas").click(function (event) {
Canvas2Image.saveAsPNG(event.target);
});
</script>
</body>
</html>
Si sus reglas de css no son demasiado complicadas, puede seguir los siguientes pasos:
Lea el archivo .css, que contiene toda la regla css. Si es necesario, puede usar un archivo css diferente y colocarlo en el servidor, que solo puede usar para este propósito.
function readTextFile(file) { var rawFile = new XMLHttpRequest(); var allText = ''''; rawFile.open("GET", file, false); rawFile.onreadystatechange = function () { if(rawFile.readyState === 4) { if(rawFile.status === 200 || rawFile.status == 0) { allText = rawFile.responseText; } } }; rawFile.send(null); return allText; } var svg_style = readTextFile(base_url + ''/css/svg_sm_dashboard.css'');
Ahora aplica el estilo en todos los elementos svg.
var all_style = svg_style.replace(//r?/n|/r/g,'''').split(''}''); all_style.forEach(function(el) { if (el.trim() != '''') { var full_rule_string = el.split(''{''); var selector = full_rule_string[0].trim(); var all_rule = full_rule_string[1].split('';''); all_rule.forEach(function (elem) { if (elem.trim() != '''') { var attr_value = elem.split('':''); //d3.selectAll(selector).style(attr_value[0].trim() + '''', attr_value[1].trim() + ''''); var prop = attr_value[0].trim(); var value = attr_value[1].trim(); d3.selectAll(selector).each(function(d, i){ if(!this.getAttribute(prop) && !this.style[prop]){ d3.select(this).style(prop + '''', value + ''''); } }); } }); } });
Usa canvg para convertirlo
$(''body'').after(''<canvas id="sm_canvas" style="display=none;"></canvas>''); var canvas = document.getElementById(''sm_canvas''); canvg(canvas, $("<div>").append($(''svg'').clone()).html());
Obtener imagen del lienzo
var imgData = canvas.toDataURL(''image/jpeg'');
¿Por qué no copiar el nodo / árbol SVG y luego tomar los estilos, como defiend por etiqueta? (Necesitará el árbol original, ya que la copia puede estar sin estilos en caso de que el elemento sea parte de un árbol más largo). Esto garantiza que solo está copiando los estilos relevantes según lo establecido en el archivo CSS. El tipo de exportación podría establecerse fácilmente antes de enviar el paquete al blob
var ContainerElements = ["svg","g"];
var RelevantStyles = {"rect":["fill","stroke","stroke-width"],"path":["fill","stroke","stroke-width"],"circle":["fill","stroke","stroke-width"],"line":["stroke","stroke-width"],"text":["fill","font-size","text-anchor"],"polygon":["stroke","fill"]};
function read_Element(ParentNode, OrigData){
var Children = ParentNode.childNodes;
var OrigChildDat = OrigData.childNodes;
for (var cd = 0; cd < Children.length; cd++){
var Child = Children[cd];
var TagName = Child.tagName;
if (ContainerElements.indexOf(TagName) != -1){
read_Element(Child, OrigChildDat[cd])
} else if (TagName in RelevantStyles){
var StyleDef = window.getComputedStyle(OrigChildDat[cd]);
var StyleString = "";
for (var st = 0; st < RelevantStyles[TagName].length; st++){
StyleString += RelevantStyles[TagName][st] + ":" + StyleDef.getPropertyValue(RelevantStyles[TagName][st]) + "; ";
}
Child.setAttribute("style",StyleString);
}
}
}
function export_StyledSVG(SVGElem){
var oDOM = SVGElem.cloneNode(true)
read_Element(oDOM, SVGElem)
var data = new XMLSerializer().serializeToString(oDOM);
var svg = new Blob([data], { type: "image/svg+xml;charset=utf-8" });
var url = URL.createObjectURL(svg);
var link = document.createElement("a");
link.setAttribute("target","_blank");
var Text = document.createTextNode("Export");
link.appendChild(Text);
link.href=url;
document.body.appendChild(link);
}