SVG 路徑(path)

<path>元素是SVG基本形狀中最強大的一個,它不僅能創建其他基本形狀,還能創建更多其他形狀。

另外,path只需要設定很少的點,就可以創建平滑流暢的線條(比如曲線)。雖然polyline元素也能實現類似的效果,但是必須設置大量的點 (點越密集,越接近連續,看起來越平滑流暢),並且這種做法不能夠放大(放大後,點的離散更明顯)。爲了更好的理解path,你最好用path實際畫一個 SVG圖形,雖然用XML或文本編輯器來編輯path元素不是很容易,但可以幫助我們理解path是如何工作的,所以,你就忍了吧。

上一章提到過,path元素的形狀是通過d屬性定義的,d屬性的值是一個“命令+參數”的序列,我們將學習這些命令,並且看到很多相關的示例。

每一個命令都用一個關鍵字母來表示,比如,字母“M”表示的是“Move to”命令,當解析器讀到這個命令時,它就知道你是打算移動到某個點。跟在命令字母后面的,是你需要移動到的那個點的x和y軸座標。比如移動到 (10,10)這個點的命令,應該寫成“M 10 10”。這一段字符結束後,解析器就會去讀下一段命令。每一個命令都有兩種表示方式,一種是用大寫字母,表示採用絕對定位。另一種是用小寫字母,表示採用相對定位(例如:從上一個點開始,向上移動10px,向左移動7px)。

d屬性採用的是用戶座標系統,不需標明單位。在後面的教程中,我們會學到如何讓變換path,以滿足更多需求。

直線命令 Line commands

<path>元素有5個畫直線的命令,如名字所示,直線命令就是在兩個點之間畫直線。首先是“Move to”命令,M,前面已經提到過,它有兩個參數,分別是需要移動到的點的x軸和y軸的座標。假設,你的畫筆當前位於一個點,在使用M命令移動畫筆後,只會 移動畫筆,但不會在兩點之間畫線。因爲M命令僅僅是移動畫筆,但不畫線。所以M命令經常出現在路徑的開始處,用來指明從何處開始畫。

M x y

or

m dx dy

這有一個比較好的例子,不過我們沒畫任何東西,只是將畫筆移動到路徑的起點,所以我們不會看到任何圖案。但是,我把我們移動到的點標註出來了,所以 在下面的例子裏會看到(10,10)座標上有一個點。注意,如果只畫path,這裏什麼都不會顯示。(這段不太好理解,說明一下:爲了更好地展示路徑,下 面的所有例子裏,在用path繪製路徑的同時,也會用circle標註路徑上的點。)

<?xml version="1.0" standalone="no"?>

<svg width="200px" height="200px" version="1.1" xmlns="http://www.w3.org/2000/svg">

  <path d="M10 10"/>

  <!-- Points -->
  <circle cx="10" cy="10" r="2" fill="red"/>

</svg>

能夠真正畫出線的命令有3個(M命令是移動畫筆位置,但是不畫線),最常用的是“Line to”命令,LL有兩個參數,分別是一個點的x軸和y軸座標,L命令將會在該點和當前點(L前面畫筆所在的點)之間畫一條線段。

L x y (or l dx dy)

另外還有兩個簡寫命令,用來繪製平行線和垂直線。H,繪製平行線。V,繪製垂直線。它們都只帶一個參數,標明在x軸或y軸移動到的位置,因爲它們都只在一個座標軸的方向上移動。

H x (or h dx)
 V y (or v dy)

現在我們已經掌握了一些命令,可以開始畫一些東西了。先從簡單的地方開始,畫一個簡單的矩形(同樣的效果用<rect/>元素可以更簡單的實現),矩形是由水平線和垂直線組成的,所以這個例子可以很好地展現前面講的畫線的方法。

<?xml version="1.0" standalone="no"?>

<svg width="100px" height="100px" version="1.1" xmlns="http://www.w3.org/2000/svg">
  
  <path d="M10 10 H 90 V 90 H 10 L 10 10"/>

  <!-- Points -->
  <circle cx="10" cy="10" r="2" fill="red"/>
  <circle cx="90" cy="90" r="2" fill="red"/>
  <circle cx="90" cy="10" r="2" fill="red"/>
  <circle cx="10" cy="90" r="2" fill="red"/>

</svg>

最後,我們可以通過一個“閉合路徑命令”Z來簡化上面的path,Z命令會從當前點畫一條直線到路徑的起點,儘管我們不總是需要閉合路徑,但是它還是經常被放到路徑的最後。另外,Z命令不用區分大小寫。

Z (or z)

所以上面例子裏用到的路徑,可以簡化成這樣:

<path d="M10 10 H 90 V 90 H 10 Z" fill="transparent" stroke="black"/>

你也可以使用這些命令的相對座標形式來繪製相同的圖形,如之前所述,相對命令使用的是小寫字母,它們的參數不是指定一個明確的座標,而是表示相對於它前面的點需要移動多少距離。例如前面的示例,畫的是一個80*80的正方形,用相對命令可以這樣描述:

<path d="M10 10 h 80 v 80 h -80 Z" fill="transparent" stroke="black"/>

上述路徑是:畫筆移動到(10,10)點,由此開始,向右移動80像素構成一條水平線,然後向下移動80像素,然後向左移動80像素,然後再回到起點。

你可能會問這些命令有什麼用,因爲 <polygon> 和 <polyline> 可以做到畫出一樣的圖形。答案是,這些命令可以做得更多。如果你只是畫直線,那麼其他元素可能會更好用,但是,path卻是衆多開發者在SVG繪製中慣用 的。據我所知,它們之間不存在性能上的優劣。但是通過腳本生成path可能有所不同,因爲另外兩種方法只需要指明點,而path在這方面的語法會更復雜一 些。

曲線命令 Curve commands

繪製平滑曲線的命令有3個,其中兩個用來繪製貝塞爾曲線,另外一個用來繪製弧形或者說是圓的一部分。如果你用過Inkscape, Illustrator 或者 Photoshop,你可能對貝塞爾曲線有一定程度的瞭解。關於貝塞爾曲線的數學解釋,你可以在Wikipedia的文檔中獲取到。其中的很多知識都可以用在這裏。貝塞爾曲線的類型有很多,但是在path元素裏,只存在兩種:三次貝塞爾曲線C,和二次貝塞爾曲線Q。

貝塞爾曲線

我們從稍微複雜一點的三次貝塞爾曲線入手,三次貝塞爾曲線需要定義一個點和兩個控制點,所以用C命令創建三次貝塞爾曲線,需要設置三組座標參數:

C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy)

這裏的最後一個座標(x,y)表示的是曲線的終點,另外兩個座標是控制點,(x1,y1)是起點的控制點,(x2,y2)是終點的控制點。如果你熟 悉代數或者微積分的話,會更容易理解控制點,控制點描述的是曲線起始點的斜率,曲線上各個點的斜率,是從起點斜率到終點斜率的漸變過程。(文字描述不好, 維基百科上有圖示,更直觀。) 

<?xml version="1.0" standalone="no"?>

<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">

  <path d="M10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>
  <path d="M70 10 C 70 20, 120 20, 120 10" stroke="black" fill="transparent"/>
  <path d="M130 10 C 120 20, 180 20, 170 10" stroke="black" fill="transparent"/>
  <path d="M10 60 C 20 80, 40 80, 50 60" stroke="black" fill="transparent"/>
  <path d="M70 60 C 70 80, 110 80, 110 60" stroke="black" fill="transparent"/>
  <path d="M130 60 C 120 80, 180 80, 170 60" stroke="black" fill="transparent"/>
  <path d="M10 110 C 20 140, 40 140, 50 110" stroke="black" fill="transparent"/>
  <path d="M70 110 C 70 140, 110 140, 110 110" stroke="black" fill="transparent"/>
  <path d="M130 110 C 120 140, 180 140, 170 110" stroke="black" fill="transparent"/>

</svg>

上面的例子裏,創建了9個三次貝塞爾曲線。有一點比較遺憾,標記控制點的代碼會比較龐大,所以在這裏捨棄了。(之前所有點都用circle標記,此 處一樣,只不過沒把代碼列出來)。如果你想更準確地控制它們,可以自己動手把他們畫出來。圖例上的曲線從左開始,控制點在水平方向上逐漸分開,最右側的曲 線,控制點之間離得更遠。這裏要注意觀察,曲線沿着起點到第一控制點的方向伸出,逐漸彎曲,然後沿着第二控制點到終點的方向結束。(這個翻譯的不太好,沒 弄清原文想要表達的意思。曲線的原理,還是看維基百科比較好。)

你可以將若干個貝塞爾曲線連起來,從而創建出一條很長的平滑曲線。如果將一個點的控制點在它的另一側建立一個對稱點(斜率不變),可以通過一個簡寫 的命令來實現,這個命令是S(或s)。(這段話可以這樣理解:S命令前面可以是一條C命令創建的三次貝賽爾曲線,這時候,S命令跟在C命令的後面,就可以 用比較簡單的參數,生成一個與前面那個相對稱的三次貝塞爾曲線。仔細看一下後面的圖例,可以幫助理解。另外,S命令也可以跟在S命令後面。)

S x2 y2, x y (or s dx2 dy2, dx dy)

S命令可以用來創建與之前那些曲線一樣的貝塞爾曲線,但是,如果S命令跟在一個C命令或者另一個S命令的後面,它的第一個控制點,就會被假設成前一 個控制點的對稱點。如果S命令單獨使用,前面沒有C命令或者另一個S命令,那麼它的兩個控制點就會被假設爲同一個點。下面是S命令的語法示例,如圖所示, 左側的控制點用紅色標示,與它對稱的控制點用藍色標示。

<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" stroke="black" fill="transparent"/>
</svg>

另一個貝塞爾曲線是二次貝塞爾曲線Q,它比三次貝塞爾曲線簡單,只需要一個控制點,用來確定起點和終點的曲線斜率。因此它需要兩組參數,控制點和終點座標。

Q x1 y1, x y (or q dx1 dy1, dx dy)

<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg"">
  <path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>
</svg>

就像三次貝塞爾曲線有一個S命令,二次貝塞爾曲線有一個差不多的T命令,可以通過更簡短的參數,延長二次貝塞爾曲線。

T x y (or t dx dy)

和之前一樣,快捷命令T會通過前一個控制點,推斷出一個新的控制點。這意味着,在你的第一個控制點後面,可以只定義終點,就創建出一個相當複雜的曲 線。需要注意的是,T命令前面必須是一個Q命令,或者是另一個T命令,才能達到這種效果。如果T單獨使用,那麼控制點就會被認爲和終點是同一個點,所以畫 出來的將是一條直線。

<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M10 80 Q 52.5 10, 95 80 T 180 80" stroke="black" fill="transparent"/>
</svg>

雖然三次貝塞爾曲線擁有更大的自由度,但是兩種曲線能達到的效果總是差不多的。具體使用哪種曲線,通常取決於需求,以及對曲線對稱性的依賴程度。

弧形Arcs

弧形命令A是另一個創建SVG曲線的命令。基本上,弧形可以視爲圓形或橢圓形的一部分。假設,已知橢圓形的長軸半徑和短軸半徑,另外已知兩個點(它 們的距離在圓的半徑範圍內),這時我們會發現,有兩個路徑可以連接這兩個點。每種情況都可以生成出四種弧形。所以,爲了保證創建的弧形唯一,A命令需要用 到比較多的參數:

A rx ry x-axis-rotation large-arc-flag sweep-flag x y
 a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy

弧形命令A的前兩個參數分別是x軸半徑和y軸半徑,它們的作用很明顯,不用多做解釋,如果你不是很清楚它們的作用,可以參考一下橢圓ellipse命令中的相同參數。弧形命令A的第三個參數表示弧形的旋轉情況,下面的例子可以很好地解釋它:

<?xml version="1.0" standalone="no"?>
<svg width="320px" height="320px" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M10 315
           L 110 215
           A 30 50 0 0 1 162.55 162.45
           L 172.55 152.45
           A 30 50 -45 0 1 215.1 109.9
           L 315 10" stroke="black" fill="green" stroke-width="2" fill-opacity="0.5"/>
</svg>

如圖例所示,畫布上有一條對角線,中間有兩個橢圓弧被對角線切開(x radius = 30, y radius = 50)。第一個橢圓弧的x-axis-rotation(x軸旋轉角度)是0,所以弧形所在的橢圓是正置的(沒有傾斜)。在第二個橢圓弧中,x- axis-rotation設置爲-45,所以這是一個旋轉的橢圓,並以短軸爲分割線,形成了兩個對稱的弧形。參看圖示中的第二個橢圓形。

上面提到的四種不同路徑將由接下來的兩個參數決定。如前所講,還有兩種可能的橢圓用來形成路徑,它們給出的四種可能的路徑中,有兩種不同的路徑。這 裏要講的參數是large-arc-flag(角度大小) 和sweep-flag(弧線方向),large-arc-flag決定弧線是大於還是小於180度,0表示小角度弧,1表示大角度弧。sweep- flag表示弧線的方向,0表示從起點到終點沿逆時針畫弧,1表示從起點到終點沿順時針畫弧。下面的例子展示了這四種情況。

<?xml version="1.0" standalone="no"?>
<svg width="325px" height="325px" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M80 80
           A 45 45, 0, 0, 0, 125 125
           L 125 80 Z" fill="green"/>
  <path d="M230 80
           A 45 45, 0, 1, 0, 275 125
           L 275 80 Z" fill="red"/>
  <path d="M80 230
           A 45 45, 0, 0, 1, 125 275
           L 125 230 Z" fill="purple"/>
  <path d="M230 230
           A 45 45, 0, 1, 1, 275 275
           L 275 230 Z" fill="blue"/>
</svg>

你應該已經猜到了,最後兩個參數是指定弧形的終點,弧形可以簡單地創建圓形或橢圓形圖標,比如你可以創建若干片弧形,組成一個餅圖

如果你是從Canvas過 渡到SVG,那麼弧形會比較難以掌握,但它也是非常強大的。用路徑來繪製完整的圓或者橢圓是比較困難的,因爲圓上的任意點都可以是起點同時也是終點,無數 種方案可以選擇,真正的路徑無法定義。通過繪製連續的路徑段落,也可以達到近似的效果,但使用真正的circle或者ellipse元素會更容易一些。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章