用Canvas繪制快應(yīng)用開發(fā)工具的logo12.14
Canvas在Android原生開發(fā)和傳統(tǒng)HTML5開發(fā)的舞臺(tái)上都扮演著重要的角色,我們通過本文了解如何正確使用 canvas 畫布,以及如何通過 canvas 繪制復(fù)雜的圖形及動(dòng)畫。
快應(yīng)用官方文檔提供了快應(yīng)用logo(如下圖)的繪制過程:
本文我們來學(xué)習(xí)一下快應(yīng)用開發(fā)工具的logo(如下圖)的繪制過程:
分析圖片
用PhotoShop打開路徑為的圖片,并添加參考線,主要為了獲取透明邊框的寬度(你可以理解為圖片文件的padding)、藍(lán)色邊框的寬度、藍(lán)色圓弧的厚度、紅色圓點(diǎn)的直徑以及紅色和藍(lán)色的具體RGB代碼。
因?yàn)榭鞈?yīng)用的Canvas不支持透明背景(原文如下),所以本文成品略有瑕疵。
繪制白色填充和藍(lán)色邊框
Canvas 繪圖的兩大基本繪制方式就是繪制填充和描邊。所謂填充,就是指用指定的內(nèi)容填滿所要繪制的圖形,最終生成一個(gè)實(shí)心的圖案,繪制填充矩形的方法是這樣的:ctx.fillRect(x, y, width, height);所謂描邊,就是沿著所要繪制的圖形邊緣,使用指定的內(nèi)容進(jìn)行描繪,最終生成的是空心的圖案,繪制描邊矩形的方法是這樣的ctx.strokeRect(x, y, width, height)。
看代碼望文生義就可以知道如果既要填充又要描邊,則不得不分別繪制兩次才能完成最終圖案,并且不能自定義描邊寬度。
為了能夠自定義描邊寬度,我們可以利用路徑來實(shí)現(xiàn)快應(yīng)用開發(fā)工具的logo的藍(lán)色邊框和白色填充。繪制白色填充和藍(lán)色邊框的代碼如下:
- // 開始繪制路徑
- ctx.beginPath();
- // 起點(diǎn)(左上角)
- ctx.moveTo(r , r);
- // 繪制到第二個(gè)點(diǎn)的線段(左下角)
- ctx.lineTo(r, h - r );
- // 繪制到第三個(gè)點(diǎn)的線段(右下角)
- ctx.lineTo(h - r , h - r);
- // 繪制到終點(diǎn)的線段(右上角)
- ctx.lineTo(h - r, r );
- // 用線段閉合路徑(直接從終點(diǎn)連回到起點(diǎn))
- ctx.closePath();
- // 描邊寬度
- ctx.lineWidth = r;
- // 定義描邊樣式,本次是純色
- ctx.strokeStyle = '#4286f5';
- // 繪制描邊
- ctx.stroke();
- // 定義填充樣式,用另一種格式的純色
- // 注意順序是R(紅色)、G(綠色)、B(藍(lán)色)、A(不透明度)而不是A、R、G、B
- ctx.fillStyle = 'rgba(255,255,255,255)';
- // 繪制填充
- ctx.fill();
- 官方文檔和我的注釋都很詳細(xì),我補(bǔ)充幾點(diǎn):
- 1、strokeStyle和fillStyle的值可以為線性漸變或中心漸變,本文只討論純色的情況
- 2、rgba的四個(gè)參數(shù)分別為R(紅色)、G(綠色)、B(藍(lán)色)、A(不透明度)而不是常說的A、R、G、B
- 繪制藍(lán)色圓弧和紅色圓點(diǎn)
- 藍(lán)色邊框和白色背景繪制了以后,下一步就是繪制藍(lán)色圓弧和紅色圓點(diǎn)了。紅色圓點(diǎn)的本質(zhì)上就是一個(gè)實(shí)心圓,繪制實(shí)心圓的方法就是閉合的圓形路徑填充顏色。代碼如下:
- // 繪制紅色圓點(diǎn)
- ctx.beginPath();
- ctx.arc(h - 2 * s, h - 2.5 * s , s / 2 , 0, p * 2, false);
- ctx.fillStyle = 'rgb(234, 67, 53)'
- ctx.fill();
- 繪制圓弧的arc()方法的五個(gè)參數(shù)分別為圓心X坐標(biāo)、圓心Y坐標(biāo)、半徑、圓弧起點(diǎn)、圓弧終點(diǎn)、是否逆時(shí)針。弧度的計(jì)算方法為角度乘以 2*PI/360,幾個(gè)關(guān)鍵方向的弧度如下:左:0或2*PI,右:PI,上:P/2,下:P/2*3 。
- 弧線段的填充、描邊方式和線段一樣。
- 我們?cè)倮L制較復(fù)雜的藍(lán)色圓弧:
- // 繪制藍(lán)色圓弧
- ctx.beginPath();
- // arc()方法參數(shù)分別為圓心X坐標(biāo)、圓心Y坐標(biāo)、半徑、起點(diǎn)弧度、的終點(diǎn)弧度、是否是逆時(shí)針
- // 逆時(shí)針繪制空心內(nèi)圈
- ctx.arc(h / 2, h / 2, h/6, -p / 4 , -p / 4 * 7, true);
- // 順時(shí)針繪制下側(cè)封邊
- ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 + (h / 6 + s / 2) * q , s / 2,-p / 4 , p / 4 * 7,false);
- // 順時(shí)針繪制實(shí)心外圈
- ctx.arc(h / 2, h / 2, h/6 + s, -p / 4 * 7, -p / 4, false);
- // 順時(shí)針繪制上側(cè)封邊
- ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 - (h / 6 + s / 2) * q , s / 2,-p / 4*7 , p / 4 ,false);
- // 填充顏色
- ctx.fillStyle = '#4286f5';
- ctx.fill();
注意弧線也必須閉合,否則會(huì)出bug
成品和完整源碼
本文的成品如下圖所示:
上文提到快應(yīng)用的Canvas暫時(shí)不支持透明背景,所以官方logo的透明邊框變成了白色邊框,這是一個(gè)瑕疵所在。
本文的完整源碼如下:
- <template>
- <div class="doc-page">
- <div class="content" >
- <canvas class="new_canvas" id="newCanvas"></canvas>
- </div>
- </div>
- </template>
- <style>
- .content {
- flex-direction: column;
- align-items: center;
- width: 100%;
- padding: 20px;
- background-color: #000000;
- }
- .new_canvas {
- height: 300px;
- width: 300px;
- background-color: #00000000;
- }
- </style>
- <script>
- export default {
- private: {
- drawComplete: false
- },
- onInit() {
- this.$page.setTitleBar({
- text: 'Canvas'
- })
- },
- onShow() {
- if(!this.drawComplete) {
- this.drawCanvas();
- }
- },
- drawCanvas() {
- const canvas = this.$element('newCanvas'); //獲取 canvas 組件
- const ctx = canvas.getContext('2d'); //獲取 canvas 繪圖上下文
- var r = 20;// 空白處和藍(lán)色邊框的寬度
- var h = 300;// 畫布大小
- var p = Math.PI;// 圓周率
- var q = Math.sin(45 * 2 * p / 360);// 45度角的正弦(角度乘以 2*PI/360就是弧度)
- var s = 30;// 藍(lán)色圓弧厚度和紅色圓點(diǎn)直徑
- // 開始繪制路徑
- ctx.beginPath();
- // 起點(diǎn)(左上角)
- ctx.moveTo(r , r);
- // 繪制到第二個(gè)點(diǎn)的線段(左下角)
- ctx.lineTo(r, h - r );
- // 繪制到第三個(gè)點(diǎn)的線段(右下角)
- ctx.lineTo(h - r , h - r);
- // 繪制到終點(diǎn)的線段(右上角)
- ctx.lineTo(h - r, r );
- // 用線段閉合路徑(直接從終點(diǎn)連回到起點(diǎn))
- ctx.closePath();
- // 描邊寬度
- ctx.lineWidth = r;
- // 定義描邊樣式,本次是純色
- ctx.strokeStyle = '#4286f5';
- // 繪制描邊
- ctx.stroke();
- // 定義填充樣式,用另一種格式的純色
- // 注意順序是R(紅色)、G(綠色)、B(藍(lán)色)、A(不透明度)而不是A、R、G、B
- ctx.fillStyle = 'rgba(255,255,255,255)';
- // 繪制填充
- ctx.fill();
- // 繪制藍(lán)色圓弧
- ctx.beginPath();
- // arc()方法參數(shù)分別為圓心X坐標(biāo)、圓心Y坐標(biāo)、半徑、起點(diǎn)弧度、的終點(diǎn)弧度、是否是逆時(shí)針
- // 逆時(shí)針繪制空心內(nèi)圈
- ctx.arc(h / 2, h / 2, h/6, -p / 4 , -p / 4 * 7, true);
- // 順時(shí)針繪制下側(cè)封邊
- ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 + (h / 6 + s / 2) * q , s / 2,-p / 4 , p / 4 * 7,false);
- // 順時(shí)針繪制實(shí)心外圈
- ctx.arc(h / 2, h / 2, h/6 + s, -p / 4 * 7, -p / 4, false);
- // 順時(shí)針繪制上側(cè)封邊
- ctx.arc(h / 2 + (h / 6 + s / 2) * q , h / 2 - (h / 6 + s / 2) * q , s / 2,-p / 4*7 , p / 4 ,false);
- // 填充顏色
- ctx.fillStyle = '#4286f5';
- ctx.fill();
- // 繪制紅色圓點(diǎn)
- ctx.beginPath();
- ctx.arc(h - 2 * s, h - 2.5 * s , s / 2 , 0, p * 2, false);
- ctx.fillStyle = 'rgb(234, 67, 53)'
- ctx.fill();
- this.drawComplete = true;
- }
- }
- </script>