圖案
Patterns 可能是 SVG 中最令人困惑的填充型別之一。但它們也非常強大,因此值得我們花時間瞭解並至少掌握它們的基本用法。與漸變一樣,<pattern> 元素應該放在 SVG 檔案的 <defs> 部分。
<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 元素上定義了 width 和 height 屬性,以描述模式在開始重複之前應該延伸的距離。如果想將此矩形的起始點偏移到繪圖中的某個位置,還可以使用 x 和 y 屬性。此處使用它們的原因將在下面說明。
與上面使用的 gradientUnits 屬性一樣,模式也有一個名為 patternUnits 的屬性,它指定了這些屬性將採用的單位。它預設為 "objectBoundingBox",與上面相同,因此值為 1 是相對於您正在應用模式的物件 width 和 height 進行縮放的。在此情況下,我們希望圖案水平和垂直重複 4 次,因此 height 和 width 設定為 0.25。這意味著圖案的 width 和 height 僅為總盒子尺寸的 0.25。
與漸變不同,圖案有一個第二個屬性 patternContentUnits,它描述了在圖案元素內部、在基本形狀本身使用的單位系統。此屬性預設為 "userSpaceOnUse",與 patternUnits 屬性相反。這意味著,除非您指定一個或兩個這些屬性(patternContentUnits 和 patternUnits),否則您在圖案內部繪製的形狀將使用與圖案元素使用的不同的座標系繪製,這在手動編寫時可能會使事情變得有些混亂。
為了使上面的示例生效,我們必須考慮我們的框的大小(200 畫素)以及我們希望圖案水平和垂直重複 4 次的事實。這意味著每個圖案單元都是一個 50×50 的正方形。然後,圖案內部的兩個矩形和一個圓形被調整為適合 50×50 的框。在該框外部繪製的任何內容都不會顯示。圖案還必須偏移 10 畫素,以便它從框的左上角開始,因此 pattern 的 x 和 y 屬性必須調整為 10÷200 = 0.05。
需要注意的是,如果物件的大小發生變化,圖案本身會縮放到適合它,但其內部的物件則不會。因此,雖然圖案內仍然有 4 個重複單元,但構成該圖案的物件將保持相同的大小,您將最終在它們之間留下大片空白。透過更改 patternContentUnits 屬性,我們可以將所有元素置於同一單位系統中
<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" 單位進行繪製,除非有必要。
這兩種用法都不是人們通常想到“圖案”時所想的。圖案通常具有固定的尺寸,並獨立於物件的形狀而重複。要建立類似的東西,圖案及其內容都必須在當前使用者空間中繪製,這樣它們在物件改變形狀時不會改變。
<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 的矩形上,但我應該指出,這並非詳盡的示例,根據您的應用程式,還有其他選項可用。
