图案

Patterns 可能是 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> 元素内部,您可以包含之前使用过的任何其他基本形状,并且可以使用您学过的任何样式来设置它们的样式,包括渐变和不透明度。在此示例中,我们在模式内绘制了两个矩形元素(它们会重叠,其中一个的大小是另一个的两倍,并且用于填充整个模式),以及一个圆形。

关于模式令人困惑的地方在于定义单位系统和尺寸。在上面的示例中,我们在 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" 单位进行绘制,除非有必要。

这两种用法都不是人们通常想到“图案”时所想的。图案通常具有固定的尺寸,并独立于对象的形状而重复。要创建类似的东西,图案及其内容都必须在当前用户空间中绘制,这样它们在对象改变形状时不会改变。

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.