在浏览器中生成、查看和保存 SVG 客户端

2024-01-12

我正在编写一个 HTML5+JS 的小工具来生成 SVG 图像。我在这样做时遇到了很多问题,虽然我对大多数问题都有解决方法,但至少在一种情况下,我觉得必须有更好的方法。还有一些事情仍然只是aren't在职的。

目前,这是我自己使用的,因此跨浏览器兼容性不是问题;只要它能在 Firefox(首选)或 Chromium 中运行,就没有问题。不过,一旦它工作正常,我想将其放在网上,因此兼容性警告将不胜感激。

Goals

  1. 所有处理都应在客户端完成;事实上,现阶段一切都是本地化的file://,不涉及网络服务器。
  2. 使用脚本化表单元素将文本和元素添加到 SVG 图像(内嵌在 HTML 中)。
  3. 单击 SVG(缩小到“预览”大小)以在新窗口/选项卡中打开修改后的它。
  4. 使用一些易于访问的方法(即不是“DOM 检查器、复制到文本文件、保存”)将 SVG 保存到磁盘。

测试用例

https://gist.github.com/perey/1d352a790f749aa05a8b https://gist.github.com/perey/1d352a790f749aa05a8b (看到它的实际应用 http://htmlpreview.github.io/?https://gist.github.com/perey/1d352a790f749aa05a8b/raw/212a1b3bcf03bc7937837768089865da94075934/svg-test.html)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <meta charset="utf-8"/>
    <title>SVG Generator</title>
    <style type="text/css">
      figure {
        width: 45%;
        float: right;
      }
      #output-pic {
        border: thin solid green;
        cursor: pointer;
      }
      form {
        width: 45%;
        float: left;
      }
    </style>
    <script>
      window.onload = function() {
        document.getElementById("input-box").oninput = update_text;
        document.getElementById("output-pic").onclick = show_svg;
        update_text();
      }
      function update_text() {
        var input_elem = document.getElementById("input-box");
        var output_elem = document.getElementById("changeable-text");
        output_elem.textContent = input_elem.value;
      }
      function show_svg() {
        var svg_win = window.open("", "svg_win");
        var embedded_svg = document.getElementById("output-pic");
        var transplanted_svg = svg_win.document.importNode(embedded_svg, true);
        var blank_root = svg_win.document.documentElement;
        svg_win.document.removeChild(blank_root);
        svg_win.document.appendChild(transplanted_svg);
      }
    </script>
  </head>
  <body>
    <figure role="img" aria-labelledby="preview-caption">
      <figcaption id="preview-caption">Preview <small>(click for full
        size)</small></figcaption>
      <svg id="output-pic"
           xmlns="http://www.w3.org/2000/svg"
           xmlns:xlink="http://www.w3.org/1999/xlink"
           version="1.1" width="640px" height="480px"
           viewBox="0 0 640 480" preserveAspectRatio="xMinYMin">
        <title>A test SVG file</title>
        <defs>
          <style type="text/css">
            text {
              font-family: serif;
              stroke: none;
              fill: red;
            }
            .underline {
              stroke: blue;
              stroke-width: 1;
              fill: none;
              marker-mid: url(#arrow);
            }
          </style>
          <marker id="arrow"
                  viewBox="-3 -3 6 6" orient="auto"
                  markerUnits="strokeWidth"
                  refX="0" refY="0"
                  markerWidth="6" markerHeight="6">
            <path d="M0,0 -3,-3 3,0 -3,3 Z"/>
          </marker>
        </defs>
        <text id="changeable-text" text-anchor="middle" font-size="40"
              x="320" y="240"></text>
        <path class="underline" d="M10,250 h310 310"/>
      </svg>
    </figure>
    <form>
      <label>Text: <input id="input-box"/></label>
    </form>
  </body>
</html>

Issues

打开 SVG

Opening about:blank,删除它的 document 元素,并添加 SVG 元素,感觉真的很hacky。然而,没有其他方法我只是找到了一种在新窗口中构建文档的稍微好一点的方法(见下文)。

特别是,我尝试加载准系统 SVG 文件并添加预览 SVG 的所有子节点,如下所示:

function show_svg() {
    var svg_win = window.open("blank.svg", "svg_win");
    var embedded_svg = document.getElementById("output-pic");
    var transplanted_svg = svg_win.document.importNode(embedded_svg, true);
    var blank_root = svg_win.document.documentElement;

    while (transplanted_svg.hasChildNodes()) {
        blank_root.appendChild(transplanted_svg.firstChild);
    }
    svg_win.alert("Done!");
}

但是,在该函数执行其操作后,加载的文件将“擦除”对其所做的所有更改并恢复到其原始状态。 (这alert是为了强调这个事实:在 Firefox 中,当页面被“擦除”时,无需用户操作,警报框本身就会消失。在 Chromium 中,警报框会悬而未决,但擦除会在其关闭后发生。)

这不是将节点重新定位到新窗口的问题onload处理程序。是的。当我第一次尝试时我犯了一个错误。这就是我所做的:

function show_svg() {
    var svg_win = window.open("blank.svg", "svg_win");
    var embedded_svg = document.getElementById("output-pic");
    var transplanted_svg = svg_win.document.importNode(embedded_svg, true);
    var blank_root = svg_win.document.documentElement;

    svg_win.onload = function () {
        while (transplanted_svg.hasChildNodes()) {
            blank_root.appendChild(transplanted_svg.firstChild);
        }
        svg_win.alert("Done!");
    }
}

What I 应该完成了定义blank_root inside the onload处理程序。这样可行。

不过,仍然感觉应该有一种方法可以从头开始构建新文档。 “修改空白 SVG”比“修改about:blankHTML”,但这真的是最好的方法吗?

缺少标记

(这似乎只是 Firefox 的问题,而不是 Chromium 的问题。)

The marker-mid样式在预览图像中工作正常,但在打开的 SVG 中则不然。我不知道为什么。Edit:修改 SVG 文件而不是about:blank没有这个问题。我准备提交一个 bug,但我已经怀疑他们会说“不要尝试将 HTML 文件动态转换为 SVG 文件”。

保存生成的 SVG

我不知道该怎么做。一些诱人的提示似乎表明这与 Blob 有关,但我没有发现任何可以解决在客户端保存生成的 SVG 文件的问题,而且我不明白他们做得足够好以使其适用于我。

有什么帮助、建议、忠告或更正吗?


我已经使用现代 HTML5 API 解决了自己的问题。

The new show_svg()函数看起来像这样:

function show_svg(evt) {
    var svg = document.getElementById("output-pic");
    var serializer = new XMLSerializer();
    var svg_blob = new Blob([serializer.serializeToString(svg)],
                            {'type': "image/svg+xml"});
    var url = URL.createObjectURL(svg_blob);

    var svg_win = window.open(url, "svg_win");
}

浏览器自己的保存功能将在这个新窗口上运行,并且它不涉及对“感觉”奇怪或黑客的其他文件的任何修改。 (序列化 SVG 只是为了再次在浏览器中查看它似乎有点奇怪,但这似乎是 HTML5 下的正确做法。)

唯一未解决的问题是标记消失——事实上,问题变得更糟,就像现在一样<use>元素也不起作用!然而,它们仍然存在并且在代码中起作用,因此一旦将 SVG 保存到文件中,文件中的所有内容都可以正常工作。我也向 Mozilla 提交了一个错误。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在浏览器中生成、查看和保存 SVG 客户端 的相关文章

随机推荐

  • 包含多种 Java 类型的表上的 DynamoDBMapper

    我有一个 DynamoDB 表 其中包含不止一种类型的逻辑实体 我的表存储 员工 和 组织 并在两者之间创建多对多关系 我正在努力解决如何使用 DynamoDBMapper 对实体和表进行建模 特别是在尝试编写将返回员工和组织的查询时 在我
  • 如何从phonegap android插件返回数组或其他集合元素类型

    这是我在 java 插件中测试代码的一部分 我正在使用phonegap 2 7 public boolean execute String action JSONArray args CallbackContext callbackCont
  • Requirejs - 在加载 data-main 之前配置 require

    我们第一次使用 requirejs 我在构建依赖项时遇到了麻烦 我已将主 app js 文件定义为 index html 中的 data main 属性 但是 我有一个文件定义了所有需要的路径 垫片配置 并且我希望它在 app js 文件之
  • 我可以使用 git 的脚本化提交模板吗?

    我们正在处理票证 当我们在第一行的 git 提交消息中使用票证编号时 票证就会使用提交消息进行更新 为了简单起见 我们总是在带有提交号的分支上工作 现在我想看到一条提交消息 其中票号已被填写 这一定是可能的 因为分支已经在提交模板中 但在被
  • 高效的弦修剪

    我有一个String价值 我想要trim https doc rust lang org stable std string struct String html method trim它 我可以做类似的事情 let trimmed s t
  • 计算每列中空值的数量

    我遇到过一个数据库 其表太宽 600 列 即使在没有参数的情况下询问前 100 行也需要 4 秒 我想把这些桌子缩小一点 为了弄清楚哪些列可以最容易地移动到新表或完全删除 我想知道每列中有多少个空值 这应该告诉我哪些信息可能最不重要 我将如
  • 何时将我的项目拆分为多个 C 文件? (大型项目的良好实践)[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我现在正在做一个C语言的大项目 我正在做其中的特定部分 另一个是由其他人完成的 我想知道什么时候应该将我的项目拆分为多个c文件 以及编写的最佳实
  • 使用 XOM 在具有默认命名空间的 xml 上应用 xpath

    我有下面的 XML 其中包含默认名称空间
  • 从字典列表中获取最后更新的字典消息

    我正在尝试从数据流中获取实体的最新更新消息 数据以字典列表的形式出现 其中每个字典都是实体的更新消息 我只需要该实体的最新更新 我的输入是一个字典列表 输出需要是一个字典的字典 注意 仅长度更新 类别保持静态 我知道哪一个是最新更新 因为对
  • 芹菜与亚马逊 SQS

    我想用亚马逊SQS http aws amazon com sqs 作为经纪人支持Celery http celeryproject org SQS 传输实现Kombu https github com ask kombu Celery 依
  • 将 url 和 hash 与 Bootstrap ScrollSpy 一起使用

    我有一个基于 twitter bootstrap 的导航菜单栏 我想应用滚动间谍来突出显示 我使用普通的 php include 将菜单包含到多个页面中 因此我使用文件名加书签链接到文件 例如 products php foo 但滚动间谍希
  • Angular 2—更改组件选择器

    The Angular 2 文档 https angular io docs ts latest guide displaying data html假设要定义这样的组件 使用魔术字符串作为选择器名称 import Component fr
  • 查找另一个字段mongodb的不同值组

    我收集了这样的文件 id ObjectId 5c0685fd6afbd73b80f45338 page id 1234 category list football sport time broadcast 09 13 id ObjectI
  • IOS越狱如何拦截短信/短信

    我目前正在尝试编写一个应用程序来拦截文本消息并根据该消息的内容做出反应 我试图挂钩 receivedMessage struct CKSMSRecord message replace BOOL replaceCKSMSService 类中
  • HTML 标签正在转换

    我有以下代码片段来获取存储在数据库表中的 XML 数据的输出 ServletOutputStream os response getOutputStream String contentDisposition attachment file
  • Android NDK:为什么 ndk-build 不在 Eclipse 中生成 .so 文件和新的 libs 文件夹?

    我按照本教程的步骤进行操作 http mindtherobot com blog 452 android beginners ndk setup step by step http mindtherobot com blog 452 and
  • python:如何绘制以节点为中心的二维不连续数据?

    我有一个二维数据和二维四边形网格 描述了细分为补丁的域 数据在每个网格节点处定义 数据中的不连续性存在于补丁边界处 即数据在同一位置处被多重定义 如何使用 Python 绘制这些数据 并在节点之间进行线性插值并正确表示沿每个面片面的不连续值
  • 将数据库作为 Docker 容器运行还是在裸机服务器上运行?

    数据库被设计为消耗所有可用的内存 CPU 和 IO Docker 不应该用于生产中的数据库是否有好的 坏的原因 可能这个问题也适用于其他工具 例如 MOM Apache Kafka Apache ActiveMQ 等 Docker 不是一个
  • PHP pthread 似乎不是多线程

    如果可能的话请提供帮助 我打算从数据库中提取 X 行 将它们分成 20 个数组的数组 并将它们传递给一个线程以同时处理 为了确保该进程同时工作 我创建了一个快速线程 该线程回显线程号 然后计数到 20 我期望看到类似 1 at 1 然后 2
  • 在浏览器中生成、查看和保存 SVG 客户端

    我正在编写一个 HTML5 JS 的小工具来生成 SVG 图像 我在这样做时遇到了很多问题 虽然我对大多数问题都有解决方法 但至少在一种情况下 我觉得必须有更好的方法 还有一些事情仍然只是aren t在职的 目前 这是我自己使用的 因此跨浏