【问题标题】:Accessing the SVG data through JavaScript通过 JavaScript 访问 SVG 数据
【发布时间】:2011-03-05 04:56:32
【问题描述】:

我正在使用 SVG 和 JS 开发一个 Web 应用程序。事情进展顺利,但我对数据处理有点困惑。

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

任何指导将不胜感激。

【问题讨论】:

    标签: javascript html canvas svg


    【解决方案1】:

    当网络浏览器加载 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 方法来获取属性。为简单起见,您可能希望使用后者。

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

      在 SVG 和 Canvas 具有相似命令(例如 rectline)的情况下,这将很简单,在它们不完全匹配的情况下进行一些工作(例如,circlearcTo,@ 987654339@ 作为一系列lineTo 命令),以及path 元素及其many drawing commands 的大量工作。

    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(我的),您必须设置onload 属性之前如果您想要IE9 兼容性,您将src 设置为数据URL。

      不幸的是,由于 a bug 可能是也可能不是,将 data-url 图像绘制到画布会导致 origin-clean 标志设置为 false,这意味着您将无法调用toDataURL() 在画布上并取回您的 PNG。所以...

    3. 我想为了您对客户端修改的 SVG->Canvas->PNG-on-server 的特定需求,您需要使用上面的第一步来序列化 svg_xml,然后将该原始源传递给 @ 987654329@.

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

    【讨论】:

    • 精彩回答!!你能否指出为什么像 var svg = document.getElementById('svg') 这样的东西不起作用......
    • @KeyBrdBasher 假设您的页面上有&lt;svg id="svg"&gt;,那么只需找到即可。如果您没有 ID,则可以使用 getElementsByTagName('svg')[0],或者更简单(在现代浏览器上)var svg = document.querySelector('svg')
    【解决方案2】:

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

    // 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 的情况下也应该是可行的(但这需要添加必要的元数据,这可能会在丢失时导致问题)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      • 1970-01-01
      • 2015-04-25
      • 1970-01-01
      • 2016-01-08
      • 1970-01-01
      相关资源
      最近更新 更多