文章目的
在做今年的 THE F2E 第一週番茄鐘時,遇到最大難題就是要做一個隨時間逐漸填滿的同心圓,想藉由此文章為製作流程做個紀錄。
開發思維
同心圓內圓與外圓之間是有間隔的,隨時間倒數間隔會逐漸填滿,示意圖如下:
我的想法是用3個圓去達成效果:
- 第一個圓在最外圍負責最外圍的 border 顯示。
- 第二個圓就是兩圓之間的間隔,它會隨時間變色進而達到效果。
- 第三個圓就是內圓,與第一個圓有大小差距,進而產生間隔效果。
SVG 與 Stroke 介紹
在這次效果製作中,這兩者扮演了很重要的角色,因此先來為它們做個簡單介紹。
- SVG 是向量標籤,我們可以在向量標籤裡透過座標的方式畫出不同的圖案。
- Stroke 是 SVG 的一種屬性,它代表邊框的意思,它總共有5種屬性:
- stroke:邊框顏色
- stroke-width:邊框寬度
- stroke-dasharray:虛線
- stroke-linecap:邊框端點的屬性 ( butt ( 預設 )、square、round ) —本次開發不會用到
- strkoe-linejoin:邊框接合尖角的屬性 ( miter ( 預設 )、round、bevel ) —本次開發不會用到
開發流程
畫出前兩個同心圓
我們先創造一個 SVG 標籤並且在裡面畫出一個圓,SVG 就是我們的第一個圓,SVG 裡的圓就是我們的第二個圓。
1 | <svg style="transform:rotate(-90deg);width:540px;height:540px;" class="rounded-circle"> |
這邊我定義了外圓 SVG 的長寬(540px),並令它呈現圓形(rounded-circle
),內部 circle
方面則是畫出大小是外圓的一半的圓,至於外圓的 SVG 再記得給它畫 border線即可。
先為 circle
裡的屬性做個解釋:
- cx:圓心的 x 座標
- cy:圓心的 y 座標
- r:圓的半徑
- fill:填色
因為我是要做出同心圓所以 cx 和 cy 的座標就是外圓的圓心位置。
利用 stroke 做出填色效果
我們將 stroke 屬性下在 circle
裡,因為要做效果的是第二個圓
前面有提到 stroke-width 可以控制邊框的寬度,在這邊我們就設定成 270px 讓它可以填滿第二個圓,並利用 stroke 設定邊框顏色。
做到這裡重點來了,我們將利用 stroke-dasharray 和 stroke-dashoffset 來做出效果。
- stroke-dasharray 是我們的虛線,假設我們設定
stroke-dasharray="60"
,呈現出的效果會是 60px 的虛線跟 60px 的空格一組一組呈現。 - stroke-dashoffset 則會推移我們的虛線,假設我們設定
stroke-dashoffset="40"
,第一個虛線就會僅剩 20px 後面的循環則是正常進行。
利用這兩個性質,將 stroke-dasharray 動態綁定到 Vue.js 裡的一個函數,綁定的函數負責幫我們算出圓周長並回傳給我們,因此 stroke-dasharray 就會是我們的圓周長。
第一個虛線就是整個圓周代表一開始虛線就會填滿整個圓,所以我們就要控制 stroke-dashoffset 讓它來決定虛線出現的大小。
我們一樣將 stroke-dashoffset 動態綁定到 Vue.js 的另一個函數,這個函數會幫我們算出符合的 stroke-dashoffset 回傳給我們。
講到這裡是不是茫了,沒關係我們來看看程式碼就會知道是怎麼回事。1
2
3
4<svg style="transform:rotate(-90deg);width:540px;height:540px;" class="rounded-circle">
<circle cx='270' cy='270' r='135' stroke-width="270" :stroke-dasharray='strokeDasharray(135)'
:stroke-dashoffset='strokeDashoffset(135,Math.min(1,startTime/setTime))' fill='none'>
</svg>Math.min(1,startTime/setTime)
,startTime 和 setTime 是我自定義的變數,分別代表進行中的時間(startTime)與設定的時間(setTime),Math.min 會回傳數列中的最小值。看完程式碼之後有沒有比較清楚了,startTime 一直在減少,所以我們會一直將它與 setTime 的比值傳給我們的函數,函數會算出剩餘時間是圓周長的幾分之幾,並將其回傳,這就會是我們的 stroke-dashoffset 。1
2
3
4
5
6
7
8// 透過傳遞半徑給此函數,算出圓周長後回傳
strokeDasharray:function(r){
return r * 2 * Math.PI;
},
// 傳遞半徑和 Math.min() 參數後,算出現在剩餘的時間屬於圓周長的幾分之幾並回傳
strokeDashoffset:function(r,el){
return (this.strokeDasharray(r) * el );
},
簡單來講,這個方法就是透過 stroke-dashoffset 的推移來控制 stroke-dasharray 的出現。
製作第三個圓
至於,第三個圓就是為了讓它幫助我們擋住第二個圓多餘的部分,因為我們的 stroke 會填滿整個圓,如果不加上第三個圓就無法呈現出只有部分填滿的視覺效果。
第三個圓做法我就不多敘述,簡單來說,第三個圓圓心位置要跟前兩個圓一樣,在開發時我是用絕對定位做到這一點,再把它的長寬設定相較前兩個圓小即可。