模式

模式

模式可以说是 SVG 中比较令人困惑的填充类型之一。它们功能强大,因此值得讨论并至少掌握其基本概念。与渐变一样,<pattern> 元素应放在 SVG 文件的 <defs> 部分。

html
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="Gradient1">
      <stop offset="5%" stop-color="white" />
      <stop offset="95%" stop-color="blue" />
    </linearGradient>
    <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
      <stop offset="5%" stop-color="red" />
      <stop offset="95%" stop-color="orange" />
    </linearGradient>

    <pattern id="Pattern" x="0" y="0" width=".25" height=".25">
      <rect x="0" y="0" width="50" height="50" fill="skyblue" />
      <rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)" />
      <circle
        cx="25"
        cy="25"
        r="20"
        fill="url(#Gradient1)"
        fill-opacity="0.5" />
    </pattern>
  </defs>

  <rect fill="url(#Pattern)" stroke="black" width="200" height="200" />
</svg>

<pattern> 元素内部,您可以包含之前包含的任何其他基本形状,并且可以使用之前学习的任何样式对其进行样式设置,包括渐变和不透明度。在这里,我们只是在图案内部绘制了两个矩形元素(它们重叠,其中一个的大小是另一个的两倍,用于填充整个图案)和一个圆形。

关于模式令人困惑的一点是定义单位系统及其大小。在上面的示例中,我们在模式元素上定义了 widthheight 属性来描述模式在开始重复自身之前应该延伸多远。如果您想将此矩形的起始点偏移到绘图中的某个位置,还可以使用 xy 属性。此处使用它们的原因在下面进行了描述。

与上面使用的 gradientUnits 属性一样,模式也具有一个属性 patternUnits,它指定这些属性将采用的单位。它默认为 "objectBoundingBox",如上所述,因此值为 1 将缩放为应用模式的对象的 widthheight。由于在这种情况下,我们希望模式水平和垂直重复 4 次,因此 heightwidth 设置为 0.25。这意味着模式的 widthheight 仅占总框大小的 0.25

与渐变不同,模式具有第二个属性 patternContentUnits,它描述了模式元素内部、基本形状本身使用的单位系统。此属性默认为 "userSpaceOnUse",与 patternUnits 属性相反。这意味着,除非您指定这两个属性之一或两者(patternContentUnitspatternUnits),否则您在模式内绘制的形状将在与模式元素使用的不同的坐标系中绘制,这在您手动编写时可能会造成一些混乱。

为了使这在上面的示例中起作用,我们必须考虑框的大小(200 像素)以及我们希望模式水平和垂直重复 4 次这一事实。这意味着每个模式单位都是一个 50×50 的正方形。然后将模式内的两个矩形和圆形调整大小以适合 50×50 的框中。我们在该框之外绘制的任何内容都不会显示。模式还必须偏移 10 像素,以便从框的左上角开始,因此必须将 patternxy 属性调整为 10÷200 = 0.05。

这里的警告是,如果对象的大小发生变化,模式本身将缩放以适应它,但内部的对象不会。因此,虽然我们仍然在模式内部有 4 个重复单元,但构成该模式的对象将保持相同的大小,并且最终会在它们之间出现大片空白区域。通过更改 patternContentUnits 属性,我们可以将所有元素放入相同的单位系统中。

xml
 <pattern id="Pattern" width=".25" height=".25" patternContentUnits="objectBoundingBox">
   <rect x="0" y="0" width=".25" height=".25" fill="skyblue"/>
   <rect x="0" y="0" width=".125" height=".125" fill="url(#Gradient2)"/>
   <circle cx=".125" cy=".125" r=".1" fill="url(#Gradient1)" fill-opacity="0.5"/>
 </pattern>

现在,由于模式内容与模式位于相同的单位系统中,因此我们不必偏移框以使模式从正确的位置开始,并且如果对象的大小更改为更大的大小,模式将自动缩放,以便在其中具有相同数量的对象和重复次数。这与 "userSpaceOnUse" 系统形成对比,在该系统中,如果对象更改大小,模式将保持不变,并且只需重复更多次以填充框。

顺便说一句,在 Gecko 中,如果圆形的半径设置为小于 0.075 的值,则似乎会出现绘图问题(目前尚不清楚这是模式元素中的错误还是其他问题)。为了解决这个问题,最好避免在 "objectBoundingBox" 单位中进行绘制,除非您必须这样做。

以上两种用法都不是您想到模式时通常会想到的。模式通常具有固定的大小并独立于对象形状重复自身。要创建类似这样的内容,模式及其内容都必须在当前的 userSpace 中绘制,因此如果对象发生变化,它们不会改变形状。

xml
 <pattern id="Pattern" x="10" y="10" width="50" height="50" patternUnits="userSpaceOnUse">
   <rect x="0" y="0" width="50" height="50" fill="skyblue"/>
   <rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)"/>
   <circle cx="25" cy="25" r="20" fill="url(#Gradient1)" fill-opacity="0.5"/>
 </pattern>

当然,这意味着如果您稍后更改对象大小,模式将不会缩放。以下三个示例显示在矩形上,该矩形已略微拉长,高度为 300px,但我应该注意,这不是详尽的图片,根据您的应用,还有其他选项可用。

Three examples showing patternUnits values of default and userSpaceOnUse and patternContentUnits values of default and objectBoundingBox. When both are set to default, the aspect ratio is maintained with white space visible. Setting patternContentUnits to objectBoundingBox effects the aspect ratio to remove white space. Setting patternUnits to userSpaceOnUse maintains the aspect ratio while eliminating white space.