【外评】SVG:好的、不好的、糟糕的
SVG 是 “可缩放矢量图形 “的简称,是一种可缩放矢量图形的格式。在这篇文章中,我总结了我对这种格式的看法、它存在的问题,并提出了改进的建议。
SVG 是 “可缩放矢量图形 “的简称,是一种可缩放矢量图形的格式。在这篇文章中,我总结了我对这种格式的看法、它存在的问题,并提出了改进的建议。
几年来,我一直在使用 SVG 和 Inkscape 绘制草图和图形,并喜欢用手写的方式来满足我对精确性和代码艺术的热爱。我和 SVG 有一种爱恨交织的关系。它功能强大,拥有一些不错的免费开源工具,但格式本身非常丑陋。
优点
- 它是矢量图形的格式。从 Adobe Illustrator 到 Inkscape 等一系列程序都很好地支持这种格式,可用于编辑和在各种浏览器中使用。
- 它是一种网络标准,因此可以直接在网站中使用。您还可以使用 CSS。
- 它以 XML 为基础,因此语法非常熟悉,具有可扩展性,可以从庞大的 XML 生态系统中受益。例如,使用 XLink 可以引用 SVG 文件中的其他元素和定义。或者 Inkscape 使用自定义 XML 标记将 SVG 扩展为其编辑器交换格式。
- 它功能强大。你可以用它做很多事情。显然,它支持各种路径类型和形状,支持文本等,还支持动画、渐变、特效等。
缺点
这是一种网络标准。按照网络标准的惯例,SVG 非常臃肿。SVG 规范的页面多达 826 页。如果这还不够,它还基于 XML 并与其他网络标准交叉链接,使任何实施范围都达到令人眼花缭乱的高度。
如果要确保正确呈现所有 SVG 文件,不仅要考虑 800 页的 SVG 规范,还要考虑另外 20 页的 XLink 规范。对了,还有 CSS。还有 JAVASCRIPT。没错。SVG 文件可以包含 <script> 标记。
SVG 非常适合网络浏览器。浏览器已经臃肿得令人发指,它们已经实现了 CSS 和 JavaScript 等 SVG 完全实现所需的功能。SVG 的问题实际上就是整个网络的问题。它的范围巨大、臃肿且难以使用。
SVG 不是一天就能实现的。或者一周。或者一个月。大量的规范通常只实现了一部分,因此很难概述哪些规范支持哪些规范,这让用户无所适从,不知道如果他们想让自己的 SVG 文件得到普遍支持,究竟可以使用哪些功能。
此外,基于 XML 的语法非常难看,而且冗长无用。手写很累,解析或自动生成也一样累。
糟糕的地方
从以上几点中可以总结出一个核心问题,这就是我在关于机器与人类语言设计的文章中详细阐述的问题:SVG 不知道自己想做什么,是以机器为中心的语言还是以人类为中心的语言,结果在这两方面都做得很糟糕。
它是一种机器可处理的语言吗?它太臃肿了。为 SVG 编写解析器、呈现器和生成器是一项艰巨的任务。语法重复而复杂。它有很多功能可以用更基本的功能来表示。
但它是一种适合人类直接使用的格式吗?当然不是。首先,冗长的语法和复杂性也不利于人类用户使用。其次,它缺少很多适合直接使用的功能。适合人类直接使用的图形语言应该是 LaTeX 的 TikZ。虽然在我看来,就用户体验而言,它并不是一种很好的语言,但它绝对是为人类设计的,并具有帮助轻松创建复杂图形的必要功能。但是没有人会想到使用 TikZ 代码作为图形成品的交换格式。没有人会愿意为了查看某个图形而编写 1300 页的 TikZ 手册。取而代之的是将其编译成 PDF 格式(这也是一种可怕的格式,而且非常臃肿,不过还好)。如果 SVG 是一种供人类使用的语言,那么将其编译成以机器为中心的格式也是一种方法,但正如我所说–它不是。两者都不是。
现在怎么办?
一个好主意是开发一种简单的矢量图形交换格式,使机器能够轻松处理。尽可能减少功能。也许可以基于 JSON,但绝对不能基于 XML。你应该能在几天甚至几小时内实现一个基本的渲染器,而不需要依赖两吨重的 XML 生态系统库。贝塞尔曲线、椭圆曲线、填充、轮廓和渐变效果应该足以表现所有一致的 SVG。通过扩展,可以在单独的文件扩展名中添加动画。
这样,这种最小化、限制明确的格式就可以有一个严格的测试套件,并相对容易地在浏览器和图像查看器中实现。用户可以在任何地方使用他们的图形,实施者也不必担心 XLink、CSS 和 JavaScript 的实施。它可以节省带宽和计算能力。还可以编写 SVG 的编译器,以实现兼容性。
它可以作为 Inkscape 或 Adobe Illustrator 等面向用户的程序的导出格式。对于希望通过代码标记图形的人来说,TikZ、Haskell diagrams 或 Python matplotlib 等程序也可以导出为新的最小交换格式。
实际上,我正在考虑制作一种以机器为中心的超薄矢量图形格式(有人建议命名为 “SlimSVG”:D),并编写我自己的以人类为中心的 Haskell 图形创建库,以在未来实现我自己的类似目标,或许作为大学的一个学生研究项目。
总之:决定一门语言是为人类还是为机器准备的,然后做其中一件事。并做好其中一件事,而不是两件事都做,但做不好。
更新 1:这篇文章发布在 Hacker News 上,并登上了首页,目前排在第 3 位。我很荣幸!在评论中,有人提到了在 SVG 中使用 <script> 标签的有趣方法。我不知道自己是该感到惊叹还是该感到恐惧:D
更新 2:有人也在 Reddit 上发布了这个帖子。目前,已有 150 多条评论,哇哦。
更新 3:大家请注意。这绝对不是在说 “XML 不好,我们改用 JSON 吧”。实际上,相比 JSON,我更喜欢 XML,我是 XML 模式和强大模式的粉丝。虽然我仍然不喜欢 XML 的语法,但一般来说,它非常适合 HTML 这样的文档标记语言。我并不关心具有良好数据模型的格式是用 JSON、XML、YAML、二进制、Brainfuck 还是猴子粪便编码的。编码确实是最不重要的部分。我只是认为,对于严格以机器为中心的数据格式而言,JSON 会是一个更好的选择。
我想我早该料到,说我不喜欢 XML,然后提到 “JSON “这个词,会引发一场宗教战争。
本文文字及图片出自 SVG: The Good, the Bad and the Ugly
你也许感兴趣的:
- 用交互式动画帮你理解SVG绘制弧线,二次、三次贝塞尔曲线
- 将 Linux 终端会话录制成 SVG 动画
- [译] 使用 SVG 符号和 CSS 变量实现多彩图标
- 【外评】电脑从哪里获取时间?
- 【外评】为什么 Stack Overflow 正在消失?
- Android 全力押注 Rust,Linux 却在原地踏步?谷歌:用 Rust 重写固件太简单了!
- 【外评】哪些开源项目被广泛使用,但仅由少数人维护?
- 【外评】好的重构与不好的重构
- C 语言老将从中作梗,Rust for Linux 项目内讧升级!核心维护者愤然离职:不受尊重、热情被消耗光
- 【外评】代码审查反模式
>此外,基于 XML 的语法非常难看,而且冗长无用。手写很累人,解析或自动生成也一样累人。
更糟糕的是,由于 XML 是一种垃圾格式,SVG 实际上建立了自己的微型-DSL 来解决各种限制。
因此,举例来说,你可以写出以下内容
<circle cx="10" cy="10" r="2" fill="red"/>。
好吧,够公平。可读,自我描述。
但你还有
<path d="M 10 10 H 90 V 90 H 10 L 10 10"/>。
哦。你几乎可以听到设计者在说:”好吧,去他妈的,我们就把它全部塞进一个字符串里吧。
基于 SGML 的格式能够如此流行,确实证明了软件工程中存在着一些根本性的问题。
不过,我还是挺喜欢 SVG 的。我的意思是,如果用 CSS 作图是另一种选择,那它就太神奇了。我也不太同意说它很难通过编程生成,你只需要决定你需要的格式的子集,看看 inkscape 能生成什么,然后从那里开始。如果你需要生成基本形状,那就相当简单了。
我迫不及待地想看到改进后的 JSON 版本:
{"path":{"d":["m", 10, 10, "h", 90, "v", 90, "h", 10, "l", 10, 10]}}
既然是 HN,我就要指出,s 表达式要优越得多:
(path (d (M 10 10) (H 90) (V 90) (H 10) (L 10 10)))
您的意思可能是
(path d M 10 10 H 90 V 90 H 10 L 10 10)
通过模式匹配为命令设置一些嵌套,返回一个路径结构:
This is the TXR Lisp interactive listener of TXR 251.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
Garbage collection is on Tuesdays: bring unwanted pointers to curb by 7:30.
1> (defstruct path () name args)
#<struct-type path>
2> (defun parse-path-args (args)
(match-case args
((M @x @y . @rest) ^((M ,x ,y) ,*(parse-path-args rest)))
((L @x @y . @rest) ^((L ,x ,y) ,*(parse-path-args rest)))
((H @x . @rest) ^((H ,x) ,*(parse-path-args rest)))
((V @x . @rest) ^((V ,x) ,*(parse-path-args rest)))
(())
(@else (error "bad path arguments: ~s" else))))
parse-path-args
3> (defun-match parse-path
(((path @(symbolp @name) . @args))
(new path name name args (parse-path-args args)))
((@else) (error "bad path syntax: ~s" else)))
parse-path
4> (parse-path '(path d M 10 10 H 90 V 90 H 10 L 10 10))
#S(path name d args ((M 10 10) (H 90) (V 90) (H 10) (L 10 10)))
Error cases:
5> (parse-path '(path d M 10 10 H 90 V 90 X 10 L 10 10))
** bad path arguments: (X 10 L 10 10)
** during evaluation of form (error "bad path arguments: ~s"
else)
** ... an expansion of (progn (error "bad path arguments: ~s"
else))
** which is located at expr-2:2
** run with --backtrace to enable backtraces
6> (parse-path '(paath d M 10 10 H 90 V 90 X 10 L 10 10))
** bad path syntax: paath d M 10 10 H 90 V 90 X 10 L 10 10
** during evaluation of form (error `bad path syntax: @else`)
** ... an expansion of (progn (error `bad path syntax: @else`))
** which is located at expr-3:1
** run with --backtrace to enable backtraces
我觉得太平了。宽度之类的地方不好放。我觉得你应该这样设计
(path (M 10 10 H 90 V 90 H 10 L 10 10) :color red)
不过,如果可能的话,我可能更喜欢嵌套的方式,这样你就能得到一个指令列表,而不需要从一个扁平化列表中进行解析。对于颜色或笔画宽度等属性,我可能会使用 alist 而不是 plist。
更胜一筹:
path 10 10 M 90 H 90 V 10 H 10 10 L #000 stroke
我知道你在开玩笑,但我还是不明白为什么 (+ x y) 是个好主意:很明显,第一个参数与另一个参数的含义不同,在我看来 +(x y) 更能显示操作与参数之间的区别。
这大大增加了语法的复杂性,因为现在嵌套函数调用需要其父函数的上下文才能形成 AST 节点。S-exps 是 AST 的字面表示,可以方便地修改和检查代码,例如通过宏。这与其说是 “第一个元素很重要”,不如说是 “这是一个函数的约定俗成的样子,因此你可以把它作为一个单独的列表来传递和修改”。
我只是半开玩笑。不同的符号各有利弊,但 s 表达式的好处是简单。列表可以是一个表达式(+ x y),也可以是一个列表,如(红蓝绿),空列表可以写成()。它基本上是最简单的结构化符号。
+(x y) 对于表达式来说很好,但对于事物列表来说就很奇怪了。
path:
d:
M: 10, 10
H: 90
V: 90
H: 10
L: 10, 10
Just beautiful.
不对,应该是数组。使用哈希数组就不会保留顺序,重复的键也会被删除。(假设这是 Yaml)。
很明显,规范的一部分就是要说明它是有序和非唯一的,如果你期待的是标准的 Yaml,那显然是你的错!
谢谢你指出了我的预期,让我更高兴了。
XML 怎么会是垃圾之火?与什么相比?另外,用文本简洁地表示路径本身就很复杂。你试图用线性的一维语法来表示一个非常二维的东西。这不是 XML 的限制,而是文本为一维的限制。
XML/SGML 是用一维字符串表示树形数据(同样是非一维数据)的一种非常有效的方法。而且它们具有极好的可扩展性,同时还能保持定义明确的模式。有没有更好的替代语言?如何更好?
> XML 如何成为垃圾之火?
如果您决定在”<path d=”M 10 10 H 90 V 90 H 10 L 10 10″/>”上使用完全的 XML,它可能会是这样的:
<path>
<point>
<x>10</x>
<y>10</y>
</point>
<point>
<x>90</x>
<y>10</y>
</point>
<point>
<x>90</x>
<y>90</y>
</point>
<point>
<x>10</x>
<y>90</y>
</point>
<point>
<x>10</x>
<y>10</y>
</point>
</path>
有人会说,XML 的设计者采用了 “M 10 10 H 90 V 90 H 10 L 10 10″,这表明他们认为 XML 太啰嗦。
simias 很可能也认为 XML 太啰嗦,并想知道他们为什么要使用 XML。
因为它很流行,尤其是在当时与网络开发相关的圈子里。而且当时还没有很多开放标准的可扩展通用结构化数据格式。(技术上,JSON 确实存在(作为 JavaScript 的一个子集),但直到 Crockford 将其命名后才广为人知。
XML 也不是没有好的想法。你可能不同意它的执行方式,但将独立标准定义的结构化数据无缝混合到一个文档中的想法是非常强大的。
另外,你的例子有点像稻草人:为单个坐标使用单独的元素是没有意义的,任何设计格式的人都知道这一点。一个更现实的例子是让 <path> 包含 <move-to x=”…” y=”…” /> 和 <line-to x=”…” y=”…” /> 元素的有序序列。(事实上,SVG 已经包含了 <line /> 和 <circle />,它们大致使用了这种结构)。
> 另外,你的例子有点像稻草人:使用单独的元素来表示各个坐标是没有意义的,设计格式的人都知道这一点。
你是这么说的,但下面是广泛使用的 “GPX “文件格式[1] 中的一些真实 XML 例子
<trkpt lat="47.644548" lon="-122.326897">
<ele>4.46</ele>
<time>2009-10-17T18:37:26Z</time>
</trkpt>
事实上,我本可以把 X 坐标作为一个属性,把 Y 坐标作为一个子元素,这样仍然可以公平地反映真实世界的 XML 文档。
而 GPX 是较好的 XML 格式之一!你想看噩梦般的 XML 吗?去看看 SAML 吧。
[1] https://en.wikipedia.org/wiki/GPS_Exchange_Format#Sample_GPX…
这些仍然是使用 XML 语法的蹩脚 DSL 的例子,而不是 XML 本身的具体问题。设计好的 DSL 是一个很难的问题,但在 JSON 或 YAML 中就不难吗?如果是这样的话,如果人们能提供具体的例子来说明为什么 XML 本身会导致糟糕的 DSL,那将会对我有所帮助。就目前的情况来看,我不禁要问,是否仅仅因为 XML 是(一直是)一种流行的格式,所以才会有这么多糟糕的 XML DSL。
与这一具体讨论相关的是,XML 在语法上对 “元素 “和 “属性 “进行了区分,但这种区分的目的往往并不明确(请搜索 “元素与属性”)。
JSON 和 YAML 则没有这种区分。
没错,但缺乏明确区分似乎也是特定 DSL 的弱点,而不是格式的弱点。HTML(除个别情况外)对属性和元素有非常明确的区分:属性用于元数据,元素用于可见的页面内容。Android 的 XML 也有类似的区分,属性用于描述视图的属性,元素用于描述子视图。
(我同意其他人的观点,即 “元素 “与 “属性 “的区别使得 XML 不适合用于序列化,但 XML 作为一种序列化格式在这里并不是真正的问题)。
XML 基于 SGML,而 SGML 最初是用来标记文本文档的,因此 TEXT 在 “节点万神殿”(Pantheon of Nodes)中被赋予了特殊的地位,甚至高于 “属性”(Attributes)。
因此,使用 XML 来表示数据结构而不是标记文本,可能会非常笨拙、低效和细微。
与可以包含 CDATA 的 TEXT 节点相比,XML 属性是二等公民,因为属性需要经过 “属性值规范化”(Attribute-Value Normalization)–换行、实体引用和空白都要规范化。换行符被规范化,前面和后面的空白被删除,重复的空白用单个空格代替。
SVG 路径属性(以及简单值,如数字、布尔值、枚举值等)不会受到属性值规范化破坏,因为它们不依赖于完美保留空白(当然是设计好的),所以可以放在属性中。
但是,如果你真的想保留一个字符串(如密码或任意字符串)的准确值,你应该在文本节点而不是属性中使用 <!CDATA[[ ]]> !
我想成为 <![CDATA[ https://donhopkins.medium.com/twenty-twenty-twenty-four-esca… ]]>
https://www.w3.org/TR/xml/#AVNormalize
3.3.3 属性值规范化
在将属性值传递给应用程序或进行有效性检查之前,XML 处理器必须通过应用以下算法或使用其他方法对属性值进行规范化处理,从而使传递给应用程序的值与算法产生的值相同。
所有换行符在输入到 #xA 时必须已按 2.11 行结束处理中的说明进行了规范化处理,因此本算法的其余部分将在按此方法规范化后的文本上运行。
以包含空字符串的规范化值开始。
对于非规范化属性值中的每个字符、实体引用或字符引用,从第一个开始一直到最后一个,执行以下操作:
对于字符引用,将引用的字符追加到规范化值中。
对于实体引用,对实体的替换文本递归应用此算法的第 3 步。
对于空白字符(#x20、#xD、#xA、#x9),将空格字符 (#x20) 追加到规范化值中。
对于其他字符,将该字符追加到规范化值中。
如果属性类型不是 CDATA,那么 XML 处理器必须进一步处理规范化属性值,丢弃任何前导和尾随空格 (#x20) 字符,并用单个空格 (#x20) 字符替换空格 (#x20) 字符序列。
请注意,如果非规范化属性值包含对空格(#x20)以外的空白字符的字符引用,则规范化值包含引用字符本身(#xD、#xA 或 #x9)。这与非规范化值包含空格字符(非引用)的情况不同,空格字符在规范化值中会被空格字符(#x20)替换,这也与非规范化值包含实体引用的情况不同,实体引用的替换文本包含空格字符;在递归处理过程中,空格字符在规范化值中会被空格字符(#x20)替换。
对于所有未读取声明的属性,非验证处理器应将其视为已声明的 CDATA 属性。
如果属性值包含对未读取声明的实体的引用,则属于错误。
一些最令人难以置信的糟糕 XML DSL 本身就是官方标准。COUGH XMLSchema COUGH
你应该读读詹姆斯-克拉克(James Clark)对官方 XML Schema (XSD) 标准的一些批评,这些批评促使他开发了 TREX(Tree Regular Expressions for Xml,Xml 树状正则表达式),并将其与 Makoto Murata 的 RELAX(Regular LAnguage description for XML,XML 正则表达式描述)结合起来,创建了 Relax/NG。
https://en.wikipedia.org/wiki/James_Clark_(programmer)
https://en.wikipedia.org/wiki/Makoto_Murata#RELAX_and_RELAX_…
>包括 Murata 和 James Clark 在内的一些人对 XML Schema 持批评态度。XML Schema 是由 W3C XML Schema 工作组设计的一种现代 XML 模式语言。W3C 打算用 XML Schema 取代传统的 DTD(文档类型定义)。XML Schema 支持众多功能,其规范庞大而复杂。村田、詹姆斯-克拉克和那些批评 XML 模式的人指出了以下几点:
>很难实现 XML Schema 的所有功能。
>工程师难以读写 XML Schema 定义。
>它不允许非确定的内容模型。
>Murata 与合作者设计了另一种现代模式语言 RELAX(Regular Language description for XML),它更简单,数学上更一致。他们于 2000 年发布了 RELAX 规范。RELAX 被批准为 JIS 和 ISO/IEC 标准。差不多与此同时,詹姆斯-克拉克还设计了另一种模式语言 TREX(XML 树状正则表达式)。
>Murata 和 James Clark 在 TREX 和 RELAX Core 的基础上设计了一种新的模式语言 RELAX NG。RELAX NG 语法是 TREX 的扩展。RELAX NG 于 2001 年 12 月获得 OASIS 批准。RELAX NG 还被批准成为 ISO/IEC 19757:文档模式定义语言 (DSDL) 的第 2 部分。
https://en.wikipedia.org/wiki/Regular_Language_description_f…
https://en.wikipedia.org/wiki/RELAX_NG
https://en.wikipedia.org/wiki/XML_Schema_(W3C)
Schema Wars: XML Schema vs. RELAX NG (1/2) – exploring XML
https://web.archive.org/web/20180429143242/http://webreferen…
https://web.archive.org/web/20180429145711/http://webreferen…
https://news.ycombinator.com/item?id=22756875
>詹姆斯-克拉克(James Clark)使用 Haskell 设计并实现了一种用于验证 Relax NG XML 架构的算法(他是 Relax NG 的共同设计者,也是其前身 TREX 的设计者),在用 Java (JING) 重新实现该算法之前,他先研究了其中的想法(Java 语言中还有许多行繁琐脆性的代码)。这样,Haskel 作为一种设计和标准定义语言就非常好用了。
https://news.ycombinator.com/item?id=25435678
>詹姆斯-克拉克(James Clark)为 Relax/NG XML 模式验证语言设计的紧凑语法非常有品位,它是一种等价但比 XML 更方便的替代语法,可用于编写匹配 XML 文档的树状正则表达式。它比官方的 “XML 模式 “标准更美观、更连贯。
[…]
>詹姆斯-克拉克(James Clark)有一篇精彩的 DDJ 访谈,名为 “简约的胜利”(A Triumph of Simplicity):James Clark on Markup Languages and XML”(《简洁的胜利:James Clark 谈标记语言和 XML》),他在采访中解释了如果每个人都只使用参考实现,那么标准就失败了,因为标准的关键在于足够简洁,以至于许多不同的实现都能完美地互操作。
>A Triumph of Simplicity:詹姆斯-克拉克谈标记语言和 XML:
https://web.archive.org/web/20130721072712/https://www.drdob…
“标准必须足够简单,以至于有多种实现方式”。詹姆斯-克拉克
有道理。但 SVG 是由 W3C 定义的,而 W3C 正是 XML 标准化的组织。如果有的话,他们应该知道自己在做什么。
> 没有多少开放标准的可扩展通用结构化数据格式。
问题是,仅仅有一个 XML 解析器还不足以解析 SVG。你还必须解析 DSL。因此,我认为这个论点是 “为什么不只使用一个能够很好地描述数据模型的 DSL 呢?
XML 结束和 DSL 开始的界限至少有点武断,但它确实有重要的影响。通过使用 XML,您可以使用 XPath 查询语言对 “路径”(XML 的终点)进行索引,但不能在 “路径”(DSL 的起点)内进行索引。这意味着,至少在概念上,您可以将颜色、事件等附加到路径上。而事实上,您不能在路径中进行附加(除非为 DSL 引入一种查询语言),这一点很不雅观,但在 99% 的应用中可能也不会有太大影响。
因为这样你就必须定义它的语法和扩展点。XML 和命名空间为你解决了这个问题,所以你唯一需要设计的就是数据的实际结构。
事实并非如此。他们还必须为嵌入字符串的 DSL 定义新的语法。
没错。但如果他们必须为整个文档定义一种语法,那就难上加难了。
我想,他们认为路径 DSL 的解析已经足够简单了(我似乎依稀记得 PostScript 也有类似的东西),而将路径节点表示为 XML 元素的开销会太大。
我并不是反对使用现有格式,只是觉得这里的混用很奇怪。
我不禁认为,使用 s-expressions 会是更好的选择。
我认为,如果不重复使用 XML,它与 HTML、JavaScript 和 CSS 之间的关系会更糟。
另外,还有 SGML:
<path>
<point x=10 y=10/>
<point x=90 y=10/>
<point x=90 y=90/>
<point x=10 y=90/>
<point x=10 y=10/>
</path>
和其他评论者一样,你删除了关于该坐标含义的信息。<point x=10 y=10/> 是否意味着我将追踪一条直线到 10,10,再移动到 10,10,追踪一条贝塞尔曲线,…
这可能是一种更好的格式,但在带宽方面仍然要节省很多。
<path>
<move x=10 y=10/>
<line x=90 y=10/>
<curve x=90 y=90/>
<end/>
</path>
这显然是对一堆点的更准确的 “xml 化”。X/Y 是点的无序属性,而不是包含在点中的有序列表的一部分。
XML 并非完美无缺,但并不意味着它是垃圾。XML 非常适合树形结构,特别是文档树形结构。因此,XML 被用来管理 SVG 类似文档的属性(元素/位置、嵌套组等)。XML 并不适合表示潜在的巨大绘图指令列表。因此,SVG 人员明智地决定使用更简洁的 DSL 来处理这种用例。就像创建 CSS 或 JS 一样。你能使用 XML 来设计样式吗?当然可以(如果你想举例说明,XAML 就是这样做的)。你甚至可以强制 JS 使用 XML 编写。事实上,在这些强制应用中,XML 是非常冗长的,但这并不意味着 XML 在总体上是冗长的。
另外,总的来说,SVG 的 d-path 语法是聪明地满足和理解需求与用户的绝佳范例。如果他们使用一些更冗长的语法(如`move-to`而不是`M`或其他),那么文件的可读性就会大大降低(XML 层面的噪音太多),但对新手却更友好。但是……新手需要手动编辑 d 路径吗?当然不需要!他们需要手动编辑 XML 结构吗?更有可能。因此,您可以使用更简洁的专家级路径语法,因为想要使用它的人很可能是专家。这也意味着 SVG 文件更小,解析所需的内存更少,更易于人类阅读。他们的选择真的很棒。
这样也行:
<path>
<m x=“10” y=“10” />
<h dx=“90” />
<v dy=“90” />
<h dx=“10” />
<l x=“10” y=“10” />
</path>
非常理智
上面有人抱怨过 JSON,但我认为它在这里做得更好:
{
"path": [
[10, 10],
[90, 10],
[90, 90],
[10, 90],
[10, 10]
]
}
不需要 x 和 y,真的。而且在一行上还是很清晰的。
{"path": [[10, 10], [90, 10], [90, 90], [10, 90], [10, 10]]}
你显然不明白 SVG 中的路径元素是如何工作的。M、L 和其他字符包含有价值的信息。M 代表移动,L 代表跟踪线,但也可以有贝塞尔曲线的指示或关闭路径的 Z。去掉这些信息的 json 格式将毫无用处。
我认为这样的格式也可以(请原谅 JSON 中通常不允许的注释):
{
paths: [
{
points: [
[10, 10], // 0
[90, 10], // 1
[90, 90], // 2
[10, 90] // 3
],
lines: [
[0, 1, 2, 3, 0] // connect point 0 to 1 to 2 to (...)
],
curves: {
0: [5, 15, 15, 5] // bezier control points for point 0 (x1, y1, x2, y2)
}
}
]
}
这样做的缺点(除了臃肿之外)是,在手工编写代码时,你必须跟踪 `points` 数组中的索引。
我更喜欢
[ { line: [10, 10] }, { cubic: [ 5, 15, 15, 5 ] }, ... ]
or even
[ ["line", 10, 10], ["cubic", ...], ... ]
– 只要有办法流式传输数据(您的格式不可能做到这一点,因为您需要先接收整个对象,然后才能做任何事情),您就可以做任何事情。
这让我意识到,XML 与 JSON 数组的映射相对较好,JSON 数组的元素是具有 1 个字段(或 2 个字段)的对象,其值也是类似的数组。
> 你显然不了解 SVG 中的路径元素是如何工作的。
不,我不明白。我是根据父代的代码工作的。不过我不欣赏你的态度。在网上有更友好的方式来纠正别人。
虽然这话有道理,但与他们的观点无关,他们的观点是:
> 不需要 X 和 Y,真的
SGML (及其后代)是一种标记语言。名字就说明了这一点。
>XML/SGML 是表示树数据的一种非常有效的方法
完全不同意:
– 从密度上讲,它并不有效,因为格式非常冗长
– 从解析角度看效果不佳,因为格式非常复杂。
– 从人性化角度看,它的效果不佳,因为属性和子节点之间存在毫无意义的区别,这对标记语言来说是合理的,但对序列化格式来说却不合理。它还非常啰嗦,读写起来很烦人。
想象一下,你有一个这样的对象
struct Object {
name: "foo",
}
Should you serialize like:
<object name="foo" />
Or:
<object> <name>foo</name> </object>
说白了,这是一个反问句。我想说的是,这种区分对于序列化格式来说意义不大,而且会迫使开发人员做出毫无意义的决定。在这里,你可能会说属性更有意义,但如果后来你意识到你可以有多个名称,那你就完蛋了,因为你要么必须想出自己的自定义格式将这些名称存储在属性中(逗号分隔? 但如果名称中有逗号呢?
不过,这对标记语言来说是非常合理的,因为文本内容和元文本内容(通常)有明显的区别。标签之间的内容是要显示给用户看的,而属性则是要由机器来解释的。
事实上,这种区分并非毫无意义。如果你关心字符串的完整性,最好使用 CDATA 文本节点,而不是属性,因为 XML 有一个可怕的晦涩功能,叫做 “属性值规范化”。
XML 只会诱使你使用属性来表示字符串,然后在你最不经意的时候踢你一脚,出其不意地、不公平地破坏你的数据,但这完全是 XML 标准本身的法律授权。
我在另一篇评论中也写到了这一点:
https://news.ycombinator.com/item?id=26122107
同意;XML 最适合文档树,而不是一般的通用树数据。我认为在大约 85% 的用例中,属性/子节点之间的含义非常明确。也就是说:属性是当前节点的属性,子节点是包含在当前节点中的独立元素。我同意解析起来可能会很复杂,也不同意它特别啰嗦。它比 CSV 或 JSON(只是因为有结尾标记)更啰嗦,但我不会说它特别啰嗦。比起 JSON(在 JSON 中,你需要在每一个字符串上加上 “type:”段落”`或在每个元素上添加等同内容,以模拟 HTML 的工作方式。XML 更适合文档树,JSON 更适合通用树数据。
(注:XAML 确实在属性和节点之间有很好的二元性(有点),这有点意思。不过我已经很久没用过它了,所以不太记得细节了)。
关于如何明确解码 XML 签名规范的介绍/文章几乎和规范本身一样长。轮到我解码时,我发现他们遗漏了一些情况。
在 XML 中,ID 字段在文档中应该是唯一的。但没人强制执行。相反,getByID 返回的是第一个 ID。这意味着,如果你通过 ID 向 DOM 元素和根元素询问一个元素,你可能会得到两个不同的答案。
将多个模式合成到同一个文件中是一个词不达意、令人困惑的烂摊子,DTD 直接就被破坏了,我唯一一次看到有人生成 A 级 XML 模式是通过将示例输入 XMLSpy 而不是自己编写。
XML 提出了一个我们早已知道答案的问题:如果我们让每个人都成为编程语言设计师会怎样?答案是 “无政府状态”,因为我们知道很多人都无法设计出语法一致的语言,也几乎没有人能设计出语义一致的语言。
我记得,詹姆斯-斯特拉坎(James Strachan)在他们为 Groovy 设计出明确的语法之前,就从 Groovy 退休了。总有一天,你会发现自己已经弄得一团糟,却没有资格去收拾(克尼根定律)。你要么做非常艰苦的工作,让自己成熟起来,承担起责任,要么退出。斯特拉坎和我共事过的十几个人以及我从第二或第三者那里听说过的无数人没什么两样,我很高兴他们都离开了。
这不是他们一个人的罪过。部分人必须归咎于这种共同的错觉,即只要用心,就可以用软件做任何事情。我们有数学证明告诉我们这不是真的,但我们仍然相信信念的力量。不幸的是,如果我们不相信这一点,那么我们可能永远也写不出任何东西,所以我不确定这是否是一种治疗方法,而是一种必须加以控制的状况。一点点就能走很长的路,而我们大多数人迟早都会走得太远。
从编程的角度来看,像 https://en.wikipedia.org/wiki/Interchange_File_Format 这样的标记交换格式要比 XML 好用得多。
如果我想要自由格式的文本,我更喜欢使用 YAML 等格式。
没错,在画布 API 中是这样写的:
<path d="M 10 10 H 90 V 90 H 10 L 10 10"/>
ctx.moveTo(10, 10);
ctx.lineTo(90, 10);
ctx.lineTo(90, 90);
ctx.lineTo(10, 90);
ctx.lineTo(10, 10);
好不了多少。
我不同意,JS 代码无需查找任何内容即可立即理解。你也可以用纯 XML 来写,但结果可能会更冗长。
SVG 中的”<path>`”元素可能需要一个类似于”<draw>`”元素的 idref,这样才能等价。这就是我猜测的等效方式:
<draw id="my-path">
<move-to x="10" y="10" />
<line-to x="90" y="10" />
<line-to x="90" y="90" />
<line-to x="10" y="90" />
<line-to x="10" y="10" />
</draw>
<path draw="my-path" />
编辑:仔细想想,使用 CSS 或 SMIL 制作上述内容的动画可能要容易得多。对 `<path>`s 上的 `d` 属性制作动画在理论上是可行的,但在实践中充其量只能说是怪异,或与浏览器不一致,甚至根本不可能。
编辑 2:在 D3 中,绘制顶部带有厚边框的区域图并不少见。做到这一点的唯一方法是使用两个`d`属性几乎完全相同的`<path>`。允许使用多个 idrefs 将图形串联起来可以解决这个问题:
<draw id=line-path><!-- ... --></draw>
<draw id="area-box-close">
<line-to x="100" y="100" />
<line-to x="0" y="100" />
<end />
</draw>
<path draw="line-path" class="line" />
<path draw="line-path area-box-close" class="area" />
也许这并不是一个坏主意。
是的!不过我猜测,自定义字符串之所以使用单字母 “操作符”,是因为对于具有复杂路径的 SVG(作为一种矢量格式,它应被视为基准格式)来说,大小开销是难以承受的。在当前的规范下,开销已经相当大了,压缩后的文件大小通常可以除以一个数量级。
我的 SVG 很不优雅,但它很实用。
我认为使用这样的方法会导致文件的整体可读性降低。85% 手工编辑 SVG 的人对手工修改路径毫无兴趣。他们很可能想移动元素、改变分组等。如果 d-path 写得不够紧凑,那么这些大多数人根本不关心的路径定义就会占据文件的绝大部分空间。这样就无法了解嵌套的情况,而且移动起来也会非常麻烦,因为它们会非常大。
还有:提醒 SVGs 的目标是展示,因此即使是简单的单色图标,其路径也有数百个控制点。更复杂或更大的图形?几千个轻而易举。这里的所有示例都是玩具示例,与 SVG 的实际用途不符。
> 哦。你几乎可以听到设计者在说:”好吧,去他妈的,我们就把它全部塞进一个字符串里。
我想在这里说两句,因为这些回复并没有解决为什么路径描述符要这样风格化的问题。无论 SVG 的底层文档格式是 XML、JSON、SGML、CSS 还是其他什么,都无关紧要。因为 “d “标记已经提供了以文本形式描述矢量路径的最简洁方式,所以无论你采用哪种方式,任何替代方案都会更加冗长。
这就是问题所在–它很小。即使是这种紧凑的形式,如果考虑到浮点数,路径字符串的长度达到千字节也是很正常的。因此,我们需要尽可能小的路径描述,以优化文件解析并减小文件大小。
顺便提一句,我不同意作者的猜测,即 SVG 作为以机器为中心的语言或以人为中心的语言都不会成功。我认为它在实践中很好地满足了这两方面的需求(当然比 HTML 更好),而且 SVG Tiny 的精简版本已经存在。
我想知道,对于可以使用 GZIP 编码的网络格式来说,这有什么关系?难道 GZIP 不会把重复的 <move-to /> 标记当早餐吃掉吗?这样一来,编写、阅读、操作和动画都会容易得多。
让我们设想一下,路径指令可以映射出更多的冗长指令。这真的会有足够的实际用途,值得标准化吗?
在大多数情况下,SVG 路径轮廓几乎都是在 Illustrator 和 Inkscape 等软件中定义的。如果没有可视化的辅助工具,一般人是无法创建或修改贝塞尔曲线的。简单的路径结构在实践中并不常见,我在这里看到的例子也不能代表实际使用情况。
SVG 确实提供了转换功能,可以轻松移动、旋转和缩放路径,而且这些功能可以在文本编辑器中应用。至于其他功能,有很多可视化工具可以帮助修改路径。就我个人而言,我已经手动修改过很多 SVG 文件,但当涉及到路径时,我不能说看到它们裸露出来会对我的工作流程有帮助。
我想让你参考一下树中其他地方的注释及其父级[0],正是它提出了这个 s 表达式:
(path (M 10 10 H 90 V 90 H 10 L 10 10) :color red)
sexprs集紧凑性、通用性和易用性于一身,确实很难被超越。如果我从制作矢量图形格式的第一条原则出发,我可能会把它做成 EDN 的模式。我敢打赌,显式映射和矢量所带来的额外复杂性一定会得到回报。
[0]: https://news.ycombinator.com/item?id=26118727
我认为这很合理,但当向量点在现实中看起来更像这样时,语法糖真的能帮助你修改路径吗?
(path (M 368.296, 1.514) (c -0.908, 0 -1.818, 0.011 -2.716, 0.021)
(c 0.053, 0, 0.106, 0, 0.159,0) (c 147.196, 0.836, 265.306, 94.672, 267.029, 183.784)
(c 0, 0.581, 0.065, 35.087, 0.065, 35.087) (h 49.415)
(v -33.471) (h 37.094) (v -31.376)
(C 719.342, 77.099, 575.826, 1.514, 368.296, 1.514)
(z))
多年来,我一直在大量使用 SVG,尤其是在过去的几个月里,我一直在编写渲染 SVG 输出的库/工具(为 cli 工具端进行解析、大量的手写和测试、清理、渲染)。
在我看来,s 表达式通常是最好的表达方式(更确切地说,x 表达式(参见 Racket)是最理想的表达方式)。但实际上,它并没有那么有用。作为中间步骤,它还是非常有用的。
例如,一个将 SVG 解析为 x 表达式并清理后再编译回去的工具。这是我正在研究的[流产的]东西之一,因为现有的三个最好的工具(JS、Python 和 Rust)在这方面都存在这样或那样的问题。或者你有一个工具可以让你编写 x 表达式,然后进行编译。但是,如果是这样的话,就无法真正直接与宿主语言/平台进行 jnterop — 正如你所说,必须从第一原理出发。更进一步说,它需要从第一原理出发的 HTML,因为其中一个巨大的好处就是 SVG 可以直接插入 HTML 中,并具有几乎相同的语义、相同的样式和相同的 JS 交互钩子。此外,SVG 不仅仅是 XML,它还是一个 DSL(NB 解决方案通常是限制功能的子集),因此简洁的结构经常会出现问题。在我看来,SVG 必须是这样的,它所使用的混杂 XML 必须有所取舍,才能真正有用。这些取舍也使其难以使用,而且通常很难轻松解析。但是,如果不改变 HTML 的工作方式和网络浏览器的渲染工作方式,我看不出有什么替代方案会更好。
我认为原帖中提到的其他需求比选择序列化格式更重要。SVG 已经存在,而且我们已经被它困住了。在其他应用中,设计更好的矢量图形格式可能会带来更多好处,而将其重新绑定到浏览器上并不会带来什么好处。
在这一点上,使用 s-expression 格式(x-expression、EDN,我不持任何看法)应该是首选。当然,首先要实现的是 SVG 转换器。
我对矢量图形很感兴趣,所以在我需要它们的少数情况下,我只是耸耸肩,用我们现有的格式来处理。
> 基于 SGML 的格式能够如此流行,确实证明了软件工程中存在着一些根本性的问题。
HTML 是一种相当不错的语法。类似 SGML 的语法只是不太适合那些不以文本为中心的格式,因为元素/属性的区别在语法中变成了多余的噪音。
我同意,HTML 很好(在我看来还是有点太啰嗦了,特别是要重复标签才能关闭它,总觉得没什么用,而且很吵)。
但 HTML 是一种标记语言,问题是出于某种疯狂的原因,业界的一大部分人在某一时刻认为 XML 是一种合理的序列化格式。在我看来,这才是真正出错的地方。
在 HTML 中,在可以明确推断出结束标记的情况下,可以不使用结束标记,比如:
<p>First paragraph<p>Second paragraph</p>
P 元素不能嵌套,因此 <p> 会自动关闭前一个 P 元素。
但这也意味着有必要在关闭标签中标明标签名称。例如,这样做会产生歧义:
<div><p>Hello</>
无法推断封闭的是 div 还是 p。
XML 当然不同。由于所有元素都必须明确关闭,因此在 close 标签中重复标签名称原则上是多余的。我认为,这样做虽然更便于阅读,但却增加了编写的工作量。
>”好吧,去他妈的,我们就把它全部塞进一个字符串里。
这几乎是试图编写 XML 语法(或之前的数据库模式)的人的通病。每个人都认为自己可以毫不含糊地解码塞进同一个固定宽度字段中的多个数据块,但几乎所有的人都错了。一遍又一遍。
他们永远学不会,这证明开发人员有能力把解决自己的克鲁格-邓宁时刻变成别人的问题。在后果不可避免之前,获得晋升或更换团队。你可以说,连蒂姆-布雷(Tim Bray)都是这么做的。
XML 永远不会成功的原因有很多,这远不是最重要的原因,但它是一个重要的促成因素。
所以,XML 失败的一个原因是,那些名义上使用 XML 的人并没有充分利用 XML 的功能来捕捉数据结构,而是保留了过去用固定宽度记录来表示所有数据的习惯?
XML 和 Java 来自同一个时代。Java 本应是面向对象的,但我们得到的却是字符串类型的代码。
编程语言中的数组字面几乎是尽可能紧凑的(开始、结束、一个字符的元素分隔符),而且类型系统或少量代码往往可以让你在事后弥补 1:1 的错误。该属性现在是一个数字或数字数组。
在 XML 中,如果你想要一个格式正确的列表,就必须使用子元素,而这很快就会变得非常昂贵,因此人们都会望而却步。尤其是当你已经通过了属性/子元素测试,误将数值定为 1:1,而结果却是 1:many。
我们也已经有了 HTML class、style 和 on* 属性作为先有技术,我们可以用它们来说服自己,多一个也没关系。从根本上说,XML 从两头都得到了好处。XML 使实体关系成为不可逆转的决定,而在这个时代,UML 已经存在并不断强调这一点。
我不知道在那个时候是否有任何补救措施。我所知道的是,我们中的很多人都意味深长地看了对方一眼,在尘埃落定之前,我们都在尽力找点别的事情做。但在 00 年代,你真的无法避免 XML。
> 如果您需要生成基本形状,这非常简单。
你会这么想的。在将 TeX 集成到我的编辑器[0]中时,我想使用 JMathTeX[1] 作为起点,将字体字形转换为矢量路径。当时,所有基于 Java 的 SVG 渲染器(Batik、JFreeSVG、SVG Salamander)都有一个完全相同的性能问题:它们都使用 Java 的 DecimalFormat 类将浮点数转换为字符串。然后将这些字符串作为路径连接到输出文档中。有时,由于缓冲区重新分配和其他原因,字符串会被重复复制无数次。(我关于开发面向 TeX 的文本编辑器的系列文章[2]第 5 部分对此进行了深入探讨)。
要获得出色的性能–至少在 Java 中–即使是基本的图形也需要一个足够大的、可重复使用的缓冲区,这样才不会引起内存重新分配,同时还需要一种高效的算法来将浮点数转换为字符串–比如 Ryu[3]。详情请参阅我将字形路径转换为矢量路径的实现[4]。通过这两项改动,我可以将 JFreeSVG 的实现改进四倍。
[0]: https://github.com/DaveJarvis/keenwrite (my editor)
[1]: https://github.com/DaveJarvis/JMathTeX/ (my fork)
[2]: https://bell-sw.com/announcements/2020/11/02/TeXnical-Writin… (my blog series)
[3]: https://github.com/ulfjack/ryu
[4]: https://github.com/DaveJarvis/JMathTeX/blob/d2d678717505765b…
使用 D3 绘制曲线图和其他数据可视化效果真是如虎添翼。除了其他优秀的绘图库(如 ggplot2)之外,SVG 作为我的画布真的让我感觉可以做我想做的一切。
如果你需要 JS 中的动态图表,它是个好东西,但如果你只是想要一个图形或徽标,我不会用它。它的维护也非常麻烦,他们每年都会对库进行一次更新,并做出一些突破性的改动,然后我就需要花一两天的时间来研究旧版本如何工作、新版本如何工作以及如何将我的图形全部转移到新版本上。
请注意,Sciter (https://sciter.com) 和 Sciter.JS 的 CSS 支持内联矢量图像。
在 99% 的用户界面案例中,我们只使用这些而不是 SVG 和类似 FontAwesome 的东西
button {
background-image: url(path:M 10 10 H 90 V 90 H 10 L 10 10);
fill: red;
}
or
<img src="path:M 10 10 H 90 V 90 H 10 L 10 10">
您也不能用列表中的 rgb/index 值来编辑原始的 png 值。SVG 的创建和使用方式与其他图像文件类似。
事实上,它们几乎可以人为编辑,而且可以内联,这意味着我们在以这种方式使用它们时一定会感到失望
我不同意,我经常手动处理 SVG(甚至是用 inkscape 这样的程序生成的 SVG),因为它可以让我添加交互性和动画。对我来说,这才是它的杀手锏:你可以在网站上绘制任意的矢量形状,然后像使用任何 DOM 元素一样使用 javascript 与之挂钩。要让它运行良好,还有一些微妙之处,但非常简单直接。
下面是一个示例:https://svkt.org/~simias/up/20210212-185105_svg.png
所有元素和路径都是通过一些 javascript 生成的 SVG。你可以与各种元素互动,移动它们,路径也会实时更新。
当然,您也可以使用光栅格式来做同样的事情,比如使用画布绘制位图,但 SVG 工作在更高的层次上,可以让您更快地完成这些事情,而且性能可能更好。您可以使用 CSS 风格,可以注册 javascript 事件回调等…
或者换一种说法:如果 SVG 是一种不透明的机器对机器格式,那为什么还要使用 XML 这种开销巨大的格式,而不是使用某种密集的二进制格式呢?
在 D3 中绘制图表时,手动弄脏 SVG 元素会给你带来极大的自由度,这一点令人惊叹。如果你在网络上做任何高级数据可视化,能够读写 SVG 的部分内容是必不可少的。
沿着这些思路,我最近遇到了这样一个项目,它可以使用 SVG 为使用 Rust 语言游戏引擎 Bevy 开发的游戏设计地图等:https://github.com/carrascomj/bevy_svg_map。
“线条的属性(颜色、不透明度、填充……)可用于以编程方式添加功能……”
是的,但 SVG 作为以机器为中心的格式也不好,这正是问题的关键所在。
我喜欢这种折中方案,即用 illustrator 等软件生成 SVG,但你可以读取实际文本中的元素,这样你就可以用 css 或 js 制作动画或进行转换。
例如,我最近 “破解 “了渐变变换。即使是 “破解”,也比维护和理解复杂的画布 JS 容易得多–至少对我来说是这样。
https://4degreesdigital.com
很喜欢!我只是想知道,除了动画部分,您还需要编辑 Illustrator 生成的 svg 吗?
我个人是为了控制颜色。在我正在实施的一个网站[0]中,你可以看到我大量使用了 SVG。例如,如果你查看 :root {},就会发现其中声明了许多 CSS 变量,这些变量可以根据 –hue 等基本变量操作 HSL 值。SVG 实现了这些功能。因此,你可以改变全局的–色调,页面上所有 SVG 元素的色调也会随之改变。我修改了 figma/illustrator 输出的 SVG,以引用变量而不是硬编码填充,例如,<path fill=”red”> 变成了 <path fill=”var(–base)”> 这只是一个简单的例子,你还可以进一步改变相对饱和度和亮度,我也是通过 CSS calc() 来实现的。这很有趣!
[0] http://www.holysnacks.us
我喜欢太阳光线
我也很喜欢将 css vars 与 SVG 相结合。
哇,我从没想过用这种方式制作动画。太棒了!
> 您也不能编辑原始 png 值
不过,如果你想这样做,可以使用 SNG¹。用它来对图像进行微小的修正或过滤,会有意想不到的乐趣。
¹ http://sng.sourceforge.net/
> SVG 的创建和使用方式与其他图像文件类似。
那为什么还要使用 XML 呢?还有,为什么要在字符串中使用嵌入式 DSL,而不是采用更冗长的 XML 方式呢?
此外,不要忘了使用 `px`、`ex` 等单位的不一致性,即:`<circle cx=”10ex” cy=”10ex” r=”2ex” fill=”red”/>`,但在 `path`中是无效的。路径中的单位只有 `px`。
我觉得有一种设计语言会很好:
def port 0,0 100,100:
L 10,10 90,0 90,70 70,70 70,90 20,90 20,70 10,70 10,10
def bank 0,0 400,100:
port 0,0 100,100
port 100,0 200,100
port 200,0 300,100
port 300,0 400,100
def router 0,0 1100,200:
port 50,50 150,150
bank 200,50 600,150
bank 650,50 1050,150
router 0,0 1100,200
我在想,如果能在 openwrt 的 “关于 “页面上用 svg 标出路由器的所有端口,那一定很酷。这应该很简单,但我弄不懂 luci。
这些东西并不等同。
圆具有无序属性。
路径有有序的命令。我想这些命令可以分开并编号,但这样不是更冗长、更难读吗?
我同意矢量图形格式不是标记语言的用武之地。不过,SVG 的优点是可以嵌入 HTML。
SVG 提供的元素可以让你用 XPath 或 JavaScript 单独解决一些问题。点不太可能通过这种方式进行操作,因此在此不再使用 XML 来标记结构也没有问题。许多其他数据类型(如时间、HTTP 或电子邮件地址)也有结构,但通常不会明确标记出来,因为它们的解析很琐碎。
> <path d=”M 10 10 H 90 V 90 H 10 L 10 10″/>
可以通过 svgo 进一步优化为:
<path d="M10 10h80v80H10V10"/>
他们可以变得近乎搞笑的密集和混淆。
我看不出路径字符串有什么问题,顺便说一下,HTML 画布中的路径字符串也是一样的。我每天都在使用 SVG,遇到过很多让我烦恼的问题,但路径数据从来不是其中之一。
我并不认为这本身是错误的,实际上,考虑到一系列限制因素,这可能是最好的解决方案。与其说是 SVG,不如说是在抨击 XML 的不切实际。
把路径塞进属性字符串而不是使用元素的想法来自于微软的 VML(影响 SVG 的矢量图形竞争标准之一)。
https://en.wikipedia.org/wiki/Scalable_Vector_Graphics#Devel…
实事求是地说,这是对 XML 作为序列化格式的一个可怕缺陷(过于松散)的一个绝妙的实际妥协,通过对每个路径使用一个字符串来节省大量内存和碎片,而不是创建具有成千上万个属性和文本节点的成千上万个 DOM 对象。但你说得没错,这是 XML 的 “原罪”,SVG 注定要受它的影响。
PDF 基本上只是 PostScript 图像模型,没有基于图灵完备堆栈的编程语言。
SVG 只是 PostScript 图形模型的最新表现形式(如果你忽略所有关于字体的内容),它基于带有 Porter Duff Compositing 的 Stencil/Paint 成像模型,是 Interpress 和 Jam 的后代。)
画布 2d api 几乎就是即时模式 SVG / PostScript 图形,并添加了一些新功能。
在某些方面,JSON 是一种更好的结构化图形格式,但它也有自己的缺陷和限制,例如没有注释,而且对于二进制数据来说非常糟糕。但至少 JSON 数组比 XML 元素更节省内存(但并不多),而且 JavaScript 本身也有类型化的二进制数组,尽管标准 JSON 不支持它们(使用基 64 字符串很糟糕)。因此,如果主要是绘制静态路径,那么用 SVG 这样的平面字符串来表示路径,而不是用 JSON 数字数组来表示路径,可能还是 JSON 的优势,但如果要经常读取、处理或编辑这些路径,JSON 的优势就不明显了。
现在,与其使用 SVG,不如直接使用自己的(或某种标准的)JSON 格式来绘制结构化图形,并使用 canvas api 绘制,这样通常会更简单、更高效。但是,永远不会有一种通用的 JSON 图形格式,只会有很多特殊用途的格式。例如,d3 有许多不同的 JSON 格式(特定领域语言),用于表示不同类型的图形和数据。
有关 PostScript 及其历史的更多信息:
https://news.ycombinator.com/item?id=21968175
>布莱恩-里德(Brian Reid)写了一篇关于页面独立性的文章,比较了 Interpress 和 PostScript 的不同方法。Adobe后来自愿采用的 “文档结构约定 “实际上是利用PostScript注释来声明和划分文件的不同部分–它实际上并不是PostScript语言的一部分,而Interpress则将页面定义为独立的,因此它们不可能相互影响:
https://groups.google.com/g/fa.laser-lovers/c/H3us4h8S3Kk
xml 或其他基于 SGML 的标记没有任何问题。它们是由计算机编写的,而不是由手…..。
也许 XML 可以,但 SGML 不行。SGML 的 SHORTREF 和标签推理等功能可以将 Wiki 和其他自定义语法解析为规范的角括号标记(又称 XML),这些功能的设计非常符合人体工程学和简约,与 Markdown 等一样受欢迎。
XML 并非计算机的理想格式。
有时很奇怪…XML 语法比 JSON 更易阅读
W3C 正在定义 SVG Native [1],它是完整 SVG 规范的一个子集。计划将其用于字体文件,对于本地应用程序来说,这应该是一种不错的格式。它取消了对 CSS、样式属性和大量额外语法的支持。由于不需要支持 XML 实体,甚至 XML 解析也变得更简单。使用 gzip 压缩应该能生成相当小的文件。
通过重复使用 SVG 格式,它仍然与现有工具兼容,如 Adobe Illustrator 和 Inkscape(这意味着它们可以打开 SVG 原生文件)。
Adobe 甚至有一个针对 SVG Native 的开源渲染器 [2]。
[1] https://svgwg.org/specs/svg-native/
[2] https://github.com/adobe/svg-native-viewer
他们还定义了 SVG Tiny,基本上就是没有 CSS 和脚本支持的 SVG。这似乎与 OP 在博文中的要求差不多。为什么需要重新发明轮子?这一次,我们在统一的矢量图形格式背后拥有整个行业的巨大动力。逆水行舟,不进则退。
> W3C 正在定义 SVG Native [1],它是完整 SVG 规范的一个子集。
酷,这只是他们第三次这样做(继 Tiny 和 Basic 之后)。
比 Tiny(= 无 CSS)还少。我最近手动编写了一些 SVG,在我看来,SVG 在这方面做得很好。
> 也许基于 JSON,但绝对不是基于 XML
不是
强大的模式是它在众多平台上获得支持的原因。因为 “它有 JSON,这是植物所渴望的 “而使用 JSON 绝对是个愚蠢的论点。参见文章 “解析 JSON 是一个雷区”。我想不出有什么方法能比用 JSON 重新实现标准更糟糕了。
正如其他评论者所指出的那样,SVG 中确实缺少一些功能。在我看来,缺少的其实是工具。实际上,SVG 所缺少的可能是相当于最小化的功能,甚至是将 xml 呈现为二进制表示法的选项。
我从小就使用 XML。一般来说,我更喜欢使用 JSON,但我的所有 SDK 都能同时输出 XML 和 JSON(偶尔也会输出 CSV)。
XML Schema 是我使用 XML 的主要原因。我讨厌模式。讨厌 HAAATESSSS NASSSTY SSSSCHEMA……,但它是铁板一块。如果在 Schema 中进行了描述,那么它就是有保证的(或者没有;在这种情况下,Schema 也会对此进行说明)。
JSON Schema 是个不靠谱的东西。似乎从来没有人使用过它,而且我认为它从来没有离开过委员会。它几乎违背了 JSON 流行的原因。
如果有人想要真正的痛苦,那么我们应该回到 BNF:https://en.wikipedia.org/wiki/Backus-Naur_form
我曾使用过 BNF 编译器,现在醒来仍会尖叫。
> JSON Schema 是个不靠谱的东西。似乎从来没有人使用过它,而且我认为它从来没有从委员会中脱颖而出过。这几乎违背了 JSON 流行的原因。
我所在的公司大量使用 JSON 模式。
OpenAPI 项目使用 JSON 模式,AWS 也允许在某些地方使用它们。
最后,有几个不错的项目可以从 Typescript 定义自动生成 JSON 模式,这也是我喜欢的方式。)
做得很好: https://json-schema.org/specification.html
但要注意 “草稿”。
比较: https://www.w3.org/standards/xml/schema
多年来一直是 “草案”。
但这并不妨碍围绕它制造工具。
https://www.w3.org/XML/Schema
每当我遇到 JSON 模式时,我都会意识到 JSON 和 XML 的重要区别不在于语法(我的集成开发环境可以很好地处理),也不在于功能。而是僵化程度的不同。当需要灵活性时,使用 JSON。而 XML 需要的是刚性。
我看不出严格的、类型化的、模式化的 JSON 有什么好处,而 XML 却不能更自然地提供这些好处。
很多应用程序接口都会输出 JSON。
JSON 模式可以让您更安全地处理这些数据。
我的观点是,如果他们需要这种 “更安全 “的方式,为什么不采用 XML 呢?
JSON 的最大优势在于它不是 XML。它不会被模式、强类型、接口、契约等问题所困扰。如果把 JSON 变成用不同语法编写的 XML,就会失去所有这些优势。
BNF 只是一种描述形式语言的符号。虽然 BNF 在使用上有许多细微的变化,但 BNF 通常用于非常精确地描述属于形式语言的句法上合法的确切句子(即序列符号)。
有些语言很简单,例如由一个或多个 “A “组成的任意序列的语言。
A、AA、AAA、AAAA 等都是这种语言的有效句子。这是一种特别简单的语言,但可以用 BNF 来描述:
<s> ::= a | <s> a
这种语言也可以用集合符号指定为 { A^n | n >= 1 },或指定为正则表达式,如 A+
稍微复杂一点的语言是所有句子的语言,这些句子由任意顺序的 A 和 B 序列组成,后面跟一个长度正好是 A 和 B 长度总和两倍的 C 序列:
<S> ::= <X>CC | <X><S>CC
<X> ::= A | B
法律句子看起来像ACC、AACCCC、ABCCCC、BABCCCCCC 等。这种语言不能用经典的正则表达式来描述,但可以用上述 BNF 所表示的无上下文语法来描述。
BNF 符号还有一些替代和概括。Wirth 在描述其语言的 Pascal 报告中使用了铁路图来描述 PASCAL 的语法。这种方法更直观,但功能并不强大。
BNF 可能很麻烦,但一般来说,没有简单的方法来表达编程语言的复杂语法要求。BNF 并不是用来解决 XML 或 JSON 所要解决的问题,它们都是对数据进行编码的方法。
BNF 是声明式语言的一种原型。
但我曾在一个 X.400 系统上工作过,我们必须用 BNF 绘制数据结构,然后通过一个 BNF/X.409 编译器,这个编译器总是把事情弄得一团糟(经常是我们的错,但那是在 “大铁 “时代,我们必须为编译器的通过而掰手腕),然后,一旦我们修复了 X.409,我们就需要把它传给 X.409/C 编译器。
然后再修复一次…
我认为,当开发人员不喜欢在 XML 中工作时,这是因为工具迫使他们正确地完成工作。
这对制作文档的人来说是件麻烦事,但对所有消费者来说却是件好事。
> 因为工具迫使他们正确完成工作
我认为,对 “将手势设为最大值 “和 “XHTML 文档少了一个括号,现在根本无法显示网页 “的限制是两个极端,这与我们 HN 读者喜欢争论的 “动态类型 vs 静态类型”、”不可变的纯函数 vs 可变的不纯函数”、”XML vs JSON(哦,等等!)”和 “网络应用程序 vs 本地程序 “的争论有相似之处。
诀窍在于在这两个极端之间找到快乐的中间点。培训一些 “懒人 “来 “正确地完成工作”,说服一些 “纯粹主义者 “更加务实地对待周围世界的限制。
毕竟,在这个 “永恒的九月”,我们需要一些东西来打发时间。
这是一个陷阱。只有当你首先接受了产生权衡的约束条件时,你才需要找到快乐的中间点。
在你列出的四个对立面中,至少有三个都归结于工具的 DX。如果你的类型错误是有用的、描述性的,那么静态类型化就不会那么痛苦。如果使用正确且易于使用的 XML linters,XHTML 文档中缺少的括号很容易就能找到。我不明白为什么编写本地应用程序不能像编写网络应用程序一样简单。至少有一些尝试似乎从这个想法中得到了一些启发(如 Revery、Flutter)。
诀窍在于让工具集更加平易近人。
> 我认为,当开发人员不喜欢使用 XML 时,是因为工具迫使他们不得不正确完成工作。
反过来说,你永远也找不到结构为”{ “zoom”:”startZoomMarkup” }5{ “zoom”:”endZoomMarkUp” }”。
> 如果有人想要真正的痛苦,那么我们应该回到 BNF…
具有讽刺意味的是,如果要实现 SVG 阅读器,就必须使用规范中提供的 BNF(用于路径什么的)。
虽然 SVG 1.1 DTD 很好用,但我还是为 c++ 和 python 创建了一个 SVG DOMish 生成器(编译起来要花很长时间),这样我就不用处理所有底层 XML 的问题了。总有一天,我会完成路径分析器、颜色分析器、转换分析器等……
对冲语法有非常好的特性,可以用一类下推自动机来解析。然而,根据我的经验,在 XML 生态系统中,并没有多少人理解和重视这些功能(参见 SVG 和 Xpath)。如果能有一种模式优先的语言,并具有良好的二进制和人类可读性,那将是一件好事。在我看来,我们可以做得比压缩 JSON 更好,即使这很难。
作为语言描述符,BNF 简单明了,不是吗?
一般来说,自由上下文语法使用起来很不方便。使用它们的自然方法要么是生成所有/随机的合法字符串,要么是检查字符串是否与语法匹配。
通常情况下,你需要的是生成一个 AST,在这种情况下,你会遇到歧义问题。
这是一种很棒的数据描述语言,但从语义上讲,使用起来并不有趣。
除了简单的数据外,JSON 真的是一种很糟糕的格式。
XML 可能冗长且不可读,但却是描述和存储数据的绝佳格式。
SVG 的一个替代方案是类似于 sqlite 的 SQL 表数据存储。我希望能有查询数据的能力,而不是通过 XML 进行解析。我知道在网络上传输这些数据是个问题。
我对 XML 最大的疑问是属性和子元素之间的模糊性。从抽象的角度看,这种区分是有意义的,但现实世界中的实现却很少以一致的方式使用它们。
一个是字典(无序、简单唯一键),一个是列表(有序、任意内容、无唯一性约束)。模式可以执行更多,但这些都是其内在特性。
我同意使用情况千差万别,但区别还是相当明显的。无稽之谈的存在并不意味着人们不能做出正确的决定。
是使用一个具有 x 和 y 属性的点标记更合理,还是将 x 和 y 作为各自的标记和值更合理?我不清楚哪个更合理,使用 xml 编写规范的人似乎也不知道。
因为 x 和 y 是简单的名称,具有简单的值,并且是唯一的对,只适用于一个点:属性。
使用其他方法意味着依赖于任意复杂的自定义模式,而不是语言本身简单得多也标准得多的模式,这就像我们在编程语言中使用数据类型,而不是到处都使用字符串一样。
很明显,如果只是用 JSON 重新实现 SVG,效果不会更好,因为要做的事情太多了。我是强模式的忠实粉丝,这是 XML 的精华所在。
虽然 JSON 远非完美,但它是一种通用语言;全世界的人类和计算机都非常熟悉它。我认为这也是三维模型 glTF 格式日益流行的原因之一,该格式也有二进制变体。
在工程师们尝试解决 “2D 图形到底有多难?”这个问题的漫长而又传奇的历史中,SVG 是另一个篇章。如果你看看业界的标准答案(从 PostScript 到 AutoLisp 再到 Gerber 再到 SVG),答案是 “非常难”。
我不知道矢量图形能否成功瘦身。现有的每一种 SVG 渲染器都会在某种程度上对 SVG 进行瘦身。做得最多的那些渲染器用得最少,因为它们无法充分表达设计者的意图。
我不得不怀疑作者是否不了解渲染图形所隐藏的复杂性。他们声称实现 svg 需要一个多月的时间,这听起来很准确,但他们又声称可以用一种新的格式来取代它,而这种格式只需几天就能实现。
当然,SVG 并不包括完全无用的数月工作。为了这种简单性,我们放弃了哪些功能?
二维矢量图形一开始看起来很简单。有一些形状、一些路径、一些affince变换。但如果你开始计算立方贝塞尔曲线的长度,或试图找到两条立方贝塞尔曲线的交点,事情就开始变得有趣起来。然后,尝试实现一种可靠而快速的布尔路径操作算法。下一个难点是偏移任意路径,或许可以用参数偏移来增加挑战性。这些我都做过,天哪,没想到兔子洞这么深。
即使是 JSON 也会 “臃肿”。这就需要一种精心设计、深思熟虑的二进制格式。虽然二进制格式的某些缺点永远不会消失,但与之相关的许多最糟糕的缺点都是由于旧标准未能包含足够的可扩展性造成的。不过,现在有很多很好的现有技术可以参考。哎呀,现在你可能只需要把某个东西定义为 Protobuf(或者你选择的类似标准,这里不想在具体选择上纠结太多),就已经完成了 95% 的工作。
即使只是将 SVG 的大部分内容线性化为显而易见的布局,只需删除任何有问题的功能(脚本、XLink、命名空间扩展),也可能是一个相当不错的开端,你可以在一周内制作出原型。你会得到一种高效的二进制格式、一种将现有 SVG 转换为该格式的显而易见的机制(同样显而易见的机制是警告用户输出中存在未经转换的特征;还有一种扫描 SVG 样本的简单机制,可以统计出有多少 SVG 适合你的新方案)、一种将你的格式转换回 SVG 的显而易见的机制,以及与你选择的序列化机制一样跨平台的序列化支持。如果这是你的目标,那么这款产品的性价比是很高的。
有一些缩小 SVG 的工具可以实现你所说的某些功能。文本格式的一个优势是可以将路径数据的精度降低到几位有效数字。而二进制格式就很难做到这一点。你必须事先决定每个坐标对是 8 字节还是 16 字节。
二进制格式不必使用固定长度的字段。你可以使用一种用 8 位存储小整数的格式,但也允许存储大整数。例如,请参见 https://developers.google.com/protocol-buffers/docs/encoding….
你甚至不必使用字节大小的字段,但这样做会增加编码和解码的难度,而且在可变大小的字段中以比特为单位存储实际长度的开销可能太大,不值得这么做。
我想你没明白我的意思。SVG 坐标实际上是任意精度的。每字节 3.5 位的任意精度,但仍然是任意精度。没有小整数,只有标量或矢量值。
varint 样式的编码也是任意精度的(尽管 protobuf 不支持任意精度),每字节 7 位是很容易做到的。
现有的可变长度二进制数字格式 [1] 已经存在。SVG 中已经有很多可变长度的内容,其缺点可能微不足道。
不过,我不知道现有的类似 Protobuf 的东西中是否有内置这些东西。我知道其中一些有可变整数,但我不知道可变浮点数。
这正是我想说的,我们现在有很多现有技术。将可变整数或浮点数添加到 SVG 中的人不必再创建自己的定制格式,也不必再自己陷入各种陷阱,一不小心就把它永远写进了规范中;与过去相比,现在有更多这样的内容,你可以从货架上买到。
[1] https://github.com/regexident/var_float
我不明白 var_float 如何从输入中检测数字字段的长度。它似乎是为了接受来自另一个函数的任意输入而设计的(该函数已经在带外决定了数据的大小)。
是我漏掉了什么,还是我不能从文件中读取 2 个字节并检测出这是数字的结束还是我需要读取下 2 个字节?
我不知道该特定库是否具有该功能,但这肯定是可以实现的。这只是一个编程问题。
是的,这就是 utf8 编码的一半工作原理:一个单元的第一个字节要么是 0xxxxxxx 要么是 11xxxxxx,在第一种情况下,它是一个 ascii 字节,而在第二种情况下,后面所有以 10xxxxxx 开头的字节都是同一个单元的一部分。
为此,只需改变数据流的顺序即可。
> 没有包含足够的可扩展性
或者抽象性和可扩展性过高,导致过于复杂!
> 即使是 JSON 也会变得 “臃肿”。这就需要一种完善的、经过深思熟虑的二进制格式
除非它不是。我最近读到不止一篇博文,声称 JSON 实际上比一些流行的二进制格式(如 protobufs)要快一些,有时甚至快过一些。我不会在这里链接这些基准测试,因为它们都没有进行足够好的测试或展示,因此不值得链接;我本人将这些报告视为似是而非的传闻。
并不是说 “二进制格式 “就能解决所有问题。你仍然需要对它进行解析。是的,当你创建它时,你可以更好地控制它,但当你创建了它并且它被大量采用时,更新它就会像更新任何流行格式一样麻烦,这意味着许多客户端至少在一段时间内不会支持某些新功能。
当然,数字在任何实际的 SVG 中都是核心,而且事实证明,使用文本格式发送数字并不像听起来那么愚蠢,从空间上来说:”1 “只是一个字节,但如果转换成 JS IEEE754 数字,就相当于 8 个字节(我认为)的 RAM。在使用文本时,您可以随心所欲地表示任意精度或将自己限制在整数范围内,而大多数二进制格式可能并非如此。
我对 SVG 的疑虑之一是,XML 本身就是一种不必要的复杂格式。作为对这一说法的某种证明,我向大家介绍一个事实:[`href`属性上的命名空间已从标准中删除](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use)。当然,这只是 XML 复杂性的冰山一角。
另一个最大的问题是,出于某种原因,SVG 的作者认为有必要为诸如 `<path>` 元素的 `d` 属性的写法打开方便之门,比如可以添加逗号或不添加逗号,在 `”45-67″`中不需要空白,因为可以解析为 `(45,-67)`等等。这些都不是无用的东西,但最终复杂性会超过最小值。
我发现基于文本的格式在很多方面都要好得多。只要看看如今网页的丰富外观,几乎所有这些都是使用基于文本的格式完成的。它们真的很强大,而且在需要时,还可以使用通用算法进行压缩。
这样的格式?https://en.wikipedia.org/wiki/Extensible_Binary_Meta_Languag…
> 决定一种语言是为人类使用还是为机器使用,然后做其中一件事。并做好其中一件事,而不是两件事都做,但做不好。
问题在于,所有这些语言(ASM、C、XML、JSON、Python 等)从根本上说都是关于人与机器之间的交流。我们需要在使其易于解析(对机器而言)或易于读写(对人类而言)之间做出权衡,但它们都必须同时满足这两种需求。当你的问题领域像 “二维矢量图形 “或更糟糕的 “网络 “这样大时,复杂性是不可避免的。
我并不是说我们不能做得比 SVG 更好。我同意作者的许多观点,并希望看到一个易于手写的 SVG 最小子集。取舍是工程上的决定,也很重要。但不要假装你可以选择一个目标,比如 “方便人类”,而忽略语言设计问题的所有其他方面。
您说得非常对,这始终是一个权衡问题。为了解决这个问题,我在文章末尾专门加了一段话:https://www.eisfunke.com/article/language-design-machine-or-…
> 从根本上说,这是关于人与机器之间的交流。
没错!我们不应该假设谁是交流的双方–机器还是人类。这就好比假设锤子是一种必须由人手握持的工具,从而排除了机器人操作的锤子。
文章提到 svg 支持 <script> 标记…最酷的用法:https://www.xul.fr/svgtetris.svg
FlameGraph [1] 将剖析结果渲染为 svg。剖面图基本上是分层的;用户可以通过点击某个元素放大到子树中。在 svg 中使用脚本可能并不令人振奋;但好家伙,这个功能真是方便极了!
https://gist.githack.com/mejedi/90eac4f11f794f43808f90e38b1a…
[1] http://www.brendangregg.com/flamegraphs.html
这里有一个完全利用这一优势的掷骰子器/虚拟桌面: https://github.com/sjbrown/togetherness
用 SVG 制作俄罗斯方块??
我的感觉是”太美了”、”太变态了”、”我也想这么做”
酷吗?看看这个:https://www.scriptol.fr/xml/code/invaders.svg
看来法国人对动态 SVG 情有独钟。
太空入侵者太神奇了
这是一个 SVG 包含脚本标签的例子,还是一个通过 javascript 操作 SVG DOM 的例子?我认为这是两个不同的问题。浏览器已经能理解这两种情况,我认为这篇文章把它归入 “糟糕 “一类,是因为如果你要从头开始构建一个渲染器,你还需要处理 javascript 和 DOM 的事情。
Wow.我都不知道自己是该佩服还是该害怕了。我已经添加了文章链接,谢谢。
我都是
不那么令人印象深刻的是一个时钟:https://www.nayuki.io/res/full-screen-clock-javascript/full-…(50行代码)
我喜欢这个藏在维基百科上的东西:
https://upload.wikimedia.org/wikipedia/commons/6/6c/Morphing…
变形数字时钟
哦,天哪。很久很久以前,我在 Adobe 工作。我是 SVG <script> 标签的测试工程师,主要是确保 DOM 方法都能正常工作。那时候有很多有趣的微型项目。
最让我引以为豪的是一个三维化学浏览器,你可以抓住分子并旋转它。使用 SVG 只是因为它方便做可视化。所有的 3D 变换都是用 Javascript 完成的。但在 2000 年,能够流畅地旋转 3d 模型的 Javascript 已经非常了不起了。
酷,感谢分享!
顺便提一下,OP 在给您的回复中发布了更新:
> 这篇文章发布在 Hacker News 上…> 在评论中,有人提到了 SVG 中 <script> 标记的一个有趣用法。我不知道自己是该感到惊讶还是惊恐:D
哇,这真是太神奇了(也有点恐怖)。我从来不知道 SVG 可以包含 Javascript。我一直以为它只是一种安全的矢量图形标记。
我本想直接写一页尖叫声,但我觉得这样写在这里不太合适。
“为什么在最初实现 SVG 的 18 年后,我还在为浏览器有不同的 SVG 实现而苦恼?”两天前,当我们徽标中的逗号神奇地只在 Firefox 上向左移动时,我不得不这样问自己。
看起来,这里的规范要负部分责任,因为 800 页的内容即使是最严谨的开发团队也很难在不与其他实现方式产生分歧的情况下实现。
我决定改用高质量的 PNG,今天就到此为止,因为我们还有其他更重要的事情要做。
不仅仅是规范。根据我的经验,你需要一个全面的测试套件,实现者可以用它来测试自己是否涵盖了边缘情况。
我一直对 “低代码 “问题很感兴趣,尤其是 20 世纪 90 年代用于尝试 “在图形用户界面中编辑 UML 图表,并以专业程序员的方式修改 Ada 源代码 “的那种高级解析器。
在被 Adobe 收购之前,Dreamweaver 曾经为 HTML 做过这些工作。如今,Dreamweaver 似乎可以在 90 太赫兹的电脑上使用,但在输入 “Hello World “后,我可以做 10 个俯卧撑,等待用户界面稳定下来。
分屏式 SVG 编辑器会特别好,因为编辑 SVG 文件的大部分工作都是为了正确计算数字。你会遇到很多有趣的问题,比如向用户展示十进制数学(无论使用的是什么浮点数,除非你以 1/2、1/5 的系数 “捕捉网格”,否则你的 git 提交都会很糟糕)。
我特别想做的是控制文档的结构,这样我就可以像程序员一样对元素进行分组。
这样的工具可能还是不能让人满意,因为贝塞尔曲线的出现是为了让人们觉得自己的计算机制图能力很差,并取代了当时获得专利的更好的替代品。我震惊地发现,我最喜欢的角色设计师竟然不知道如何用贝塞尔曲线来绘制动漫角色。
这就是您所说的群组吗?
“<g> SVG 元素是用于分组其他 SVG 元素的容器。
应用于 <g> 元素的变换在其子元素上执行,其属性由其子元素继承。它还可以对多个元素进行分组,以便以后使用 <use> 元素进行引用。”
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
大部分是
这是将 “编程 “或 “架构 “规范应用于 SVG 的最主要工具。
例如,你可以制作一个看起来像猫爪的 <g>,然后 <使用> 它来制作一个猫爪轨迹。这比 “剪切-粘贴 “一个你画了 10 次的猫爪更有条理,真正的艺术家可能会这么做,我也可能会这么做,因为我总能想出如何用绘图程序来做。
与此相关的是 CSS 的使用,它可以是易于理解的漂亮代码,也可以是一团糟的代码。
我是作者,在手工编辑 SVG 时,我使用 VSCode(准确地说是 VS Codium)和 SVG 浏览器插件分屏:https://marketplace.visualstudio.com/items?itemName=cssho.vs…
作为分屏编辑器,效果相当不错。使用ctrl-S保存时,预览会刷新。
SVG 实际上是我计划在 https://concise-encoding.org/ 和参考实现完成后首先解决的主题之一。
你肯定不想通过转向另一种基于文本的格式来解决 SVG 的臃肿问题。
你还打算解决这个问题吗?
是的!只是 CE 规格所需的时间比我预计的要长得多;-)
CE 规范已经完成(我预计不会再有任何改动),参考实现也已进入最后阶段。之后是模式格式,然后是正式的 V1 版本,然后我就可以继续开发建立在此基础上的技术了。
根据我最近进行的一些事后计算,我应该可以用相同的基本结构(这样你就可以在它们之间进行转换)来表示相同的矢量图形,但只需要大约 1/3 的空间(不包括 CSS 和 JS 等疯狂的东西)。
我来这里是为了分享我最喜欢的 SVG 资源:
http://slides.com/sdrasner/svg-can-do-that
莎拉-德拉斯纳(Sarah Drasner)是个了不起的人,尽管她的文章已经发表了 4 年(!),但它仍然具有现实意义和启发性。
以下是幻灯片附带的演讲:https://www.youtube.com/watch?v=dv2TvTXQ4FQ (36min)
SVG 的真正丑陋之处在于,我们经常向设计师或公司索取 SVG,而他们递给我们的 SVG 文件却只包含一个 base64 编码的 PNG 图像。
很多矢量编辑程序在遇到困难时就会作弊。我见过把阴影变成位图、把路径交叉点变成带有无数线段的多段线、把元素弄丢等等。做矢量图很难,除了基本的形状之外,我感觉有些开发人员和公司一开始就低估了他们要做的事情,然后不得不依靠变通方法来实现某些功能。
上次我需要 SVG 的时候,我放弃了,直接用 Vim 输入了。
我对 SVG 的两个不满(尽管第二个不满更多是针对浏览器的实现)。
1.它不支持预乘法 alpha 插值模式。如果您曾导入部分透明的光栅化图像,那么它可能会在不透明区域的边缘造成明显的伪影。
2.据我所知,目前还没有一款软件支持在线性色彩空间(linearRGB [1])中进行插值。
因此,尽管它很臃肿,但仍然缺少一些功能。尽管浏览器非常适合支持线性色彩空间,但它们仍然懒得执行完整的规范。而他们在实现 PDF 时,会使用更多的渐变元素和色彩插值模式。
[1] https://www.w3.org/TR/SVG11/painting.html#ColorInterpolation…
缺少的其他内容:
– 相对坐标。您可以通过在 SVG 文档中使用其他 SVG 文档来解决这个问题,但这实际上只是一种破解方法。
– 圆锥渐变。即使 CSS 也有。
此外,SVG 还存在一些实现上的 bug。过去几年,Chromiums 和 Firefox 团队在修复 Bug 方面做得非常出色,但如果你做的是先进的东西,就难免会遇到这些 Bug。此外,Safari 对 SVG 也不太擅长,但老实说,谁在乎呢。
> 相对坐标。您可以通过在 SVG 文档中使用其他 SVG 文档来解决这个问题,但这实际上只是一种破解方法。
您也可以使用 <def/> 来实现类似的功能。
如果您正在寻找一种具有类似 SVG 成像模型的机器可读矢量图形格式,那么现在已经有这样一种格式了:AI4
AI4 是 Adobe Illustrator 4.0 的缩写。Gnuplot 和 Mathematica 可以生成 AI4 文件。大多数矢量图形程序也可以打开 AI4 文件。
文档如下: http://www.idea2ic.com/File_Formats/Adobe%20Illustrator%20Fi…
SVG 的前身是 postscript 和 PDF,而 postscript 和 PDF 又是 SVG 的基础。
postscript 语言参考手册长达 912 页。
https://www.adobe.com/jp/print/postscript/pdfs/PLRM.pdf
PDF 参考手册共 978 页。
https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pd…
SVG,如果比两者都少,实际上做得很好…
在我看来,这三种技术和随附的文档都是杰作,尽管臃肿不堪。钻研这些参考文档几乎是一种乐趣
作者关于 SlimSVG 的想法听起来很有趣,但我认为仅仅关注文件格式是不够的–SVG 的一个强大功能是它是 DOM 的一部分。还有比 DOM+JS 更好的动态文档系统吗?
例如,JSON 格式的文档对象模型(也许可以使用 JSON 模式),允许使用 JSON 补丁进行更新,并使用客户端/服务器模式进行更新。(DOM 还有更多内容)
我个人认为 XML 非常适合这项任务,很高兴能从这个主题中了解到 SVG Native。
我希望在 “丑陋 “部分提到的一点是,允许使用 Javascript 以及在一定程度上使用 XML 会带来安全问题,例如潜在的 XSS(因为 javscript)、XXE(因为 XML)等。只要小心谨慎,就能避免漏洞。但你必须小心谨慎,知道要注意什么。
> 如果你不把它编译成 PDF 格式(这也是一种可怕的格式,而且非常臃肿,但它很好)
是啊…PDF 在某些方面可能更糟糕(而且还可能有 javascript)。对于 SVG,使用 SVG 的子集生成图像并不难。但对于 PDF,仅仅制作一个有效、有用的 PDF 就相当复杂,而且需要对规范有相当的了解(这一点非常重要)。要正确呈现任何有效的 PDF 可能更难。
> 可能基于 JSON,但绝对不是基于 XML。
如果我们要重新开始,那就创建一种从头开始专门构建的新语法。JSON 并没有复制 XML 在这种用途上的所有缺点,但它复制了很多缺点。比如,所有导致主要 XML 格式在字符串中嵌入自己的迷你 DSL 的因素在 JSON 中也同样存在。
在我们的行业中有这样一种传统,也许是对 90 年代 “不是在这里发明的 “综合症的一种反应,就是习惯性地把已经存在的零碎东西拼凑在一起。似乎没有其他原因,只是因为它们已经存在,而且可以被黑。我最近开始称之为 “华莱士和葛罗米特工程学”。
我喜欢 SVG。我用它来制作整洁的交互式家谱图表(可点击的 URL):
https://progenygenealogy.com/Portals/0/images/charts/Kennedy…
和扇形图:
http://findyourfamilytree.com/images/131.html
如果要以文本格式编写自己的图形,我认为 PostScript 是不错的选择;然后,如果有驱动程序,您可以以任何想要的格式(可以是光栅或矢量格式)进行输出。但如果你想存储矢量图形的结果,就需要不同的格式,我认为 PDF 和 SVG 都不是很好,PostScript 也不是很好(虽然它是矢量图形的编程语言,但它是一种编程语言,而不是矢量图形格式)。
Ghostscript 没有 SVG 输出驱动程序,不过你可以先输出为 PDF,然后使用其他程序将 PDF 转换为 SVG。如果他们制作了 SlimSVG 或其他矢量格式,那么希望可以提供该格式的 Ghostscript 驱动程序,以便可以从 PostScript 程序中生成该格式。
然后,你就可以使用任何编程语言(无论是 PostScript、Haskell 还是其他语言)来生成 SlimSVG 或其他任何格式。
这篇文章的论据并不充分。这篇文章,以及前面那篇人类与机器可读性的文章,都只是泛泛而谈,却没有指出任何实例。我不觉得它能说服任何不熟悉相关问题的人。
这很可惜,因为实际上我同意其中的很多观点。
网络 “标准 “严重失灵。我们无法构建交互式图表等工具,例如 ERD 编辑器,因为图表和绘图工具与数据输入工具(输入标签等)是分开的。而且它们仍然不直接支持丰富的图形用户界面。因此,许多常见的用户界面习惯必须通过臃肿、错误百出、速度缓慢的 JavaScript 库重新发明。
我建议对网络标准进行重构,并将其分为三类:A) 艺术、媒体和娱乐。B) 文档和小册子,以及 C) CRUD、图形用户界面、数据、生产力
它们将尽可能多地重叠,但也可以更好地专注于各自的细分领域。
最近,我不得不在一个涉及浏览器动画的项目中决定使用 Canvas 还是 SVG。我想使用反应式框架(具体来说是 VueJS),因此选择了 SVG。整体图像的各个部分都存储为 Vue 组件。动画就像元素中的 vue 绑定一样简单。与之相比,Canvas 的构建要复杂得多,也更难管理。这样做的代价是性能损失。在帧速率下降之前,你只能操作 SVG 的这么多部分。但对于我的项目来说,代码复杂度的降低似乎是值得的。
无论是好的,坏的,还是难看的,我都很高兴能将 SVG 直接嵌入 html 文件,然后用 Javascript 对其进行操作。当你在教学时,把所有东西都放在一个文件里,学生可以在浏览器中打开,这样生活就更轻松了。
我认为 XML 没有任何问题。至少在基本形式上是这样。我广泛使用它(经常借助 notepad++ / notepadqq 进行手动编辑),没有任何问题。我也不是专门的网络开发人员。
我非常欣赏这篇文章。如果能看到一个更小的 SVG 图形标准,那将会非常棒。我认为 SlimSVG 这个名字不好,因为它意味着它仍然是 SVG。它应该与众不同。这只是我的看法。
在我看来,SVG 之所以臃肿,并不在于它是为人还是为机器设计的,因为与过滤器、CSS 动画、交互性、在不同上下文中的高级渲染选项等功能相比,这些都是无关紧要的……
关于标准形状的简单使用,您可以将自己限制在 SVG 中的简单形状上:这样您就已经有了无数现有的实现方法和工具,而且大部分都是人类可以理解的、简短的、可以用手工/简单脚本编写的。
你甚至可以称它们为移动 SVG Tiny and Basic:它从 2009 年就存在了。https://www.w3.org/TR/2003/REC-SVGMobile-20030114/。这将是一个良好的开端。
我最近在 “深入研究”(好吧,只是大量的思考和试错)如何在我即将发布的纸牌游戏(想想《大富翁交易》)中使用 SVG 或 CSS。
天啊,这真是个兔子洞。我从主要使用 CSS 实现图形用户界面,到主要使用 SVG 实现图形用户界面,现在又回到了主要使用 CSS 而不是 SVG。
最大的问题是模糊!”缩放带有文字的扑克牌(transform:scale|scale3d 等……)–最终看起来很模糊。这些都是我手工 “编码 “的基于 html 的虚幻 SVG。
> 一个好主意是开发一种简单的矢量图形交换格式,以便于机器处理。尽可能减少功能。也许可以基于 JSON,但绝对不能基于 XML。
在此说明一下,这种格式已经存在,而且相当流行,请参见: https://lottiefiles.com/
Lottie 文件是由 Adobe After Effects 的 Bodymovin 插件生成的 JSON 文件。
这些文件主要用于制作简短的矢量动画,但也可用于制作静态图像。
SVG 是我最喜欢的网络语言。它很好,而且离伟大很近。老实说,我觉得如果除了 XML 之外,SVG 几乎还能做其他任何事情,那它就会更上一层楼。
我认为这篇文章完全忽略了 SVG 在用户界面/用户体验方面的优势。举例来说,我已经能够实现一些令人惊叹的动画,这些动画几乎不需要我费什么力气,就能让设计师真正展示他们的才华。
SVG 也许并不完美,但绝对利大于弊。当我在前端工作时,我认为很少有使用案例需要担心 SVG 的可读性。作者还让我对基于 JSON 的图形失去了兴趣。
一个人的臃肿就是另一个人的功能。SVG 中的大多数 “臃肿 “和支持不一致问题都出现在 SVG 文本、过滤器、动画和 DOM 界面中。如果你进行的是 OP 想要创建的基本绘图,就不会遇到这些问题。基本的 SVG 绘图非常简单,而且老实说非常紧凑,有很多快捷方式和合理的默认设置。(除了标记–这很糟糕)。
已有 ivg https://github.com/reactivego/ivg
是的,这是 IconVG 文件格式的渲染器。正如我之前所说:
IconVG 是一种紧凑的二进制格式,适用于简单的矢量图形:图标、徽标、字形和表情符号。
IconVG 的概念类似于 SVG(可缩放矢量图形),但要简单得多。与 “SVG Tiny “相比,它不具备文本、多媒体、交互性、链接、脚本、动画、XSLT、DOM 以及与光栅图形(如 JPEG 格式的纹理)相结合等功能。
该公告位于 https://groups.google.com/forum/#!topic/golang-nuts/LciLeI5p… 并引自该公告:
“SVG 规范共 400 页,不包括 XML、CSS 或 XSLT 规范。[包括文件格式规范的 IconVG godoc.org 页面打印出来有 26 页]…
材料设计图标集……由 961 个矢量图标组成。作为 SVG 文件,总计 312,887 字节。24 * 24 像素的 PNG 文件,190,840 字节。48 * 48 像素 PNG 文件,318,219 字节。作为 IconVGs,122,012 字节”。
我曾经想过把 Radial Menu [1] 移植到 SVG,但在花了一个小时摆弄代码之后,我就放弃了。真是一团糟。我记得在某处读到过:”如果你是从画布编程过来的,你可能会觉得画圆有违直觉”–是的,我是这么觉得的。
1 – https://github.com/victorqribeiro/radialMenu
>喜欢手写
老实说,我对有人手写 SVG 感到非常震惊。
我这样做是为了创建模板(用 jinja2 创建的 svg),然后通过解析生成独特的 svg 图像。
Inkscape 制作了一个不错的初始模板,但在命名、缩放、文字包装和嵌套方面不够精细和精确。Inkscape 生成的 XML 相当混乱。没有明确的 IDS、四舍五入错误、通过组任意嵌套、任意排序等。
例如,能够打开文件快速更改图形的填充颜色就很不错。
我第一次使用 inscape 时,由于 inscape 的元数据,我编辑的简单徽标的文件大小增加了 6 倍,因此我只能手动更改。
我用过,但只是用在一些非常简单的地方,比如用一小撮彩色圆圈构建一个徽标。对于更复杂的工作,我当然不会推荐使用它。
其实并不难…
但是,是的,我做到了。做了很多次。我甚至还做过一次 SVG 路径到 G 代码的转换。
XML 不是为文档(即主要是文字的文本,如技术手册)而开发的吗?这不就是 xml 文件被称为 XML 文档的原因吗?在我看来,任何用它来存储数据的人都用错了工具。
这些都是我一直在思考的问题,因为我目前正在专门为用户界面设计师编写一种类似于 svg 的语言。他说的关于人类语言和机器语言的问题非常正确;这是一个很难回答的问题。
最近从 SVGs 转向了 PNGs,因为设计师使用的工具集意味着每个 SVG 都有相同的 HTML ID 属性值。因此,当在一个页面上呈现 >1 个 SVG 时,它们都会呈现出与 dom 中最后一个相同的效果。
看看 SVG 注入。这可能会解决你的问题,因为注入器会为你的 SVG 添加一个唯一的 ID:
https://github.com/iconfu/svg-inject
将 SVG 放大作为工作流程的一部分(例如 svgo)对于所有这些边缘情况来说都是救命稻草。
特别是考虑到设计工具生成的 SVG 通常非常巨大。另外,我发现 svgcleaner 比 svgo 更好。根据我的经验,svgo 似乎有更多的 bug,而且更经常在 svg 上窒息。
注意到,谢谢。
我对大多数 SVG 都是这样处理的:https://jakearchibald.github.io/svgomg/
“SVGO缺失的图形用户界面”。把它交给设计人员,他们就能确保为您提供尽可能小且合理的文件。我发现有些文件在精度为 “0 “时看起来很好,而有些则需要 “1 “或 “2”。
只是使用指向 SVG 的 img 标记吗?
那么基于 JavaScript 的 SVG 节点操作就不起作用了。
但家长说他们改用了 PNG,问题也一样,对吗?
我决定从 SVG(可在构建时对属性(比例、颜色、旋转等)进行操作)转向图像优化库(不久可能会转向类似 imgix 的 saas)。
如果不是因为 I’d 碰撞的事情,我更愿意坚持使用 SVG,所以有了这些工具中的一个,我们就可能做到这一点。
指向 SVG 的 IMG 标签没有 ID 碰撞,因为 SVG 处于孤立的上下文中,它对引用页面是不透明的,因为它被当作其他 img 引用。
我们使用了一些服务器端代码,通过缓存标题对 SVG 进行实时重新着色,这样就不会一直请求着色,主要是通过 img 标签,因为我们已经从 PNG 转向了 SVG,它就是这样工作的。
在这种使用情况下是不行的。原因很简单,因为在 img 标记中使用 SVG 时,我们无法操作 SVG 的属性(至少不那么容易)。但在 “内联 “时可以。我们不情愿地采用了 PNG,并说服设计师提供各种尺寸和颜色的资产,这使他们的工作量增加了一倍甚至两倍,而这只是因为我们在拖延时间,试图找到替代方案(我们已经开始为 PNG 颜色转换等建立自动化链条)。展望未来,我将尝试使用一种或几种 SVG 优化器,并尝试回到构建/运行时 SVG 属性操作。这才是 SVG 的初衷。
使用内联 SVG 还能大大降低缓存的复杂性。我现在 “只是 “缓存标记,没有二进制资产缓存。
今后,我将尝试使用
是的,对不起,我就是不明白,你不能使用 SVG 的图像标记,因为无法对其进行操作,但你可以使用 PNG,这就更难操作了,而且是 img 标记,对吗?
至少,SVG 作为图像可以调整大小,因此无论大小如何,你只需要一个资产,而颜色处理则是个问题,但由于 SVG 只是 xml,因此在服务器端很容易完成,浏览器也会像处理其他图像一样处理缓存。
我们突然发现我们的图标等全部使用的是上次加载的 SVG 的样子,于是就匆忙改用了 PNG。我们已经有了一个 PNG “解决方案”(更像是一个黑客。有人记得如何使用 imagemagick 设置一些构建时对 PNG 的操作 — 我们甚至没有检查是否可以对 SVG 做这样的操作,我们只是想尽快解决这个问题),再加上设计人员主动提出将大部分变体导出为 PNG,我们根本没有进行太多讨论,剩下的我们就用 imagemagick 黑客解决了。
因此,我们跳转到了 PNG 格式(大约两周前,仅供参考)。现在我们(知道并)可以使用其中一种 SVG 清理工具了,我们将改用它,然后再回到内联 SVG。
PNG 一直被视为次品。我们不希望有额外的请求来加载它们–我们的应用程序对请求数量非常敏感–我们甚至将它们作为数据线导入。
总之,我们做出了选择。现在,我们有 90% 的可能会恢复内联 SVG,并在管道中使用某种清洁器。请不要为此失眠。我们会没事的。
与此无关。但为什么这个网站需要一个粘贴式页眉?在小显示器上太浪费空间了。别再为 30 英寸的屏幕设计了!
> 一个好主意是开发一种简单的矢量图形交换格式
啊,对了,老好人 https://xkcd.com/927/