今天要用 canvas
來畫圖,canvas可以用來即時畫圖、畫動畫,還可以用來處理影片,為影片增加特效。今天要來做一個會隨著點擊時間「移動」、「變色」、「縮放」的畫筆
首先要設置一個 <canvas>
來裝我們要畫圖的地方,並設置畫布的大小。要注意是畫布的像素大小,而不是 canvas
的元素大小,元素大小是 canvas.style.width
。如果設定了元素大小,會等比例縮放畫布
Canvas width and height in HTML5
<!--產生一個像素是800*800的畫布-->
<canvas id="draw" width="800" height="800"></canvas>
接著我們使用 cavnas.width
、canvas.height
畫布變成全螢幕大小,並設置 canvas.getContext()
來讓畫布是 2d
的或 3d
的,這裡我們設置 2d
畫布
const canvas = document.getElementById('draw');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
接著我們要讓滑鼠「拖曳」的時候才會有效果,拖曳就是滑鼠「左鍵點擊」並「移動」,所以我們設置一個 isDrawing
來監測滑鼠是否被點擊,預設是 false
。只有在 isDrawing
為 true
時才會畫圖。所以只有在 mousedown
事件才會改成 true
, mouseup
、mouseout
(離開視窗)都會變成 false
。
let isDrawing = false;
function draw() {
if (!isDrawing) return;
//畫圖
}
canvas.addEventListener('mousedown', () => isDrawing = true);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);
接下來就是要設定怎麼畫了, canvas
是原點在左上角,往右往下皆為正的坐標系,知道這點就可以開始畫圖了。首先使用 .beginPath()
表示開始規劃路徑, .moveTo()
移動畫筆, .lineTo()
則是從當前位置畫線到參數的位置, .closePath()
表示結束規劃路徑,最後 .stroke()
才是真的畫圖。
let lastX = 0; //設定初始x位置
let lastY = 0; //設定初始y位置
function draw(e) {
ctx.beginPath();//開始規劃路徑
ctx.moveTo(lastX, lastY);//畫筆移動到座標(lastX, lastY)
ctx.lineTo(e.offsetX, e.offsetY); //畫線到 (e.offetX,e.offetX)
ctx.closePath();//結束規劃路徑
ctx.stroke(); //作畫
}
這時候你會看到的圖案是是一個從(0, 0)到滑鼠位置的軌跡線,這是因為我們並沒有隨時更新位置。
我們可以把時間切成極短的時間,這樣「短時間」的線連起來就會是直線
function draw(e) {
...
[lastX, lastY] = [e.offsetX, e.offsetY]; //將結束位置設為下次起始位置
}
這時會發現每次下筆都是從上一次結束的位置,而不是下筆位置,因此我們再對 mousedown
做修改
一點擊就設定成起始位置。
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY]
});
這樣我們就完成畫線了。
但是此時看線不太是圓的,所以我們要對他做修改,讓線更圓滑。
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.lineWidth = 50;
其中 linesJoin
是兩線相接的樣式 ;lineCap
是對末端做修改; lineWidth
是畫筆的粗度。
接著我們要來控制線的粗細變化,誠如上面提到,我們將初始寬度設定在 50,我們希望線條寬度在1~100之間變化。
所以我們設定一個變數 direction
為 true
來表示正向, false
來表示反向。
當超出邊界的時候就更改 direction
,讓畫筆的寬度的變量變號。
let direction = true;
function draw(e) {
...
if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) {
direction = !direction;
}
if(direction){
ctx.lineWidth++;
} else {
ctx.lineWidth--;
}
}
最後是顏色,這邊用的是 hsl 顏色表示法,HSL分別代表 Hue(顏色)
, Saturation(飽和度)
, Lightness(亮度)
。我們先不管後面兩個,只看顏色表示法。由於 hue 的顏色是360度的方式表示紅橙黃綠藍靛紫,所以我們讓變數 hue
雖呼叫函式時增加, 到達360時,就讓它歸0,這樣就可以呈現顏色變化了
let hue = 0;
function draw(e) {
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
ctx.beginPath();
...
hue++;
if (hue >= 360) {
hue = 0;
}
}