小試SVG

下半身要幸福發表於2018-12-24

基本概念

svg(Scalable Vector Graphics)是一種基於XML語法的影像格式,全稱是可縮放向量圖,其它影像格式都是基於畫素處理的,SVG則是屬於對影像的形狀描述,所以它本質上是文字檔案,體積較小,且不管放大多少倍都不會失真.SVG是面向圖形,HTML時面向文字。

嵌入到HTML

SVG可以寫在一個獨立的檔案中,然後用小試SVG, , , 等標籤插入網頁

  <img src="circle.svg">
  <object id="object" data="circle.svg" type="image/svg+xml"></object>
  <embed id="embed" src="icon.svg" type="image/svg+xml">
  <iframe id="iframe" src="icon.svg"></iframe>
複製程式碼

SVG檔案可以轉為base64編碼,然後作為Data URI寫入網頁

  <img src="data:image/svg+xml;base64,[data]" />
複製程式碼

SVG書寫的注意點

  • SVG的元素和屬性必須按照標準格式來寫,因為XML是確認大小寫的
  • SVG裡的屬性值必須用引號引起來,就算是數值也必須這麼做
  • SVG影像的預設大小是300畫素(寬)x 150畫素(高)
  • 後面的元素會渲染在前面元素之上

SVG的所有元素

SVG的所有元素

SVG的所有屬性

SVG的所有屬性

常用的形狀元素

常用的形狀元素

其實上圖只是對一些常用svg標籤的初步認識,因為svg所提供的標籤不止這些,而且比如path標籤是在svg中最為通用的形狀標籤,因為它可以通過設定路徑畫出其它圖形,比如矩形,圓,橢圓,多邊形,多線段,甚至是複雜的貝塞爾曲線等等

第一次看到svg的<path ...>標籤的時候,開啟控制檯,也是一臉懵逼,首先這裡面的d屬性是個啥,M是啥,L是啥,Z是啥,H是啥,V是啥,C是啥,S是啥,Q是啥,T是啥,A是啥,我... 打擾了,打擾了

path

嗯,26個兄弟快湊齊了,馬上就可以召喚神龍了。當然,path這條神龍在svg界就是“爸爸”,啥玩意都能給你弄出來,

想要通過path勾勒出美妙的圖形,需要了解d這個屬性,path標籤中的d屬性可以定義一系列的指令和引數,每一個指令通過一個字母來指定,比如上面說的M,它表示移動到,也就是"move to"的意思,比如讓我們移動到(10, 10)的座標點,就可以這樣寫:

  <rect d="M10 10" />'
複製程式碼

當然每一種字母都是區分大小寫的,比如M是基於畫布上的一個絕對座標,而m則是基於上一個點的座標,也就是相對座標。比如有下面兩種指令

  <path d="M20,20 L40 40 M60 60 L80 80" fill="none" stroke="blue" stroke-width="5"/>

  <path d="M20,20 L40 40 m60 60 L80 80" fill="none" stroke="blue" stroke-width="5"/>
複製程式碼

path

兩個path唯一的區別就是第三個指令,一個是M60 60, 一個是m60 60

線段指令(Line commands)

  • L:L指令會拿到兩個引數,x座標和y座標,然後從當前位置到指定引數座標位置來繪製線段
  • H:H其實是horizontal的縮寫,意為繪製出水平方向的線段,因為方向已確定,所以只需一個引數就能完成線段的繪製
  • V:同H同理,只不過表示垂直方向(vertical)的線段繪製

比如用H和V來繪製一個矩形, 我們一步一步來

  • step1
  <path d="M10 10 H 90" fill="none" stroke="blue"/>
複製程式碼

step1

  • step2
  <path d="M10 10 H 90 V 90" fill="none" stroke="blue"/>
複製程式碼

step2

  • step3
  <path d="M10 10 H 90 V 90 H 10" fill="none" stroke="blue"/>
複製程式碼

step3

  • step4
  <path d="M10 10 H 90 V 90 H 10 V 10" fill="none" stroke="blue"/>
複製程式碼

step4

上面的寫法也可以通過一個指令來簡寫一下,這就用到了Z指令

Z:該指令的作用是從當前位置向起始點畫出一條線段,它一般都被放置在一連串節點的末尾,並且不區分大小寫。可以理解為”閉環“指令

所以上例可以寫成這樣,也能達到同樣的效果

  <path d="M10 10 H 90 V 90 H 10 Z" fill="none" stroke="blue"/>
複製程式碼

同樣,上例也可以通過相對定位的形式進行改寫,效果是一致的

  <path d="M10 10 h 80 v 80 h -80 Z" fill="transparent" stroke="blue"/>
複製程式碼

relative

曲線指令(Curve commands)

一說到曲線,那貝塞爾曲線是繞不開的,對於曾高數掛科的我來說是很排斥的,但好在閒著蛋疼,遂學之。

path標籤中有兩類貝塞爾曲線,一種叫做“三次貝塞爾曲線(cubic curve)“, 一種叫做”二次貝塞爾曲線(quadratic curve)“,這名字聽起來就不接地氣。

那先從三次貝塞爾曲線說起

C:該指令用於建立一個三次貝塞爾曲線,需指定三組引數

比如:

  <path d="M10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>
複製程式碼

首先,(20 20)和(40 20)表示控制節點,一個是描述曲線起始點的斜率,另一個是描述曲線終止點的斜率,最後一組(50 10)表示曲線的終點。總結一下這段示例,就是有一條從(10 10)到(50 10)的一條線段,通過設定兩個控制點的斜率,使這條線段的各個點彎曲成正確的(符合斜率趨勢的)曲線。

MDN上有多組曲線的對比示例。

MDN上有多組曲線的對比示例

這裡面我們再新增一種情況,就是設定兩個水平的控制節點,來看看線段是如何變化的

  <path d="M10 10 C 10 10, 40 10, 50 10" stroke="black" fill="transparent"/>
複製程式碼

水平

通過S指令能生成和上述示例中同樣的平滑曲線,使用S指令分為以下兩種情況

  • S指令跟在C或者另一個S指令之後:那S指令的開始控制節點就是基於前一個控制節點的對稱點,並且S指令指定的第一組節點是結束控制節點
  • 單獨的S指令:兩個控制節點會被設定為同一個點

比如如下程式碼

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

    <circle cx="10" cy="80" r="2" fill="red"/>
    <circle cx="95" cy="80" r="2" fill="red"/>
    <circle cx="180" cy="80" r="2" fill="red"/>
    <circle cx="150" cy="150" r="2" fill="red"/>
  </svg>
複製程式碼

我們通過不斷改變S的第一組節點來看圖形的變化趨勢

S

我們可以看到,隨著不斷給S指令結束控制節點的橫座標累加,曲線會向右偏移。

接下來看下S指令前面沒有其他C或者S指令的情況,程式碼如下

  <svg
    xmlns="http://www.w3.org/2000/svg"
    width="300"
    height="300"
  >
    <path d="M10 80 S 95 150, 180 80" stroke="black" fill="transparent"/>

    <circle cx="10" cy="80" r="2" fill="red"/>
    <circle cx="95" cy="150" r="2" fill="red"/>
  </svg>
複製程式碼

S

另一種曲線是二次貝塞爾曲線(quadratic curve)

它通過指令Q來來進行描述,相較於三次貝塞爾曲線,它更為簡單。

Q:只需要指定兩組引數,第一組表示控制節點的座標,第二組表示終點座標。

示例:

  <svg
    xmlns="http://www.w3.org/2000/svg"
    width="300"
    height="300"
  >
    <path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>

    <circle cx="10" cy="80" r="2" fill="red"/>
    <circle cx="95" cy="20" r="2" fill="red"/>
    <circle cx="180" cy="80" r="2" fill="red"/>
  </svg>
複製程式碼

Q

和三次貝塞爾類似,二次貝塞爾也提供了快捷的玩法,那就是T指令

T:通過找到前一個控制節點,來推斷出一個新的控制點,T指令後面只需要指定一組結束點座標即可,由於T指令是基於前一個控制點的基礎上來生成的,所以T指令之前必須要有Q指令或者其他T指令,否則生成的控制節點就和前一個控制節點就會重合,在畫布上看到的就僅僅是一條直線。

示例:

  <svg
    xmlns="http://www.w3.org/2000/svg"
    width="300"
    height="300"
  >
    <path d="M10 80 Q 52.5 10, 95 80 T 180 80" stroke="black" fill="transparent"/>

    <circle cx="10" cy="80" r="2" fill="red"/>
    <circle cx="52.5" cy="10" r="2" fill="red"/>
    <circle cx="95" cy="80" r="2" fill="red"/>
    <circle cx="180" cy="80" r="2" fill="red"/>

  </svg>
複製程式碼

S

在上面幾個例子中,兩種曲線都生成了同樣的結果,雖然三次貝塞爾允許更多的自由度,但是決定使用哪種曲線還要依照具體情形以及對稱曲線的數量來定

弧度(Arcs)

在svg中也可以建立弧度這種曲線,它通過A指令來指定,A指令可以接收7個引數

  1. rx:x軸半徑
  2. ry:y軸半徑
  3. x-axis-rotation:弧形的旋轉角度
  4. large-arc-flag:決定弧線是大於180度好事小於180度,0表示小角度弧,1表示大角度弧
  5. sweep-flag:表示弧線的方向,0表示從起點到終點沿逆時針畫弧,1表示從起點到終點沿順時針畫弧
  6. x:弧形終點的橫座標
  7. y:弧形終點的縱座標

示例:

<?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>
複製程式碼

S

餅圖

通過學習path,我們來繪製一個簡單的餅圖

  <svg width="325" height="325" 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="M170 80
            A 45 45, 0, 0, 1, 125 125
            L 125 80 Z" fill="red"/>
    <path d="M170 80
            A 45 45, 0, 0, 0, 125 35 
            L 125 80 Z" fill="blue" />
    <path d="M80 80
            A 45 45, 0, 0, 1, 125 35
            L 125 80 Z" fill="pink"/>
  </svg>
複製程式碼

pie

小結

在最近的一些專案中,接觸到了部分有關svg的需求,所以這篇文章就是記錄下自己在學習svg的一部分總結,比較基礎,方便自己今後的複習和查閱。