一個比想象中更騷氣的圓-svg實現

Bob-Chen發表於2016-07-10

之前寫了一篇Canvas畫圖-一個比想象中更騷氣的圓(漸變圓環),其實SVG也可以實現類似的效果,而且兩者api驚人的相似。

關於SVG

SVG是一種向量圖形,在圖形改變尺寸的情況下質量不會損失。

相比canvas,svg有一個很大的優勢就是內聯進html的時候可以像操作dom一樣操作svg,這樣做起動畫來非常方便。

本文不會介紹svg的基礎知識,不過也沒涉及什麼複雜的東西,基於xml的語法還是比較好理解的。

期望實現的效果和Canvas一樣是顏色非對稱的沿著圓周進行漸變。

SVG的漸變

和之前講canvas一樣,svg也有線性漸變和徑向漸變,這裡主要講線性漸變,徑向漸變api差別不大。

老規矩,上程式碼:

    <svg version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
         width="595.28px" height="841.89px" viewBox="0 0 595.28 841.89" enable-background="new 0 0 595.28 841.89" xml:space="preserve">
    <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="213.0787" y1="303.3227" x2="384.1807" y2="303.3227">
        <stop  offset="0.107" style="stop-color:#00A29A"/>
        <stop  offset="0.1301" style="stop-color:#28A891"/>
        <stop  offset="0.1968" style="stop-color:#76B874"/>
        <stop  offset="0.2649" style="stop-color:#9FC758"/>
        <stop  offset="0.3339" style="stop-color:#BBD338"/>
        <stop  offset="0.4041" style="stop-color:#CDDA06"/>
        <stop  offset="0.4761" style="stop-color:#D7DE00"/>
        <stop  offset="0.5527" style="stop-color:#DAE000"/>
        <stop  offset="0.9265" style="stop-color:#F39800"/>
    </linearGradient>
    <circle fill="none" stroke="url(#SVGID_1_)" stroke-width="16" stroke-miterlimit="10" cx="306.385" cy="355.208" r="77.551"/>
    </svg>複製程式碼

這個是直接從AI裡匯出的,也可以嘗試使用別的SVG編輯器,其中linearGradient就是定義一個線性漸變,和Canvas中的ctx.createLinearGradient一個意思,stop標籤就類似Canvas中的grd.addColorStop方法,同樣是設定漸變點,這裡給這個漸變設定了一個id,id="SVGID_1_"

下面的那個circle標籤就是定義一個圓,cx,cy,r分別是圓心座標和半徑,fill和stroke分辨對應canvas中的fillStyle和strokeStyle,stroke-width對應canvas中的lineWidth。

和之前給canvas版的騷氣圓環用漸變一樣,svg的實現也是定義一個線性漸變,然後讓圓用這個漸變來描邊stroke="url(#SVGID_1_)"

實際上出來的效果,和Canvas漸變是異曲同工,即使svg有路徑的概念,漸變也沒有按照路徑來漸變,而是和canvas一樣從左到右,上下顏色是對稱的。

如圖:

一個比想象中更騷氣的圓-svg實現

SVG非對稱的漸變圓環

Canvas的非對稱漸變圓環我們藉助了ctx.createPattern,google一下,svg裡同樣有個<pattern>

這裡為了方便,我把要用到的圖片base64進去了,實際上用線上圖片也可以。

程式碼如下,省略base64的內容:

    <svg height="108" width="108" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
      <defs>
        <pattern id="fill-img" patternUnits="userSpaceOnUse" width="108" height="108">
          <image xlink:href="data:image/png;base64,xxxxxxxxxxx"
            x="0" y="0" width="108" height="108">
          </image>
        </pattern>
      </defs>
       <circle fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49" >
       </circle>
    </svg>複製程式碼

和canvas一樣,定一個<pattern>,然後給圓描邊的時候用這個東東。

出來的效果:

一個比想象中更騷氣的圓-svg實現

看了之前Canvas的文章的話,svg程式碼還是比較簡單的,然後我們來加個動畫。

SVG動畫

SVG動畫實際上是讓路徑動起來,要讓路徑動起來首先要了解stroke-dasharray和stroke-dashoffset這兩個屬性。

  • stroke-dasharray 表示用虛線描邊。可選值為none, , inherit。

    • none 表示不用虛線描邊
    • inherit 表示繼承
    • 可就厲害了,基本上路徑動畫都需要用到,這是一個逗號或者空格分隔的數值列表,第一個值表示線段的長度,第二個值表示線段間空白的長度,舉個例子stroke-dasharray="308 1000"中,308表示虛線中的線段的長度,而1000表示兩個線段間的長度是1000px。其實這個dasharray可以不只兩個值,可以有很多個,會迴圈依次用到線段和空白之間。
  • stroke-dashoffset 表示虛線的起始偏移。可選值為:, , inherit. 分別表示:百分比值,長度值,繼承。這個dashoffset和上面那個結合起來用,一般來說虛線的第一段是實線線段,如果我想要第一段是空白怎麼辦,設定這個dashoffset就可以了。

現在就來試一試,只需要修改circle元素的程式碼就可以了:

    <circle fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"  stroke-dasharray="308 1000" stroke-dashoffset="100">
    </circle>複製程式碼

如下圖:

一個比想象中更騷氣的圓-svg實現

缺的那一塊就是因為虛線的空白部分被移出來了,這裡r設定49和Canvas的原理一樣,想畫看起來半徑54的圓,需要用54減去描邊寬度的一半,54-10/2,而這裡stroke-dasharray的第一個數,我這裡設定的是圓的周長,2Math.PI49=307.8760800517997 約等於308啦,至於第二個數,設大一點就好,大過圓的周長就可以了。

想要做動畫就不斷的改變stroke-dashoffset的值讓虛線的空隙動起來就可以了,svg本身支援屬性的動畫,稍微改動一下程式碼:

    <circle fill="none" stroke="#e5ece7" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"/>

    <circle fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"  stroke-dasharray="308 1000" stroke-dashoffset="308" stroke-linecap="round" transform="rotate(-88 54 54)">
        <animate attributeName="stroke-dashoffset" begin="0s" dur="1.5s" from="308" to="0" repeatCount="indefinite" />
    </circle>複製程式碼

這裡我把circle的初始stroke-dashoffset改成308,表示從空白開始,animate標籤中attributeName表示動畫屬性是stroke-dashoffset,begin表示開始的延時,dur表示時間整個動畫的時間,frometo表示初始值和最終值,repeatCount表示重複次數,這裡是無限次。整體和CSS3動畫還是很像的。

這裡還有一個stroke-linecap="round"和Canvas的ctx2.lineCap="round";作用一樣,是設定描邊的兩頭是圓形。

另外我還在上面加了一個圓,用來做底色,同時給做動畫的圓做了一個旋轉transform="rotate(-88 54 54)"用來改變起始點。

效果如下:

一個比想象中更騷氣的圓-svg實現

SVG動畫2

大致瞭解了SVG動畫的原理之後,其實SVG還可以用CSS3的transition和animation來做動畫。

新增css:

    .animate-item {
        transition: stroke-dashoffset 1.5s ease;
    }複製程式碼

新增js:

    setTimeout(function(){
        $(".animate-item").css("stroke-dashoffset",94);
    }, 1000)複製程式碼

前面說過svg聯進html的時候可以像操作dom一樣操作svg,這裡修改了一下圓環,給了一個class.animate-item

修改圓環:

    <circle class="animate-item" fill="none" stroke="url(#fill-img)" stroke-width="10" stroke-miterlimit="1" cx="54" cy="54" r="49"  stroke-dasharray="308 1000" stroke-dashoffset="308" stroke-linecap="round" transform="rotate(-88 54 54)">
    </circle>複製程式碼

效果如下:

一個比想象中更騷氣的圓-svg實現

至此,騷氣圓環SVG版也就完成了,總體上來說svg的實現更簡單,做動畫的程式碼也比較少,相對於canvas需要佔用js執行緒進行一定量的計算來說,svg的效能要好一些。

不過svg在android4.3以上才有比較好的支援,相對來說canvas的支援就比較好了。

一個比想象中更騷氣的圓-svg實現

完整程式碼: github.com/bob-chen/ca…

參考

www.zhangxinxu.com/wordpress/2…

designmodo.com/svg-pattern…

相關文章