2011-03-05 19 views
10

Estoy trabajando en una aplicación web usando SVG & JS. Las cosas van bien, pero estoy un poco confundido por el manejo de datos.Accediendo a los datos de SVG a través de JavaScript

Los datos para los objetos que los usuarios crean se añaden dinámicamente a la raíz SVG. Donde & cómo se almacenan estos datos SVG, & ¿cómo puedo acceder a él? La razón por la que quiero leerlo es que quiero convertir estos datos SVG en un lienzo HTML5 (usando el canvg de Google) y finalmente convertir eso en una imagen png para que se almacene en nuestro archivo db como referencia.

Cualquier orientación sería muy apreciada.

Respuesta

19

Cuando un navegador web carga un archivo SVG, analiza (aproximadamente) la secuencia de bytes y crea una estructura DOM en la memoria para el archivo SVG. Es esta representación en memoria que se modifica cuando el script crea dinámicamente y agrega nuevos elementos al documento.

Se puede ver un ejemplo muy simple de esto aquí:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
El SVG carga el archivo con un círculo en el fondo de la cara, y luego JavaScript crea dinámicamente los ojos y la nariz y los añade como hijos de la Elemento SVG.

Hay tres maneras que sé de los que puede acceder esta información y ponerlo en un lienzo:

  1. Se puede caminar el DOM de los elementos a sí mismo, y los comandos de dibujo contexto lienzo tema:

    var svg = document.getElementsByTagName('svg')[0]; 
    var kids = svg.childNodes; 
    for (var i=0,len=kids.length;i<len;++i){ 
        var kid = kids[i]; 
        if (kid.nodeType!=1) continue; // skip anything that isn't an element 
        switch(kid.nodeName){ 
        case 'circle': 
         // ... 
        break; 
        case 'path': 
         // ... 
        break; 
        // ... 
        } 
    } 
    

    Consulte el SVG DOM reference para obtener más información sobre las propiedades y los métodos disponibles, o simplemente utilice los métodos DOM 2 Core para obtener propiedades. Para simplificar, es posible que desee utilizar el último.

    Por ejemplo, puede acceder a la actual (no SMIL animada) cx del círculo utilizando el SVG DOM a través de var cx = kid.cx.baseVal.value; o simplemente puede hacer var cx = kid.getAttribute('cx');.

    Esto va a ser sencillo donde SVG y Canvas tienen comandos similares (por ejemplo rect o line), un poco de trabajo en los que no coinciden exactamente (por ejemplo circle frente arcTo, polyline como una serie de comandos lineTo) y mucho trabajo para el elemento path y su many drawing commands.

  2. por this answer y this paper, utilizar la interfaz XMLSerializer para obtener el SVG atrás como el marcado, el uso que directamente como la fuente de una img, y luego drawImage que a la lona. Utilizando el ejemplo anterior:

    var svg_xml = (new XMLSerializer).serializeToString(svg); 
    console.log(svg_xml); 
    // "<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" viewBox="-350 -250 700 500"> 
    // <circle r="200" class="face" fill="red"/> 
    // <path fill="none" class="face" transform="translate(-396,-230)" d="M487.41,282.411c-15.07,36.137-50.735,61.537-92.333,61.537   c-41.421,0-76.961-25.185-92.142-61.076"/> 
    // <circle cx="-60" cy="-50" r="20" fill="#000"/> 
    // <circle cx="60" cy="-50" r="20" fill="#000"/> 
    // </svg>" 
    var ctx = myCanvas.getContext('2d'); 
    var img = new Image; 
    img.onload = function(){ ctx.drawImage(img,0,0); }; 
    img.src = "data:image/svg+xml;base64,"+btoa(svg_xml); 
    

    Si tiene SVG en XHTML (como en mi ejemplo), la serialización no capturará estilos definidos fuera del bloque SVG (como en mi ejemplo) y por lo que no será aplicada en la imagen.

    Tenga en cuenta que por this question/answer (el mío), debe establecer el atributo onload antes se ajusta el src a la URL de datos si desea que la compatibilidad de IE9.

    Desafortunadamente, debido a lo que puede o no ser a bug, una imagen-url datos de dibujo a un lienzo hace que la bandera de origen limpio para ajustarse a false, lo que significa que no vas a ser capaz de llamar toDataURL() en el lienzo y recuperar su PNG. Entonces ...

  3. Supongo que para sus necesidades específicas de SVG-modificado por el cliente-> Canvas-> PNG-on-server necesitará usar el primer paso anterior para serializar el svg_xml y luego pasar esa fuente sin procesar a canvg.

Alternativamente, usted podría considerar la serialización de SVG por lo anterior y la presentación que directamente a su servidor y haciendo server-side SVG-to-PNG conversion.

+0

Eso está maravillosamente explicado. Muchas gracias Phrogz. – Kayote

+0

espléndida respuesta !! Se puede también señalar por qué algo así como * var SVG = document.getElementById ('SVG') * no trabajará ...... –

+0

@KeyBrdBasher que trabajará acaba de encontrar, suponiendo que tiene ' 'en tu página. Puede usar 'getElementsByTagName ('SVG') [0] 'si no tiene un ID, o más simplemente (en los navegadores modernos)' SVG var = document.querySelector ('SVG') '. – Phrogz

1

El error mencionado en la respuesta webkit @Phrogz parece haber sido corregido en las versiones más recientes, así que encontré una solución que no requiere un análisis sintáctico manual es

// from http://bl.ocks.org/biovisualize/1209499 
// via https://groups.google.com/forum/?fromgroups=#!topic/d3-js/RnORDkLeS-Q 
var xml = d3.select("svg") 
    .attr("title", "test2") 
    .attr("version", 1.1) 
    .attr("xmlns", "http://www.w3.org/2000/svg") 
    .node().parentNode.innerHTML; 

// from http://webcache.googleusercontent.com/search?q=cache:http://phpepe.com/2012/07/export-raphael-graphic-to-image.html 
// via http://stackoverflow.com/questions/4216927/problem-saving-as-png-a-svg-generated-by-raphael-js-in-a-canvas 
var canvas = document.getElementById("myCanvas") 
canvg(canvas, svgfix(xml)); 
document.location.href = canvas.toDataURL(); 

que requiere https://code.google.com/p/svgfix/ y https://code.google.com/p/canvg/ y usa d3.js para obtener la fuente svg, que también debería ser factible sin d3.js (pero esto se encarga de agregar los metadatos requeridos que pueden ocasionar problemas cuando faltan).

Cuestiones relacionadas