簡單的 canvas 翻角效果

右上角需要從無的狀態撕開一個標記 , 且有動畫過程 , 上圖是實現的效果圖 , 不是gif

對這個翻角效果的難點在於沒有翻開的時候露出的是dom下面的內容 , 實現角度來說 純dom + css動畫的設計方案並沒有相出一個好的對策 ; 於是撿起了好久之前學的入門級別的canvas;

下面說一下實現思路:

  1. 動畫拆分 :
    將此動畫分解成兩部分 , 一部分是翻頁出現的黑色三角區域 , 另一個是露出的橘色展示內容
    對於橘色的展示內容區域相對好一些 , 因爲是一個規則圖形 , 而黑色區域相對較難;

先從基礎canvas使用方法說起 :

1

2

3

<div class="container">

    <canvas class="myCanvas" width="100" height="100"></canvas>

</div>

佈局如上 , 這裏要說一點踩過的坑是 , canvas必須要設置上width 與 height , 此處並非爲css中的width與height;而是寫在dom上的屬性 ; 因爲dom上的width與height標識了canvas的分辨率(個人理解); 所以此canvas畫布分辨率爲100*100 , 而展示尺寸是可以通過css控制;

js中首先要做的是獲取canvas對象 ,

1

2

3

4

var canvas = document.querySelector('.myCanvas'); //獲取canvas對應dom

var ctx = canvas.getContext('2d'); //此方法較爲基礎 , 意爲獲取canvas繪畫2d內容的工具(上下文)

var cw = 100; //分辨率 , 其實直接從dom上獲取可能更好些

var ch = 100; //分辨率 , 其實直接從dom上獲取可能更好些

ctx這個繪畫上下文在這個教程中起到的作用至關重要 ; 它提供了非常強大的api , 比如用於畫線 , 填充 , 寫文字等 , 這樣看來理解爲畫筆會更爲簡明一些;

此處效果需要用到的api如下 ( 不做詳細解釋 , 可w3c自行查詢 );

1

2

3

4

5

6

7

8

9

10

11

12

ctx.save() //保存上下文狀態 (比如畫筆尺寸 顏色 旋轉角度)

ctx.restore() //返回上次保存的上下文狀態

ctx.moveTo(x,y) //上下文移動到具體位置

ctx.lineTo(x,y) //上下文以劃線的形式移動到某位置

ctx.stroke() // 畫線動作

ctx.quadraticCurveTo() //上下文(畫筆)按貝塞爾曲線移動(簡單理解爲可控的曲線即可)

ctx.arc() //畫圓

ctx.beginPath() //開啓新的畫筆路徑

ctx.closePath() //關閉當前畫筆路徑

ctx.createLinearGradient() //創建canvas漸變對象

ctx.fill() //對閉合區域進行填充

ctx.globalCompositeOperation //畫筆的重疊模式

可能方法列舉的不夠詳盡 , 見諒.

首先是繪製黑色翻出的部分 , 圖形分解爲如下幾部分(請根據上圖腦補)

  1. 左上角向右下的半弧 ╮

  2. 然後是豎直向下的豎線 |

  3. 然後是向右的半圓 ╰

  4. 再然後是向右的橫線

  5. 接着還是向右下的半弧 ╮

  6. 最後是將線連接會起點

於是第一步 我們要先將畫筆移動到 起始位置

1

ctx.moveTo(50,0);

然後

1

ctx.quadraticCurveTo(55 , 5 , 55 , 25); // 可以理解爲從(50,0)這個點劃線到(55,25)這個點 , 中間會受到(55,5)這個點將直線想磁鐵一樣"吸"成曲線;

於是第一個向右下的半弧完成 , 此時canvas上沒有任何繪製內容 , 因爲還沒有執行過繪製方法例如stroke或fill,

接下來直線向下就是簡單的移動

1

ctx.lineTo(55 , 40);

這個時候我們接下來應該畫向右的半圓 , 這個時候再用貝塞爾曲線繪製 實在有些不太合適 , 因爲從圖上來看 , 這裏完全是1/4的圓 , 所以要使用canvas提供的畫圓的api

1

ctx.arc(60 , 40 , 5 , Math.PI , Math.PI / 2 , true);

上述畫圓的代碼意爲 : 以(60,40)點爲圓心 , 5爲半徑 , 逆時針從 180度繪製到90度 , 180度就是圓心的水平向左 到達點(55,40) , 與上一步連接上 , 然後又因爲屏幕向下爲正 , 90度在圓心正下方 , 所以繪製出此半圓

於是按照相同的步驟 水平向右

1

ctx.lineTo(75 , 45);

然後再次使用貝塞爾曲線用第一步的思路畫出向右下的弧;

1

ctx.quadraticCurveTo( 95 , 45 , 100 , 50 );

同理 上述貝塞爾曲線可以理解爲一條從( 75 , 45 ) 到 ( 100 , 50 )的線被 ( 95 , 45 )”吸”成曲線

最後鏈接起點 , 閉合繪畫區域

1

ctx.lineTo(50 , 0);

這個時候黑色區域的翻頁就畫完了 , 然後此時開始填充顏色 ;

1

2

3

4

var gradient = ctx.createLinearGradient(50 , 50 , 75 , 75);

gradient.addColorStop(0 , '#ccc');

gradient.addColorStop(0.7 , '#111');

gradient.addColorStop(1 , '#000');

我們通過上述代碼創建一個 從( 50 , 50 )點到(75 , 75)點的線性漸變 , 顏色從 #ccc 到 #111 到 #000 ; 創建高光效果;
然後填充:

1

2

ctx.fillStyle = gradient;

ctx.fill();

於是翻頁效果的一半就算完成了。

至此 , 我要說一點我領悟的canvas的繪畫”套路”;

對於上述教程中 , 有一步我們使用了一個詞叫做 閉合 , 閉合的概念在canvas中是真是存在的 , 對於fill方法來說 填充的區間是有一個空間尺寸纔可以的 , 比如我們繪畫的這個黑色的三角形 , 加入我們最後沒有將終點與起點相連接 , 同樣canvas會自動幫我們鏈接最後一筆繪畫的位置到起點 , 強制行程閉合空間 , 而這樣我們想再多畫幾個新的閉合空間就麻煩了 , 所以canvas提供瞭如下api 新建閉合路徑:

1

2

ctx.beginPath(); //新建路徑

ctx.closePath(); //閉合路徑

所以對於我們接下來要繪製右上角橘色區域來說 , 我們在繪製黑色區域之前首先要做的是

1

2

ctx.beginPath();

...

然後在fill之前 我們應該

1

ctx.closePath();

也就是說beginPath 到 closePath之間標識着我們自己的一個完整的繪畫階段.

那麼接下來繪製右上角的橘色區域就簡單很多了:

1

2

3

4

5

6

7

8

ctx.beginPath();

ctx.moveTo(50,0);

ctx.lineTo(100,50);

ctx.lineTo(100,0);

ctx.lineTo(50,0);

ctx.closePath();

ctx.fillStyle = '#ff6600';

ctx.fill();

於是右上角的橘色區域我們就繪製完成了;

文字繪製

接下來繪製”new” , 實際上是使用canvas簡單的文本繪製 , 代碼如下:

1

2

3

4

5

6

7

8

9

10

var deg = Math.PI / 180;

ctx.globalCompositeOperation = 'source-atop'; //canvas層疊模式

ctx.beginPath();

ctx.font = '14px Arial'; //設置字體大小 字體

ctx.textAlign = 'center'; // 字體對齊方式

ctx.translate(78 , 22);  // 移動canvas畫布圓點

ctx.rotate(45 * deg);    // 旋轉畫布

ctx.fillStyle = '#fff';  // 設置文字顏色

ctx.fillText('NEW' , 0 , 0); //文字繪製動作

ctx.closePath();

對於上述代碼中 , 文字的相關api是屬於沒有難度的 , 只是設置而已 , 需要理解的部分在於 translate和rotate,

這兩個方法中 translate的意思爲移動canvas畫布的( 0 , 0 )點到 (78,22),然後旋轉45度, 再將文字渲染在原點 , 實際就是 ( 78 , 22 ) 這個點上, 此時我們對canvas的畫筆做出了非常大的修改


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章