Canvas畫(huà)圓啊犬,實(shí)現(xiàn)倒計(jì)時(shí)效果

最近在項(xiàng)目中遇到一個(gè)需求:繪制圓形進(jìn)度條倒計(jì)時(shí)功能
UI設(shè)計(jì)圖如下:


倒計(jì)時(shí)

對(duì)于圖片中數(shù)字的顯示實(shí)現(xiàn)起來(lái)是比較容易的俊扳,這里就直接忽略掉菊值,主要是想把繪制動(dòng)態(tài)圓的整個(gè)思路寫(xiě)下來(lái)

動(dòng)畫(huà)就是由一幅幅靜態(tài)圖片以極快的速度連續(xù)播放而產(chǎn)生的效果

canvas實(shí)現(xiàn)動(dòng)畫(huà)的原理亦是如此

每隔一段時(shí)間重新繪制圖形隨后清除圖形,模擬動(dòng)畫(huà)的過(guò)程

分析

有了對(duì)動(dòng)畫(huà)的理解刻剥,我們先分析一下應(yīng)該如何實(shí)現(xiàn)

  • 最底下先畫(huà)一個(gè)顏色為藍(lán)色的靜態(tài)圓(我們先稱其為基礎(chǔ)圓)
  • 最上面是一個(gè)動(dòng)態(tài)的圓遮咖,效果是每隔一定的時(shí)間圓走過(guò)一定的角度
  • 循環(huán)采用定時(shí)器(setTimeout 或者 setInterval)

實(shí)現(xiàn)

根據(jù)上面的分析就可以著手實(shí)現(xiàn)了,有關(guān)canvas的api不了解的請(qǐng)參考w3school

繪制基礎(chǔ)圓

  • 定義canvas畫(huà)布
<canvas id="canvas" width="200px" height="200px"></canvas>
  • 畫(huà)基礎(chǔ)圓
let canvas = document.getElementById('canvas');
let ctx =  canvas.getContext('2d'); //返回對(duì)象造虏,該對(duì)象提供畫(huà)圖用到的所有方法和屬性三繪制路徑

funcation drawBase(){
   ctx.beginPath(); //定義一天起始路徑
   ctx.lineWidth = 10; //設(shè)置線條的寬度
   ctx.strokeStyle = '#f6f6f6'; //設(shè)置筆觸顏色
   ctx.arc(x, y, r, start. end, false); //x,y為圓的圓心坐標(biāo)御吞,start為開(kāi)始角度,end為結(jié)束角度漓藕,false是設(shè)置繪制圓以順時(shí)針?lè)较?   ctx.arc(0, 0, 50, 0, Math.PI * 2, false);
   ctx.stroke(); //繪制定義好的路徑 (該函數(shù)是繪制圖形的關(guān)鍵哦)
}

有了上面的代碼魄藕,設(shè)計(jì)圖中灰色的圓就畫(huà)好了

繪制動(dòng)態(tài)圓

// 動(dòng)態(tài)圓
function drawValue(srcDegree, targetDegree) {
   ctx.beginPath();
   ctx.lineWidth = 12;
   ctx.lineCap = 'butt'; //設(shè)置線條結(jié)束時(shí)端點(diǎn)的樣式
   ctx.strokeStyle = this.config.lineColor;
   ctx.arc( 0,  0,  50, degreeToRadian(srcDegree - 90), degreeToRadian(targetDegree - 90),  false); //這里需要把度數(shù)處理為弧度,由于圓是默認(rèn)從0度開(kāi)始畫(huà)撵术,所以需要把角度減掉90度背率,從正上方的位置開(kāi)始
   ctx.stroke();
  }

drawValue這個(gè)函數(shù)其實(shí)與drawBase沒(méi)有區(qū)別,都是實(shí)現(xiàn)畫(huà)圓的功能嫩与,差別在于一個(gè)的目標(biāo)角度是變的寝姿,目前有利于理解先這么寫(xiě)李,之后可以重構(gòu)代碼合為一個(gè)函數(shù)會(huì)更加簡(jiǎn)潔划滋。

// 處理角度
function degreeToRadian(degree){
      return degree * Math.PI / 180;
}

現(xiàn)在我們要計(jì)算執(zhí)行一次畫(huà)圓函數(shù)角度應(yīng)該增加多少饵筑?

如果讓瀏覽器1s中渲染50次,那么一次需要20ms处坪,需求是120s畫(huà)完360度根资,120s等于120000ms, easing = 360/(120000/20)

// 清除畫(huà)布
function clearAll(){
    ctx.clearRect(0, 0, 200, 200); 
}

//圓形進(jìn)度條
function draw(srcDegree, targetDegree){
    clearAll();
    drawBase();
    drawValue(srcDegree, targetDegree);
}

現(xiàn)在定義好的兩個(gè)畫(huà)圓函數(shù)被draw調(diào)用架专,已經(jīng)實(shí)現(xiàn)了我們分析過(guò)程的一大部分,還需要對(duì)每次的目標(biāo)角度進(jìn)行計(jì)算玄帕。

let targetDegree = 0; //全局變量

function drawFrame(){
  let easing = 360 / 6000;
  //當(dāng)目標(biāo)角度達(dá)到滿圓時(shí)就可以清空計(jì)時(shí)器對(duì)象和畫(huà)布
  if(Math.round(targetDegree) >= Math.PI * 2){
      clearInterval(timer);
      clearAll();
  }else{
    targetDegree += easing; //實(shí)現(xiàn)勻速
    draw(srcDegree, targetDegree);
  }
}

現(xiàn)在所有的功能已經(jīng)實(shí)現(xiàn)部脚,只差調(diào)用,哈哈哈裤纹!

render(){
  let timer = setInterval(drawFrame, 20);
}

render(); //哇歐委刘!

是不是感覺(jué)還挺容易的,其實(shí)只要理解了動(dòng)畫(huà)的原理還是很容易上手的鹰椒,But問(wèn)題還有完锡移。。漆际。

問(wèn)題:如果說(shuō)用戶一直停留在倒計(jì)時(shí)這個(gè)頁(yè)面淆珊,那么整個(gè)過(guò)程是沒(méi)有問(wèn)題出現(xiàn)的,但是當(dāng)用戶在倒計(jì)時(shí)的過(guò)程中想隱藏頁(yè)面或者tab切換頁(yè)簽奸汇,這個(gè)時(shí)候你就會(huì)發(fā)現(xiàn)在離開(kāi)的過(guò)程中畫(huà)圓的速度跟你定義好的是不一樣的,那么問(wèn)題出在哪里呢施符?

這個(gè)現(xiàn)象的出現(xiàn)是定時(shí)器導(dǎo)致的,由于HTML5標(biāo)準(zhǔn)規(guī)定茫蛹,為了節(jié)電操刀,對(duì)不處于當(dāng)前窗口的頁(yè)面烁挟,瀏覽器會(huì)將時(shí)間間隔擴(kuò)大到1000ms婴洼,因此單位時(shí)間內(nèi)的畫(huà)圓角度就變了,以至于不能同步撼嗓。

出現(xiàn)這個(gè)好像解決不了的bug柬采,真的是很惱人唉!多虧且警,多虧我有小眼睛粉捻,哈哈,我們兩個(gè)一起討論出了斑芜,是否能判斷用戶離開(kāi)當(dāng)前頁(yè)面肩刃,然后在離開(kāi)期間擴(kuò)大角度的變化速率,這樣單位時(shí)間內(nèi)的角度是不變的杏头,當(dāng)用戶再回到頁(yè)面時(shí)也已經(jīng)渲染到正確的位置盈包。

查找資料后發(fā)現(xiàn),瀏覽器支持visibilitychange事件醇王,窗口隱藏或tab頁(yè)簽切換都屬于該事件呢燥,根據(jù)document.isHideen屬性可以知道頁(yè)面是否被隱藏。

 document.addEventListener('visibilitychange', this.eventHandler.bind(this));
 eventHandler() {
    let isHidden = document.hidden;
    if (isHidden) {
      this.easing = 360 / 5950 * 50;
    } else {
      this.easing = 360 / 5950;
    }
  }

我想對(duì)于這個(gè)需求或許還有其他更好的實(shí)現(xiàn)方法寓娩,后面會(huì)繼續(xù)查找資料叛氨, 若這篇文章哪里寫(xiě)的不夠好的呼渣,請(qǐng)大家不吝賜教!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寞埠,一起剝皮案震驚了整個(gè)濱河市屁置,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌畸裳,老刑警劉巖缰犁,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異怖糊,居然都是意外死亡帅容,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)伍伤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)并徘,“玉大人,你說(shuō)我怎么就攤上這事扰魂÷笃颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵劝评,是天一觀的道長(zhǎng)姐直。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蒋畜,這世上最難降的妖魔是什么声畏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮姻成,結(jié)果婚禮上插龄,老公的妹妹穿的比我還像新娘。我一直安慰自己科展,他們只是感情好均牢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著才睹,像睡著了一般徘跪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琅攘,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天垮庐,我揣著相機(jī)與錄音,去河邊找鬼乎澄。 笑死突硝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的置济。 我是一名探鬼主播解恰,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼锋八,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了护盈?” 一聲冷哼從身側(cè)響起挟纱,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎腐宋,沒(méi)想到半個(gè)月后紊服,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胸竞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年欺嗤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卫枝。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡煎饼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出校赤,到底是詐尸還是另有隱情吆玖,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布马篮,位于F島的核電站沾乘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏浑测。R本人自食惡果不足惜翅阵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尽爆。 院中可真熱鬧怎顾,春花似錦读慎、人聲如沸漱贱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幅狮。三九已至,卻和暖如春株灸,著一層夾襖步出監(jiān)牢的瞬間崇摄,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工慌烧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逐抑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓屹蚊,卻偏偏與公主長(zhǎng)得像厕氨,于是被迫代替她去往敵國(guó)和親进每。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評(píng)論 25 707
  • 一:canvas簡(jiǎn)介 1.1什么是canvas命斧? ①:canvas是HTML5提供的一種新標(biāo)簽 ②:HTML5 ...
    GreenHand1閱讀 4,683評(píng)論 2 32
  • 一田晚、canvas簡(jiǎn)介 1.1 什么是canvas?(了解) 是HTML5提供的一種新標(biāo)簽 Canvas是一個(gè)矩形區(qū)...
    Looog閱讀 3,942評(píng)論 3 40
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)国葬、插件贤徒、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,103評(píng)論 4 62
  • 醉后書(shū)0815閱讀 89評(píng)論 0 0