通过JavaScript访问SVG数据

时间:2011-03-05 04:56:33

标签: javascript html5 canvas svg

我正在使用SVG& amp; JS。事情进展顺利,但我对数据处理感到有些困惑。

用户创建的对象的数据会动态附加到SVG根目录。哪里&这个SVG数据是如何存储的,&我怎么才能访问它?我想要阅读它的原因是我想将这个SVG数据转换为HTML5画布(使用Google的canvg)并最终将其转换为png图像以存储在我们的数据库中以供参考。

非常感谢任何指导。

2 个答案:

答案 0 :(得分:20)

当Web浏览器加载SVG文件时,它(粗略地)解析字节流并在内存中为SVG文件创建DOM结构。当脚本动态创建并向文档追加新元素时,会修改此内存中表示。

你可以在这里看到一个非常简单的例子:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
SVG文件在脸部的背景中加载一个圆圈,然后JavaScript动态创建眼睛和鼻子,并将它们作为SVG元素的子项附加。

我知道有三种方法可以访问这些信息并将其放入画布中:

  1. 您可以自己遍历元素的DOM,并发出画布上下文绘制命令:

    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;
        // ...
      }
    }
    

    有关可用属性和方法的更多信息,请参阅SVG DOM reference,或者只使用DOM 2 Core方法获取属性。为简单起见,您可能希望使用后者。

    例如,您可以通过cx使用SVG DOM访问圈子的当前(非SMIL动画)var cx = kid.cx.baseVal.value;,或者您可以更简单地执行var cx = kid.getAttribute('cx');

    这很简单,SVG和Canvas有类似的命令(例如rectline),这是一些他们不完全匹配的工作(例如circlearcTopolyline作为一系列lineTo命令),以及path元素及其many drawing commands的大量工作。

    < / LI>
  2. 根据this answerthis paper,使用XMLSerializer界面将SVG作为标记返回,直接将其用作img的来源,并且然后drawImage到画布。使用上面的例子:

    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);
    

    如果你在XHTML中有SVG(如我的例子),序列化将不会捕获在SVG块之外定义的样式(如我的例子中所示),因此它们不会应用于图像中。

    请注意,根据this question/answer(我的),如果您希望IE9兼容,则必须在之前设置onload属性,然后将src设置为数据网址

    不幸的是,由于a bug可能有或没有,将数据网址图像绘制到画布会导致原点清理标记设置为false,这意味着您不会能够在画布上调用toDataURL()并恢复你的PNG。所以...

  3. 我想根据您对客户端修改的SVG-&gt; Canvas-&gt; PNG-on-server的特定需求,您需要使用上面的第一步来序列化svg_xml,然后传递原始来源为canvg

  4. 或者,您可以考虑按照上述顺序对SVG进行序列化,并将其直接提交到您的服务器并执行server-side SVG-to-PNG conversion

答案 1 :(得分:1)

@Phrogz回答中提到的webkit bug似乎已在更新版本中得到修复,因此我找到了一个不需要手动解析的解决方案

// 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();

需要 https://code.google.com/p/svgfix/https://code.google.com/p/canvg/并使用d3.js来获取svg源代码,这也应该在没有d3.js的情况下可行(但这需要添加必需的元数据,这可能会在丢失时导致问题)。