筆主最近一個多月以來 「深刻「 研究了 canvas 的實現原理,一口氣讀完了 《HTML5 Canvas 核心技術》這本書;而這一切以及這篇文章的誕生,都源於筆主公司的一位實習產品經理~
這位實習生擁有剛畢業時的血氣方剛,以及天馬行空的想象力;他從未考慮過項目的實際需求,以及上線時間成本,在咱們公司以注重產品功能爲導向的氛圍中,自成一派,成爲一股清流 😂
一個推廣的小頁面,須要有山有水,有天空有流星,手指放上去還得泛起漣漪,拿到需求文檔時嚇得我趕忙上 GG 搜 demo,這時我發現單個 demo 都能很好的運行在頁面中,但是當他們合併之後,在瀏覽器調試面板中一行行鮮紅的文字不停的拍打着個人臉頰。我忽然發現本身在遇到一些奇葩需求時,是多麼的無助。由於我不會 canvas 啊!
本系列文章旨在與你們分享筆主這段時間學習 canvas 的經驗,由淺入深,將本身實際工做過程當中抄過的 demo (什麼?作個抽獎?評估時間?你等等,我搜下 demo…… 哦,不用評估時間了,已經改好了)都一一實現一遍,讓媽媽不再用擔憂咱們遇到奇葩需求啦!javascript
原文地址 喜歡就給我個大大的 ✨ 吧!css
先上預覽 demo html
咱們假設咱們的讀者都很是熟悉 javascript 原生語法。java
咱們想要操做 canvas,首先須要獲取這個 canvas 對象css3
<canvas id="canvas" width="250" height="50"></canvas>
複製代碼
// 獲取 canvas 對象
let canvas = document.getElementById('canvas'),
// 獲取 cavans 繪圖環境對象,參數爲 2d
context = canvas.getContext('2d');
複製代碼
context 是繪圖環境對象,若是你在瀏覽器中輸出 context,你會發現裏面包含了許多屬性,如:fillStyle
strokeStyle
等,以及一些函數方法,arc()
rect()
save()
restore()
clip()
等等。git
context.rect($x, $y, $width, $height)
github
矩形是最簡單的圖像繪製了;canvas
🔑 參數: y:分別對應矩形左上角在 canvas 畫布中的座標;
height:就是矩形的寬高啦;數組
⚠️ 不過值得注意的是,調用這個方法,~只是繪製的矩形的路徑~,該路徑是不可見的,除非你在後面調用 context.fill()
和 context.stroke()
方法,進行填充或者描邊。瀏覽器
填充描邊的表現形式取決於 context 繪圖環境的 fillStyle
和strokeStyle
屬性的值。
context.arc($x, $y, $radius, $start_radian, $end_radian [, $clockwise])
圓形稍微複雜一丟丟,不過也很簡單啦。
🔑 參數: y:表明圓的圓心在 canvas 畫布中的座標點;
start_radian $end_radian:起始角和終止角,他們接收的值只能是弧度。
記得圓周率麼?記得3.14是啥不,在 javascript 中
Math.PI
就表明的 π ;
簡單的說,圓有360°,而一個 π 是180°,你想畫個整圓,就是從 0° 到 360° 走一圈,Math.PI * 2
;你想畫個半圓,就是 0° 到 180°,Math.PI
;
$clockwise:傳入布爾值,false 圓由順時針繪製;true 圓由逆時針繪製。
和矩形相同,這個方法也只是繪製了一個路徑,想要在頁面顯示,任然是須要調用 context.fill()
和 context.stroke()
兩個方法。
context.beginPath()
咱們在建立一個集合圖形以前,都應當先調用該方法,該方法會清除上一次繪製時留下的路徑,並將本次繪製的路徑做爲 ~當前路徑~。
let canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
/** * 繪製一個矩形 * @param {Num} x 矩形的左上角 x 軸的位置 * @param {Num} y 矩形的左上角 y 軸的位置 * @param {Num} width 矩形的寬度 * @param {Num} height 矩形的高度 */
function drawRect(x, y, width, height) {
context.beginPath(); // 清空上一次的路徑
context.rect(x, y, width, height); // 建立一個矩形路徑
context.fill(); // 將該矩形路徑填充爲繪圖環境指定的填充顏色 context.fillStyle
}
/** * 繪製一個圓形 * @param {Num} centerX 圓心 x 軸座標 * @param {Num} centerY 圓心 y 軸座標 * @param {Num} radius 圓的半徑 */
function drawCircle(centerX, centerY, radius) {
context.beginPath();
context.arc(centerX, centerY, radius, 0, Math.PI * 2, false);
context.fill();
}
drawRect(0, 0, 100, 100);
drawCircle(160, 50, 50);
複製代碼
context.clearRect($x, $y, $width, $height)
該方法,擦除規定矩形中的全部內容;參數同繪製矩形是同樣的,只不過這是清除!canvas 的狀態包括了:
transform
的東西,不用擔憂,本章並不涉及;context.clip()
後面會詳細講到;fillStyle[規定填充的顏色]
strokeStyle[規定描邊的顏色]
,這些狀態決定的 canvas 中繪製的圖像的展現效果,他們是全局的,也就是說一旦規定了fillStyle
爲紅色,那麼除非在 javascript 後面重置這個屬性,不然你未來繪製出來的幾何圖形永遠都是紅色的。context.fillStyle = 'red';
drawRect(0, 0, 100, 100); // -> red
drawRect(110, 0, 100, 100); // -> red
context.fillStyle = 'blue';
drawRect(220, 0, 100, 100); // -> blue
複製代碼
若是有個需求,我想要先繪製一個紅色的矩形,接着繪製一個藍色的矩形,最後再繪製一個紅色的矩形
咱們知道 javascript 是逐條同步執行的,那麼要實現上面的需求,咱們須要先定義繪圖環境的填充顏色爲紅色,繪製了第一個紅色矩形後,再定義繪圖環境的填充顏色爲藍色,繪製,再定義繪圖環境的填充顏色爲紅色,就像這樣:
context.fillStyle = 'red';
drawRect(0, 0, 100, 100); // -> red
context.fillStyle = 'blue';
drawRect(110, 0, 100, 100); // -> blue
context.fillStyle = 'red';
drawRect(220, 0, 100, 100); // -> red
複製代碼
是否是以爲這樣作很是的傻~
此時 save() 和 restore() 就站出來講不了!
context.save()
:能將執行該方法以前的全部 ~canvas 狀態~ 保存下來; context.restore()
:將 save 方法保存的 ~canvas 狀態~ 釋放出來;
因此上面弱智的寫法,咱們能夠寫成這樣:
context.fillStyle = 'red';
drawRect(0, 0, 100, 100); // - red
context.save();
context.fillStyle = 'blue';
drawRect(110, 0, 100, 100); // -> blue
context.restore();
drawRect(220, 0, 100, 100); // -> red
複製代碼
save 方法保存的是 context.fillStyle = 'red'
這個狀態,當設置這個狀態爲藍色時,context 繪圖環境的 fillStyle 屬性變成了藍色,當執行 restore 方法時,又被恢復成了紅色。
context 繪圖環境對象提供了一個 context.clip()
剪輯區域方法,這也是本章實現橡皮擦功能的核心方法。
該方法會將 ~當前路徑~ 做爲一個剪輯區域,使該區域之外的圖像不可見。
而且在剪輯區域中,全部填充,清除等操做不會影響剪輯區域之外的內容。
因此咱們能夠建立一個剪輯區域,在這個剪輯區域中執行清除操做,就能夠擦除 canvas 畫布中指定的內容。
drawRect(0, 0, 100, 100);
context.save();
// 建立一個圓形路徑,並做爲剪輯區域,擦除該區域中的全部內容
drawCircle(0, 0, 50);
context.clip();
context.clearRect(0, 0, canvas.width, canvas.height);
context.restore();
drawRect(110, 0, 100, 100);
複製代碼
本章須要用到的基礎知識就講到這裏啦,若是你們還有疑問,能夠查閱 w3school 上的 canvas 文檔
⚠️ 這個 demo 只能運行在手機上,瀏覽器須要打開手機模擬。
🚶 思路:
drawEraser()
,該方法會將當前的路徑做爲剪輯路徑繪製,並::清除該路徑內的全部內容::;drawEraser()
方法,繪製第一個剪輯區域;drawEraser()
方法,繪製剪輯區域,實現橡皮擦效果。<!DOCTYPE html>
<html>
<head>
<title>橡皮擦</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
</head>
<body>
<canvas id="canvas" width="300" height="300" style="background: #eee">
Canvas not supported
</canvas>
<script> var canvas = document.getElementById('canvas'), context = canvas.getContext('2d'), ERASER_SIZE = 15, // 橡皮擦的大小 dragging = false; // 是否處在拖動狀態 /** * 轉換座標值 * 將鼠標點擊或移動時獲取的座標值,減去 canvas 相對窗口的座標值,就是在 canvas 畫布中的座標值 * @param {Obj} e 手指當前相對窗口的座標位置 */ function windowToCanvas(e) { let x = e.targetTouches[0].clientX, y = e.targetTouches[0].clientY, bbox = canvas.getBoundingClientRect(); return { x: x - bbox.left, y: y - bbox.top } } /** * 繪製剪輯區域,並清除該區域中的內容 * @param {Obj} loc 手指當前相對 canvas 畫布中的座標位置 */ function drawEraser(loc) { context.save(); context.beginPath(); context.arc(loc.x, loc.y, ERASER_SIZE, 0, Math.PI * 2, false); context.clip(); context.clearRect(0, 0, canvas.width, canvas.height); context.restore(); } /** * 頁面加載時,繪製一個鋪滿 canvas 畫布的矩形 * 該矩形用於被擦除 */ window.onload = function (e) { context.save(); context.fillStyle = '#666'; context.beginPath(); context.fillRect(0, 0, canvas.width, canvas.height); context.restore(); } /** * ① 手指按下時,開啓 dragging 狀態,並繪製剪輯區域 */ canvas.addEventListener('touchstart', function (e) { var loc = windowToCanvas(e); dragging = true; drawEraser(loc); }) /** * ② 手指移動時,不斷進行剪輯區域的繪製,以及路徑更新,實現擦除的效果 */ canvas.addEventListener('touchmove', function (e) { var loc; if (dragging) { loc = windowToCanvas(e); drawEraser(loc); } }) /** * ③ 手指離開,結束擦除過程 */ canvas.addEventListener('touchend', function (e) { dragging = false; }) </script>
</body>
</html>
複製代碼
使用 canvas 實現橡皮擦功能是很是簡單的。咱們能夠把橡皮擦的形狀換成矩形,多邊形,五角星等等;只須要改變繪製剪輯區域的路徑就好了;
刮刮卡的功能,也徹底是由橡皮擦功能實現的,咱們能夠把 canvas 的背景圖片設置爲開獎的內容,文字等,用一個數組將這些圖片的路徑包含進去,每次加載頁面時,隨機調用一個數組元素;
這期內容就講到這裏,下期帶你們用 canvas 實現 大轉盤抽獎,九宮格抽獎。3Q,阿里呀多。
原文地址 喜歡就給我個大大的 ✨ 吧!