在SVG中从另一个圆中减去一个圆

Posted

技术标签:

【中文标题】在SVG中从另一个圆中减去一个圆【英文标题】:Subtract one circle from another in SVG 【发布时间】:2014-04-30 01:04:59 【问题描述】:

我正在尝试找到一种方法,在 SVG 中从另一个形状中减去一个形状,在中间创建一个洞或从它的侧面咬出一个洞。有点像剪切路径,但不是显示交叉点,我想显示交叉点外的一个部分。 One solution 涉及使用 Adob​​e Flex,但我不知道如何正确实施。我知道在 Inkscape 中有一种方法可以使用布尔路径操作来执行此操作,但我想保持圆形元素的原样,而不是将它们更改为路径元素。

<defs>
    <subtractPath id="hole">
        <circle r="50" cx="100" cy="100" />
    </subtractPath>
</defs>
<circle id="donut" r="100" cx="100" cy="100" subtract-path="url(#hole)" />

【问题讨论】:

【参考方案1】:

诀窍是使用fill-rule 来控制剪辑路径的显示。一个(方形)甜甜圈的例子是

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg"
  >
<defs>
</defs>
   <g transform="translate(50, 50)">
      <path d="M 0 0 L 0 200 L 200 200 L 200 0 z
               M 50 50 L 50 150 L 150 150 L 150 50 z" fill-rule="evenodd"/>
   </g>
</svg>

这使用形状的填充规则属性来删除内部正方形 - 您可以调整它以使用贝塞尔路径来完成,以根据需要创建一个圆。

创建基本剪辑路径后,您可以从中创建剪辑路径 - 有关剪辑路径的信息,请参阅 this MDN entry。

【讨论】:

【参考方案2】:

面具就是你想要的。要创建&lt;mask&gt;,请将您想要保留的内容设为白色。你想要隐形的东西会变黑。中间的颜色会导致半透明。

因此生成的 SVG 类似于您的伪标记,如下所示:

<div style="background: #ddf">
  <svg  >
    <defs>
      <mask id="hole">
        <rect   fill="white"/>
        <circle r="50" cx="100" cy="100" fill="black"/>
      </mask>
    </defs>

    <circle id="donut" r="100" cx="100" cy="100" mask="url(#hole)" />

  </svg>
</div>

我们用一个白色矩形填充蒙版,然后在我们想要的孔位置放置一个黑色圆圈。

【讨论】:

是的,这就是我要找的。我没有想过在面具中使用两个形状。它可以在我的浏览器中运行,但对于我的一生,我无法让它在 Inkscape 中运行。它所做的只是显示大圆圈。会不会是 Inkscape 的错误? 回答我自己的问题,只要一个组包含掩码中的元素,它就可以在 Inkscape 中工作。 有什么办法可以改变颜色吗?比如如果我想让黑色圆圈部分是白色的,而中间的圆圈是半透明的呢? 当然可以。只需设置填充:&lt;circle id="donut" r="100" cx="100" cy="100" mask="url(#hole)" fill="white" /&gt; @Shivam 是的。但是过滤器是在遮罩之前应用的,所以您只需将其包装在一个组中,然后将过滤器应用于该组即可。 jsfiddle.net/86jnkr3L【参考方案3】:

两个答案建议 (1) 使用 或 (2) 使用“fill-rule=evenodd”属性从形状 A 中减去形状 B em> (A ∖ B).

两个建议的答案都解决了问题的“中间的洞”(B ⊆ A) 部分,但只有 mask 方法是解决“咬伤”的合理解决方案出边”部分(B ⊈ A)。使用 evenodd 填充规则意味着两个形状被平等对待,因此第二个形状不与第一个相交的部分将成为结果的一部分。为了咬出某种形状,“咬”形状必须与被咬形状共享部分边界。这在实践中可能很难实现。

一个例子:为了从另一个圆中减去一个圆,您必须创建一个“咬合”形状,它是两个圆的交点。

掩码方法更为普遍。

【讨论】:

这并不能真正回答原始问题。我害怕作为一个真正需要的答案。如果删除其他答案中的一个或两个,则很难理解您的意思。 @RobertLongson:感谢您指出这一点。我不知道可以删除答案。所以我想我的将被删除而无需任何进一步的操作。 为什么不把它转换成可以回答问题的东西呢?【参考方案4】:

|*|蒙版:用于减去对象:

|=> fill="white" => 要显示的块 |=> fill="black" => 要删除的块

|=> fill="white" => 将显示块也放在掩码标签内并填充白色 |=> fill="black" => 将 Remove Block 放在 mask 标签内并填充黑色

|::|使用掩码从大矩形中删除中心小矩形的示例

<rect x="20" y="20"   mask="url(#rmvRct)"/>
<mask id="rmvRct">
    <rect x="20" y="20"   fill="white"/>
    <rect x="40" y="40"   fill="black"/>
</mask>

|::|使用掩码从大圆中删除中心小圆的示例:

<circle cx="50" cy="50" r="45" mask="url(#rmvCir)"/>
<mask id="rmvCir">
    <circle cx="50" cy="50" r="45" fill="white"/>
    <circle cx="50" cy="50" r="25" fill="black"/>
</mask>

【讨论】:

以上是关于在SVG中从另一个圆中减去一个圆的主要内容,如果未能解决你的问题,请参考以下文章

如何从一组重叠的圆中计算出一组多边形?

ACM_素数环

2015 NCPC Problem G-Goblin Garden Guards

在 Swift 中从另一个 ViewController 访问变量

在 SQL 中从另一个表更新一个表的最佳方法是啥?

如何在 Nuxt 中从另一个访问一个 Vuex 状态?