通过 JavaScript 访问 SVG 数据

发布于 2024-10-20 19:24:51 字数 305 浏览 1 评论 0 原文

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

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

任何指导将不胜感激。

I am working on a web application using SVG & JS. Things are going well but I am a bit confused by data handling.

The data for objects that users create is dynamically appended to the SVG root. Where & how is this SVG data stored, & how can I access it? The reason I want to read it is that I want to convert this SVG data into HTML5 canvas (using Google's canvg) and finally turn that into a png image to be stored in our db for reference.

Any guidance would be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

゛时过境迁 2024-10-27 19:24:51

当 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

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

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

    这将很简单,因为 SVG 和 Canvas 有类似的命令(例如 rectline),但它们不完全匹配时需要做一些工作(例如,circlearcTopolyline 作为一系列 lineTo 命令),并且为做了大量工作code>path 元素及其许多绘图命令

  2. 根据这个答案本文,使用 XMLSerializer 接口将 SVG 作为标记返回,直接将其用作 img 的源,然后将其 drawImage 绘制到画布上。使用我上面的例子:

    var svg_xml = (new XMLSerializer).serializeToString(svg);
    控制台.log(svg_xml);
    // "
    // 
    // <路径 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"/>
    // <圆 cx="-60" cy="-50" r="20" fill="#000"/>
    // <圆 cx="60" cy="-50" r="20" fill="#000"/>
    // "
    var ctx = myCanvas.getContext('2d');
    var img = 新图像;
    img.onload = function(){ ctx.drawImage(img,0,0); };
    img.src = "数据:image/svg+xml;base64,"+btoa(svg_xml);
    

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

    请注意,每个这个问题/answer(我的),如果您想要 IE9,则必须先设置 onload 属性,然后再将 src 设置为数据 URL兼容性。

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

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

或者,您可以考虑按照上述序列化 SVG 并将其直接提交到您的服务器并执行 服务器端 SVG 到 PNG 转换

When a web browser loads an SVG file, it (roughly) parses the stream of bytes and creates a DOM structure in memory for the SVG file. It is this in-memory representation that is modified when script dynamically creates and appends new elements to the document.

You can see a very simple example of this here:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
The SVG file loads with a circle in the background for the face, and then JavaScript dynamically creates the eyes and nose and appends them as children of the SVG element.

There are three ways I know of that you can access this information and get it into a canvas:

  1. You can walk the DOM of elements yourself, and issue canvas context drawing commands:

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

    See the SVG DOM reference for more information on the properties and methods available to you, or just use the DOM 2 Core methods to fetch properties. For simplicity, you might want to use the latter.

    For example, you can either access the current (non-SMIL animated) cx of the circle using the SVG DOM via var cx = kid.cx.baseVal.value; or you can more simply do var cx = kid.getAttribute('cx');.

    This is going to be simple where SVG and Canvas have similar commands (e.g. rect or line), a little bit of work where they don't match exactly (e.g. circle versus arcTo, polyline as a series of lineTo commands), and a lot of work for the path element and its many drawing commands.

  2. Per this answer and this paper, use the XMLSerializer interface to get the SVG back as markup, use that directly as the source of an img, and then drawImage that to the canvas. Using my above example:

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

    If you have SVG in XHTML (as in my example), the serialization will not capture styles defined outside of the SVG block (as in my example) and so they will not be applied in the image.

    Note that per this question/answer (mine), you must set the onload attribute before you set the src to the data URL if you want IE9 compatibility.

    Unfortunately, due to what may or may not be a bug, drawing a data-url image to a canvas causes the origin-clean flag to be set to false, which means that you will not be able to call toDataURL() on the canvas and get your PNG back. So...

  3. I suppose for your specific needs of Client-modified SVG->Canvas->PNG-on-server you will need to use the first step above to serialize the svg_xml and then pass that raw source to canvg.

Alternatively, you might consider serializing the SVG per the above and submitting that directly to your server and doing server-side SVG-to-PNG conversion.

浮云落日 2024-10-27 19:24:51

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

The webkit bug mentioned in @Phrogz answer seems to have been fixed in more recent versions, so I found a solution that doesn't require a manual parse is

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

which requires
https://code.google.com/p/svgfix/ and https://code.google.com/p/canvg/ and uses d3.js to obtain the svg source, which should be doable without d3.js as well (but this takes care of adding required metadata which can lead to problems when missing).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文