SVG動畫進階使用

出自不錯學群
跳至導覽 跳至搜尋

群組

  • 上面的文字與方塊已經算是一個群組了,接下來可以在<g>這個元素,使用變形(transform)來一起改變外觀
  • 就算有設定<g>的x,y值,但就是完全沒有反應,如果要控制<g>的位置,就要用transform了。
  • 利用transform=”translate(40 20)”,就可以位移了,這用法和CSS3 transform相當接近,雖然類似x,y但本質上還是有所不同。
<svg width="100%" height="150">
    <g transform="rotate(-10)">
        <rect y="10" width="100" height="100" style="stroke: #777; stroke-width: 3; fill: #07B492;"/>
        <text x="0" y="130" style="stroke: pink; fill: white"> SVG</text>
    </g>
</svg>
  • 像以上這樣,<g>群組就會被旋轉(-10 deg)。
  • 在G裡面的元素,都會被外層<g>所設定的樣式影響,像以下內部的元素沒有設定外框,但卻可以繼承其父層的<g>樣式。
  • 也就像CSS一樣,如果子元素有設定,則子元素優先。
   <svg width="100%" height="150">
       <g style="stroke: pink; stroke-width: 5px">
           <circle cx="40" cy="35" r="30" style="fill: white;"/>
           <circle cx="120" cy="35" r="30" style="fill: white;"/>
           <rect x="160" y="5" width="40" height="40" style="fill: white;"/>
           <rect x="220" y="5" width="40" height="40" style="fill: red;"/>
       </g>
   </svg>

不過我沒想到的是,svg還可以這樣用,在<g>裡面再放一個<svg>,這樣就可以設定他的x,y,這招太絕了,這樣就可以避免使用translate,使用x,y來設定位置。

   <svg width="100%" height="150">
       <g>
           <svg x="40" y="20">
               <rect y="10" width="100" height="100" style="stroke: #777; stroke-width: 3; fill: #07B492;"/>
               <text x="0" y="130" style="stroke: pink; fill: white"> SVG</text>
           </svg>
       </g>
   </svg>

定義一次,引用多次

  • defs 顧名思義就是「definitions」:定義,我們可以把許多重複性質高的元素,放入 defs 元素內,讓它變成一個可以重複利用的物件,原理就有點類似當年 flash 裏頭把一些動畫或是圖案轉換成物件一樣;首先我們來看到最常見的 defs 例子:「重複的圖形」,下面利用 defs 定義了一個矩形的長寬顏色,再使用 use 元素把矩形表現在畫面上,而 use 元素具有 x 與 y 的座標屬性,就可以輕鬆的做出許多不同位置的矩形。
   <defs>
     <rect id="rect1" width="100" height="50" x="10" y="10" fill="#c00"/>
   </defs>
   <use xlink:href="#rect1"/>
   <use xlink:href="#rect1" x="110"/>

也可以將 g 元素 ( 群組 ) 放在 defs 元素裏頭:

   <defs>
       <g id="g1">
             <rect id="rect1" width="100" height="50" x="10" y="10" fill="#c00"/>
             <circle id="circle1" cx="30" cy="30" r="10" fill="#00c"/>
       </g>
   </defs>
   <use xlink:href="#g1"/>
   <use xlink:href="#rect1" x="110"/>
   <use xlink:href="#circle1" x="210"/>

定義漸層色

   <defs>
      <linearGradient id="a1">
        <stop offset="5%" stop-color="#F00" />
        <stop offset="95%" stop-color="#ff0" />
      </linearGradient>
   </defs>
   <rect x="50" y="250" width="100" height="100" stroke="#000" stroke-width="5" fill="url(#a1)"></rect>
   <circle cx="220" cy="300" r="50" stroke="#000" stroke-width="5" fill="url(#a1)"></circle>
   <rect x="290" y="250" width="100" height="100" stroke="url(#a1)" stroke-width="5" fill="none"></rect>

文字路徑(先把貝茲曲線定義好,再把文字套入)

   <defs>
     <path id="a1" d="M0 50 C150 150 100 -50 300 50" stroke="#000" fill="none"/>
   </defs>
   <text>
      <textPath xlink:href="#a1">這是隨著路徑跑的文字
   </textPath>
   </text>

使用 defs 定義 filter(把漸層或濾鏡變為ID就能放進矩形、圓形等等圖形中)

   <defs>
   <filter width="200" height="200" x="0" y="0" id="blur" filterUnits="userSpaceOnUse">
     <feGaussianBlur stdDeviation="5" />
   </filter>
   </defs>
   <rect x="30" y="30" width="70" height="70" fill="#a00" filter=url("#blur") />

一朵花的程式碼

   <rect x="95" y="100" style="width:10;height:200;fill:green;"/>
   <polygon points="100,110 120,20 100,10 80,20" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <polygon points="100,110 120,20 100,10 80,20" transform="rotate(45 100 100 )" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <polygon points="100,110 120,20 100,10 80,20" transform="rotate(90 100 100 )" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <polygon points="100,110 120,20 100,10 80,20" transform="rotate(135 100 100 )" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <polygon points="100,110 120,20 100,10 80,20" transform="rotate(180 100 100 )" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <polygon points="100,110 120,20 100,10 80,20" transform="rotate(225 100 100 )" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <polygon points="100,110 120,20 100,10 80,20" transform="rotate(270 100 100 )" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <polygon points="100,110 120,20 100,10 80,20" transform="rotate(315 100 100 )" stroke="yellow" stroke-width="1" fill="#00a0e9"/>
   <circle cx="100" cy="100" r="50" fill="#FF8000"/>
   <circle cx="85" cy="85" r="4" fill="blac k"/>
   <circle cx="115" cy="85" r="4" fill="black"/>
   <circle cx="100" cy="100" r="4" fill="black"/>
   <path d="M 85,130 Q 100,145 115,130" style="stroke:black;fill:none;"/>


    • 花瓣

漸層

漸層的類型有兩種,線形漸層和放射形漸層。線形漸層沿直線變化,在 defs元素裡創建一個 <linearGradient> 元素,就創建了一個線形漸層。漸變必須有一個id屬性,否則它不能被其他元素引用,等於白做了。

  • 漸層由一種以上的顏色所組成,由一種顏色慢慢轉成另一種顏色,設定好顏色之後,再以ID的形式給漸層。
  • 漸層(又稱為「漸變」)是指將構成元素的形狀或色彩做次第改變的層層變化。例如,同一種形狀的漸大或漸小、同一種色彩的漸濃或漸淡,均屬於漸層的形式變化,而在這些漸增或漸減的層次變化中,即能具現出漸層的美感。
  • 漸變的基本原理與反覆相類似,但由於其中或形或色的漸次改變,使得畫面較具活潑性,予人生動輕快的感受。中國建築中的寶塔;樂曲中音量的漸強漸弱;文學小說中情節高潮的堆且;大會舞隊型的漸次縮小或擴大……等,都是漸層形式原理的例子。

(一)線性漸層

在上面的例子裡,一個線形漸層被用在<rect>元素上,線形漸層內部有若干 <stop> 節點,它們用來指定漸變應該在什麼位置形成什麼顏色,其中兩個屬性分別是:定義偏移位置的offset屬性和定義顏色的stop-color屬性。另外,它們可以直接設置,或通過CSS設置。上面的例子裡混合使用了這兩種形式。比如,這個例子的漸變是從紅色開始,到中間漸變成黑色,最後漸變到藍色。你可以按照自己的想法設置各種stop-color,但是它們的offset必須是從0%逐漸提高到100%。(如果不加%,就是0-1)。如果有重複的值,不會被分配到xml樹的最後。另外像fill和stroke一樣,你也可以設置一個stop-opacity屬性表示透明度。

   <?xml version="1.0" standalone="no"?>
   <svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
     <defs>
         <linearGradient id="Gradient1">
           <stop class="stop1" offset="0%"/>
           <stop class="stop2" offset="50%"/>
           <stop class="stop3" offset="100%"/>
         </linearGradient>
         <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
           <stop offset="0%" stop-color="red"/>
           <stop offset="50%" stop-color="black" stop-opacity="0"/>
           <stop offset="100%" stop-color="blue"/>
         </linearGradient>
         <style type="text/css"><![CDATA[
           #rect1 { fill: url(#Gradient1); }
           .stop1 { stop-color: red; }
           .stop2 { stop-color: black; stop-opacity: 0; }
           .stop3 { stop-color: blue; }
         ]]></style>
     </defs>

     <rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100"/>
     <rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>
 
   </svg>
  • 在上面的例子裡,一個線形漸層被用在<rect>元素上,線形漸層內部有若干 <stop> 節點,它們用來指定漸變應該在什麼位置形成什麼顏色,其中兩個屬性分別是:定義偏移位置的offset屬性和定義顏色的stop-color屬性。另外,它們可以直接設置,或通過CSS設置。上面的例子裡混合使用了這兩種形式。比如,這個例子的漸變是從紅色開始,到中間漸變成黑色,最後漸變到藍色。你可以按照自己的想法設置各種stop-color,但是它們的offset必須是從0%逐漸提高到100%。(如果不加%,就是0-1)。如果有重複的值,不會被分配到xml樹的最後。另外像fill和stroke一樣,你也可以設置一個stop-opacity屬性表示透明度。
  • 使用漸變時,我們需要在對象的fill或stroke屬性裡引用它。就像在CSS里通過url來引用其他元素一樣,在這裡,url引用的是我們給漸變設置的id,所以只需要將fill屬性設置成url(#Gradient) ,我們的對象就可以呈現出五彩斑斕的效果。另外你也可以給stroke進行同樣的設置。
  • <linearGradient>元素還可以設置其他一些屬性,用來定義尺寸和样​​式。比如漸變的方向是由兩個點控制的,它們用x1, x2,y1,y2四個屬性控制,形成一條直線,漸變就沿這條直線變化。漸變默認的方向是水平方向,使用這些屬性就可以改變方向。上面例子裡的Gradient2就是一個垂直的漸變。

(二)放射漸層

放射形漸層很類似線形漸層,只不過是從一個點向外發散漸變。在文檔的 defs 段落裡增加一個 <radialGradient> 元素,就可以創建放射形漸層。

   <?xml version="1.0" standalone="no"?>
   
   <svg width="120" height="240" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
     <defs>
         <radialGradient id="Gradient1">
           <stop offset="0%" stop-color="red"/>
           <stop offset="100%" stop-color="blue"/>
         </radialGradient>
         <radialGradient id="Gradient2" cx="0.25" cy="0.25" r="0.25">
           <stop offset="0%" stop-color="red"/>
           <stop offset="100%" stop-color="blue"/>
         </radialGradient>
     </defs>
    
     <rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#Gradient1)"/>
     <rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>
     
   </svg>
  • 這個例子的裡,放射形漸層中的stop節點在用法上和前面的線形漸層一樣,但是這裡的圖形對像是中間呈紅色,然後向各個方向發散漸變,直到邊緣漸變到藍色。放射形漸層<radialGradient>也有若干用來定義位置和方向的屬性,不過與線形漸層不同,這裡的設置會稍微複雜一點。放射形漸層裡也可以設置兩個點,用來確定它的範圍。第一個點用來定義一個環,限定漸變的範圍。該點包括坐標屬性cx和cy,以及半徑屬性r。定義這三個屬性,就可以改變漸變的位置和大小,就像上面例子裡的第二個漸變效果。
  • 第二個點被稱為焦點,通過坐標屬性fx和fy來確定。第一個點決定的是漸變所處的範圍,而焦點則決定漸變的中心。
   <?xml version="1.0" standalone="no"?>
   
   <svg width="120" height="120" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
     <defs>
         <radialGradient id="Gradient"
               cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
           <stop offset="0%" stop-color="red"/>
           <stop offset="100%" stop-color="blue"/>
         </radialGradient>
     </defs>
    
     <rect x="10" y="10" rx="15" ry="15" width="100" height="100"
           fill="url(#Gradient)" stroke="b​​lack" stroke-width="2"/>
     <circle cx="60" cy="60" r="50" fill="transparent" stroke="white" stroke-width="2"/>
     <circle cx="35" cy="35" r="2" fill="white" stroke="white"/>
     <circle cx="60" cy="60" r="2" fill="white" stroke="white"/>
     <text x="38" y="40" fill="white" font-family="sans-serif" font-size="10pt">(fx,fy)</text>
     <text x="63" y="63" fill="white" font-family="sans-serif" font-size="10pt">(cx,cy)</text>
 
   </svg>
  • 如果焦點被移動到漸變範圍之外,漸變不可能被正確渲染,所以會被重定義到範圍的邊緣。如果不定義焦點,則默認與漸變範圍的中點是同一點。
  • 兩種漸變都可以通過一些屬性,定義諸如變形等樣式。在這裡僅提其中一個:spreadMethod屬性。當漸變已經到達範圍邊緣,但圖形對像還沒被完全填充時,這一屬性​​將決定接下來會發生什麼。它有三個可用值,"pad", "reflect", 以及 "repeat"。 "pad"的效果你已經看到過了,當漸變到達範圍邊緣,最後一個顏色將用來填充圖形剩下的區域。 "reflect"是繼續漸變,但是會從100%處的顏色漸變會0%的位置,然後再翻過來繼續。 "Repeat"也是讓漸變繼續,不過是跳過返回的過程,直接回到起始狀態,然後重新漸變。
  • 柔焦濾鏡與放射漸層的練習

柔焦濾鏡

feGaussianBlur(柔焦濾鏡)應該算是 SVG filter 裏頭最簡單的濾鏡,因為它只有一個參數需要注意:stdDeviation,這也是控制模糊程度的參數,數字越大越模糊,數字為零則是圖片原本的狀態,在這邊有一個比較需要注意的地方,就是要記得設定 filter 的filterUnits為 userSpaceOnUse ,因為預設值是會讓 filter 跟隨著套用該 filter 的物件跑,所以要記得設定成跟隨整個 SVG space。

   <?xml version='1.0' encoding='UTF-8' standalone='no'?>
   <svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='160' height='160'>
   <defs>
 	    <radialGradient id='r4' cx='50%' cy='50%' r='50%' >
               <stop style='stop-color:#fff100' offset='0%' />
               <stop style='stop-color:#ff9900;stop-opacity:.98' offset='50%' />
               <stop style='stop-color:#ff1700;stop-opacity:.98' offset='100%' />
           </radialGradient>
           <filter id='f1' >
           <feGaussianBlur stdDeviation='3' />
           </filter>
   </defs>
   <circle cx='79' cy='79' r='75' style="fill:url(#r4);filter:url(#f1);" />
   </svg>

feGaussianBlur後面的stdDeviation='3'用來設定模糊的程度,0就是完全沒有改變。

path

用參數(0~1)和控制點作圖:

  1. 一次:
  2. 二次: 
  3. 三次: 
  4. 四次: 
  5. 五次:

path示範

  1. 波浪
  2. 二,三次貝茲曲線
  3. 三次貝茲曲線軌跡
  4. 循跡字串(textPath子標籤)
  5. 簡易動畫(齒輪自轉)
  6. 簡易動畫(齒輪自轉並前進)

標籤:

  1. set(開關)
    • 只用attributeName,to,begin三屬性
  2. animate(屬性連續改變)
  3. animateTransform(平移,旋轉,縮放)
  4. animateMotion(循跡運動)
  • 共通語法:將母圖形分拆成開始和結束兩標籤,中間插入動畫標籤。
  • 共通屬性:
    1. attributeName:
      • set,animate為某一個母圖形的屬性。from 和 to 就是這個屬性的值將由多少變到多少。
      • animateTransform為'transform'另搭配 type 屬性
      • animateMotion免設此屬性
    2. type屬性之值(animateTransform專用):
      • rotate旋轉,影響屬性from='起始角度,旋轉軸心x座標,旋轉軸心y座標'、to='結束角度,旋轉軸心x座標,旋轉軸心y座標'。
      • scale縮放,影響屬性from='x起始倍率,y起始倍率'、to='x結束倍率,y結束倍率',倍率是自左上原點開始算,如果同組x,y倍率相同,可以只寫一個值。
      • translate平移,影響屬性from='起始原點x座標,起始原點y座標'、to='結束原點x座標,結束原點y座標'。
      • skewX X軸不動,X軸下方向右歪斜,影響屬性from='起始歪斜角度'、to='結束歪斜角度'
      • skewY Y軸不動,Y軸右方向下歪斜,影響屬性from='起始歪斜角度'、to='結束歪斜角度'
    3. begin='幾s':幾秒開始跑,通常設為 0s 。
    4. dur='幾s':跑一輪要幾秒,可以設為 indefinite 。
    5. repeatCount='幾':要跑幾輪,indefinite代表無限多輪,預設值為1。
    6. from 開始狀態(animate,animateTransform有)。
    7. to 結束狀態(set,animate,animateTransform有)。
    8. path(animateMotion專用) 屬性為移動路徑:由 m 開始
    9. rotate='auto'(animateMotion專用) 圖形隨路徑曲度而轉折。

貝茲曲線

在數學的數值分析領域中,貝茲曲線(英語:Bézier curve,亦作「貝塞爾」)是計算機圖形學中相當重要的參數曲線。更高維度的廣泛化貝茲曲線就稱作貝茲曲面,其中貝茲三角是一種特殊的實例。 貝茲曲線於1962年,由法國工程師皮埃爾·貝茲(Pierre Bézier)所廣泛發表,他運用貝茲曲線來為汽車的主體進行設計。貝茲曲線最初由Paul de Casteljau於1959年運用de Casteljau演算法開發,以穩定數值的方法求出貝茲曲線。

二次貝茲曲線

貝茲曲線的程式碼

   <path id='a1' d='M0,50 C150,130 100,0 300,40' style='stroke:#000;fill:none;' />
  • 用貝茲曲線設定文字要先在<def></def>寫好,再使用id匯入。
  • 所以只需要設定一次,就可以使用設好的ID使用多次。
  • 我可以在每一個<textPath></textPath>中放上不一樣的文字,就會有一樣的角度,不同的樣貌

程式碼如下(此為文字)

  <textPath startOffset='4%' xlink:href='#a1' style='font-family:KaiTi;fill:pink;font-size:40px'></textPath>

純貝茲曲線指令碼

  <path d='M0,0 Q50,50 20,0 T40,0 60,0 80,0 100,0 120,0 140,0 160,0 180,0 200,0' style='stroke:black;fill:none;' transform='translate(0,50)'/>
三次貝茲曲線

三次的程式碼

   <path d='M0,50 C50,100 80,0 200 50' style='stroke:blue;fill:none;' />
  • 三次與兩次相比更加細緻。
三次與數次貝茲曲線的差異
  • 以此類推,雖然曲線細緻度不同,但底層的原理一樣。

動畫

  • 共通屬性:
    1. attributeName:
      • set,animate為某一個母圖形的屬性。from 和 to 就是這個屬性的值將由多少變到多少。
      • animateTransform為'transform'另搭配 type 屬性
      • animateMotion免設此屬性
    2. type屬性之值(animateTransform專用):
      • rotate旋轉,影響屬性from='起始角度,旋轉軸心x座標,旋轉軸心y座標'、to='結束角度,旋轉軸心x座標,旋轉軸心y座標'。
      • scale縮放,影響屬性from='x起始倍率,y起始倍率'、to='x結束倍率,y結束倍率',倍率是自左上原點開始算,如果同組x,y倍率相同,可以只寫一個值。
      • translate平移,影響屬性from='起始原點x座標,起始原點y座標'、to='結束原點x座標,結束原點y座標'。
      • skewX X軸不動,X軸下方向右歪斜,影響屬性from='起始歪斜角度'、to='結束歪斜角度'
      • skewY Y軸不動,Y軸右方向下歪斜,影響屬性from='起始歪斜角度'、to='結束歪斜角度'
    3. begin='幾s':幾秒開始跑,通常設為 0s 。
    4. dur='幾s':跑一輪要幾秒,可以設為 indefinite 。
    5. repeatCount='幾':要跑幾輪,indefinite代表無限多輪,預設值為1。
    6. from 開始狀態(animate,animateTransform有)。
    7. to 結束狀態(set,animate,animateTransform有)。
    8. path(animateMotion專用) 屬性為移動路徑:由 m 開始
    9. rotate='auto'(animateMotion專用) 圖形隨路徑曲度而轉折。

向前移動並消失的程式碼

   <?xml version='1.0' encoding='UTF-8' standalone='no'?>
   <svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='400' width ='1000'>
   <defs>
       <linearGradient id='LG' x1='30%' y1='0%' x2='70%' y2='0%'>
           <stop offset='0%' style='stop-color:#ffff00;stop-opacity:1' />
           <stop offset='100%' style='stop-color:#ff0000;stop-opacity:1' />
       </linearGradient>
   </defs>    
   <circle cx="30" cy="30" r="25" style="stroke: none; fill:url(#LG);">
   <animate attributeName="cx" attributeType="XML"
       from="30"  to="1020"
       begin="0s" dur="3s"
       fill="remove" repeatCount="indefinite"/>
   <animate attributeType="CSS" attributeName="opacity" from="1" to="0" dur="3s" repeatCount="indefinite" />
   </circle>	
   </svg>

圖形範例

綜合應用:

三角形:

直角三角形:

動畫:

旋轉:

三個方塊的舞蹈:

互動:

參考資料

工程師必須知道的SVG觀念