效果預覽
canvas 繪製基本流程
初始畫布
對於canvas的繪製,首先需要在html內指定一塊畫布,即<canvas></canvas>, 可以看做是在PS中新建一個空白文件,之後所有的操作都將呈現在這個文件之上,與PS的區別是,canvas本身沒有圖層的特性,當需要展示不同維度的檢視時,需要交由html的位置關係來解決。
canvas標籤上,值得一提的就是width和height兩個屬性,這兩個屬性代表著畫布的寬高,與canvas樣式上的寬高有很大區別。在瀏覽器當中,看到的圖形繪製大小,本身是由canvas.style.width/canvas.style.height決定的,他們決定了canvas這個dom元素的大小關係,而canvas.width和canvas.height決定的是canvas內部圖形的大小關係。當這兩個寬高比不同時,就會產生視覺上的形變。即,把canvas.style.height放大為2倍時,顯示效果會被拉伸:
當不設定樣式寬高時,瀏覽器中canvas大小由畫布大小決定(在實際開發中,碰到一個例外,是在使用mapbox時,繪製map的標籤如果只設定canvas畫布大小時,在ios移動端的瀏覽器上顯示異常,PC正常)。
獲取上下文
所謂上下文,代表的就是一個環境,在這個環境當中你可以獲取到相關的方法,變數。程式中有上下文,html的媒體中也有上下文,比如音訊上下文(AudioContext),只有拿到了上下文,才能進行相關的方法操作,canvas也是如此,canvas上的方法都是藉由canvas上下文得到。
<canvas id="leftCanvas"></canvas>
const canvasL = document.getElementById("leftCanvas");
const cxtL = canvasL.getContext("2d");
配置線條
本次圓弧動畫需要用到的上下文屬性有:
- lineCap 線段端點形狀,本次設定為round
- lineWidth 線寬
- strokeStyle 線條填充顏色
- clearRect 清除畫布裡面的內容
- beginPath 在畫布上開始一段新的路徑
- arc 圓弧繪製引數配置
- stroke 繪製
角度計算
角度計算之前,先介紹一下繪製圓弧的基礎api arc。
ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);
這個函式可以接收6個引數,前五個為必填,分別為圓心x座標,圓心y座標,半徑,起始角度,結束角度,方向(預設為false,順時針)。
回到圓弧動畫,當前動畫有兩段,以順時針方向這段為例。
- x, y:在canvas當中,座標系預設以左上角為原點,如果想讓圓弧動畫以畫布中心點旋轉,可以將圓心點設定為畫布中心點,即畫布長寬的1/2,假設設定的畫布長寬均為100,那麼圓心點的座標即為(50, 50),這個圓就繪製在了畫布中間。
- radius:為了不與畫布產生切角,半徑設定比畫布一般略小,。
- startAngle:起始角度為正北方向,而圓以x軸水平方向為0度,因此將起始點逆時針旋轉90°,即:-1 / 2 * Math.PI。
- endAngle:因為圓弧長度為30°,終點角度在起始角度的基礎上增加 1 / 6 * Math.PI。
順時針方向圓弧初始配置為:
cxtL.arc(WidthL / 2, HeightL / 2, WidthL / 2 - 5, -1 / 2 * Math.PI, 1 / 6 * Math.PI, false);
開啟動畫
window.requestAnimationFrame()
藉助requestAnimationFrame,來對canvas圓弧進行不斷的重繪,每次重繪canvas之前清空畫布,每輪動畫方向角偏移2°,即2 / 180 * Math.PI,動畫結束的標記為圓弧終點的角度,移動至3 / 2 * Math.PI,當滿足條件時,呼叫window.cancelAnimationFrame(animationId)取消動畫。
螢幕適配
通過進入html後,動態獲取視口,來設定canvas寬高,比如希望畫布大小為視窗的寬度的15%,可以通過
const clientWidth = document.documentElement.clientWidth;
const canvasWidth = Math.floor(clientWidth * 0.15);
const canvasL = document.getElementById("leftCanvas");
canvasL.setAttribute("width", canvasWidth + "px");
這樣就可以使畫布適應不同螢幕大小。
以下為未整理程式碼,較亂,僅供參考。