如何在不使用Javascript或扩展/侵蚀过滤器的情况下在SVG中实现偏移路径效果?

时间:2012-10-04 09:04:01

标签: javascript vector svg effect

我有一个很长时间的项目:一个基本的矢量图形工具,它在浏览器中运行并使用SVG和Javascript(也许你已经在其他地方看到了其中的一些)。该工具只有非常有限的功能集,因为受众受限制且目的非常具体,事实上不允许其他功能超出明确允许的范围(您知道)。一个遗漏的特征是侵蚀(也称为插入或薄)和扩张(开始,加粗,加粗)多边形和其他图形元素。

我多次使用过Adobe Illustrator的偏移路径效果,我可以轻松地复制稀疏或加厚的图形对象,而不会影响原始对象,因此几乎可以支持程序。

我试图在SVG中使用相同的功能,但没有成功。

我尝试过以下方法:
- 扩张和侵蚀过滤器,但结果不令人满意(please see the image here
- 服务器端Python的Shapely库,但这种解决方法太慢,只允许插入或开始基本多边形(description here
- 找到javascript库/代码/函数,它可以改变图形元素的路径数据,但找不到javascript

有没有任何有意义的方法来实现这一点,如偏移路径效应和如何?

2 个答案:

答案 0 :(得分:22)

这是一个"回答你自己的问题 - share your knowledge, Q&A-style"风格的答案,但如果你有更好的答案,请自由使用你的键盘。

我使用了SO只有几天,所以请不要把我推向差距。我对这个问题有一个有趣的workaround idea,它基于可变宽度的笔画和蒙版。

但是,让我们从你(或我)的第一个想法开始吧。当我们要在SVG中侵蚀(瘦)图形对象时,首先想到的是使用侵蚀过滤器:

但是因为侵蚀过滤器(以及扩张)uses pixel data (the rasterized path),结果在所有情况下都不好看。事实上,当用于过滤矢量对象时,我从未见过好看的腐蚀。看到口和嘴:

Eroded image

扩张过滤器有类似的问题(鼻子不好,棒球帽很杂乱和其他一些不一致):

Dilated image

Adob​​e Illustrator的所有用户都知道好的路径效果,可用于将各种路径操作应用于形状(对象)。这些效果不会改变原始路径数据,它们只会创建对象的修改副本。其中最有用的是Offset Path Effect,它可用于从指定距离(或类似的东西)中选择对象。 SVG:侵蚀和扩张滤镜与Illustrator的偏移路径效果有相似之处,但质量是矢量操作(相对于位图)高。

SVG格式在其当前状态下,缺乏对类似Illustrator的偏移路径的支持,但是可以使用可变宽度笔划和掩码来获得相同的功能,如here所述。

让我们深入了解SVG蒙版的世界。通过简单地增加行程宽度可以实现扩张(或开始路径或变厚),但是侵蚀(或插入路径或变薄)需要更多的东西,例如掩模。 在SVG中,任何图形对象或' g' element可以用作alpha蒙版,用于将当前对象合成到背景中W3C SVG 1.1 Recommendation)。

上述意味着不仅可以将对象的填充用作遮罩,还可以用作笔划。 调整用作蒙版的路径的笔触宽度,我们可以控制当前对象(使用蒙版属性将蒙版应用到其中)的多少被掩盖

让我们举一个使用面具的例子。首先我们在SVG中定义一个路径:s defs元素:

<defs>
<path id="head_path" d="M133.833,139.777c1 ...clip... 139.777z"/>
</defs>

当我们在defs元素中定义路径时,它消除了在文档的其他部分重复相同数据的需要。路径的id属性用于指代文档某些点的路径。

现在我们可以在掩码中使用此路径数据:

<defs>
...
<mask id="myMask" maskUnits="userSpaceOnUse">
<use xlink:href="#head_path" fill="#FFFFFF" stroke="#000000" 
stroke-width="18" stroke-linecap="round" stroke-linejoin="round"/>
</mask>
...
</defs>

使用&#39;元素引用&#39;路径&#39;元素,其id为&#39; head_path&#39;并指示&#39; head_path&#39;的图形内容(在这种情况下仅为路径数据)。元素包含在此蒙版中。 在上面使用&#39;中定义的笔划宽度。元素将是偏移量(侵蚀)效果。这个数量被掩盖在元素之外,我们将在下面绘制它。

好的,让我们首先画一个&#39; head&#39;没有掩饰,看它是多么美丽:

...
</defs>
<use x="5" y="5" xlink:href="#head_path" fill="#4477FF" stroke="black"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>

这会产生以下形状:

Original shape

现在测试一下,使用mask可以实现什么:

...
</defs>
<use x="5" y="5" xlink:href="#head_path" fill="#22EE22" stroke="black"
stroke-width="21" stroke-linecap="round" stroke-linejoin="round"
mask="url(#myMask)"/>

以上&#39;使用&#39;指示元素使用&#39; myMask&#39;作为面具和&#39; head_path&#39;作为图形内容。蒙版效果应用于“使用”#39;元素和以下形状绘制:

Masked shape

如果我们将两者叠加在每个上面,我们可以将原始头部与蒙面头部进行比较:

Original and masked shape

一点都不差?让我们将使用SVG侵蚀过滤版本的第一次尝试与屏蔽版本进行比较:

Eroded vs masked

左边的一个被侵蚀过滤而右边的一个被遮盖以模仿类似Illustrator的偏移路径效果。帽子和嘴巴里没有奇怪的文物!

那么扩张怎么样?有没有办法消除棒球帽鼻子和油腻的路径不忠?当然。而且这种方法非常简单但有点破解。幸运的是,没有必要使用面具。相反,我们可以调整笔画宽度以达到预期的效果。并且由于笔划已用于螺栓固定,为了在螺栓形状周围获得黑色笔划(如果需要),我们必须添加一个具有更宽行程的元素的附加副本,并将其放置在螺栓形状下方:

<!-- To get the black stroke -->
<use x="220" y="5" xlink:href="#head_path" fill="red" stroke="black"
stroke-width="24" stroke-linecap="round" stroke-linejoin="round"/>
<!-- To get the boldened shape -->
<use x="220" y="5" xlink:href="#head_path" fill="red" stroke="red"
stroke-width="21" stroke-linecap="round" stroke-linejoin="round"/>

这会产生以下形状:

Offset Path Effect applied

此处原始形状和应用了我们的自定义偏移路径效果的形状:

Original and Offset Path Effect applied

我们的定制螺栓与扩张过滤器相比如何:

Dilated vs Boldened

左侧(上方)使用SVG:扩张过滤器扩张,右侧使用我们的自定义偏移路径效应进行加粗。很好,我喜欢。路径忠实地遵循给定距离处的原始路径,并且没有棒球帽上的刮擦迹象。

最后让我们将所有电线拉到一起: Dilate/Origina/Erode vs Offset Path Combined

左侧(上图)使用SVG的扩张/侵蚀滤镜,右侧使用Illustrator模拟的偏移路径效果,这是使用SVG蒙版和较粗的笔画实现的。你会选择哪一个?

结论:我们不会被迫使用Javascript或其他脚本来加粗或细化SVG中的图形元素。 SVG的腐蚀和膨胀过滤器可能有一些使用目的,但它们不适合高质量的路径修改&#34;。使用面具有点复杂,但经过一些实验后你就会熟悉它们。我真的希望将来的SVG本身可以支持Offset Path Effect,而不会像黑客那样使用它。

我对这些示例中使用的形状进行了讨论,以便您使用过滤器和蒙版:http://jsfiddle.net/7Y4am/
(至少测试改变笔划宽度!)

(抱歉,我的英语不好,让母语人士一直笑到死,但请记住,我属于94%的人,不会说英语。但幸运的是我们有谷歌翻译。)​​

答案 1 :(得分:0)

此软件包允许执行SVG路径偏移量:https://www.npmjs.com/package/@flatten-js/polygon-offset,并且自述文件提供了有关所使用算法的大量信息。