iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 8
0

今天要做的是操作 Canvas,並做出類似小畫家的效果,隨意在畫布上作畫。其實在做這一天內容前我沒有接觸過 Canvas,只好臨時抱佛腳趕快學一些基本的東西,還好還是做出來了...

完成作品:Fun with HTML5 Canvas程式碼

開始!

首先要先知道如何在 Canvas 畫出線條、更改樣式!
在 HTML 創建了一個 canvas tag 之後就可以把注意力轉移到 JS 了,首先先做一些基本設定

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;

設定監聽事件

由於我們要知道滑鼠當下位置的座標來當作劃線的起點,所以需要設定監聽事件來得知當按下滑鼠左鍵時的座標

// 記錄最後的座標
let lastX = 0;
let lastY = 0;

canvas.addEventListener('mousedown', function(e) {
    lastX = e.offsetX;
    lastY = e.offsetY;
});

規劃想法是記錄最後一點後每次都依 lastXlastY 的座標位置為畫線起點,而我希望當按下滑鼠 + 移動滑鼠時會開始畫線,所以要再設定一個監聽事件(mousemove)以及畫線的函式

canvas.addEventListener('mousemove', draw);

function draw(e) {
    // 開始畫線
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(e.x, e.y);
    ctx.stroke();
    
    // 紀錄最後座標
    lastX = e.x;
    lastY = e.y;
}

可以看到當滑鼠移動時 lastXlastY 是隨時在更新並劃出新的直線的,但畫面上看起來就像是真的在畫畫一樣。

接著要設定當滑鼠移動時,線條的粗細可以變大 > 變小 > 再變大的迴圈;同時不停的更改顏色

更改線條顏色

這裡介紹的方法是我之前沒有使用過的 hsl 調色方法,共有三個參數如下:
hsl(色相角度但不加單位0~360, 色彩飽和度0~100%, 色彩亮度0~100%)

為了隨時更改顏色,我們先將變數 hue 初始值設定為 0,並隨著滑鼠移動不停變更數字,直到 360 後歸零重算

let hue = 0;

function draw(e) {
    // 開始畫線
    ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
    
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(e.x, e.y);
    ctx.stroke();
    
    // 紀錄最後座標
    lastX = e.x;
    lastY = e.y;
    
    // 改變顏色
    if (hue >= 360) {
      hue = 0;
    } else if (hue > -1) {
      hue++;
    }
}

判別很簡單,當 hue 大於 360 後歸零,其餘狀況加 1,並記得改變線條顏色 ctx.strokeStyle = 'hsl(${hue}, 100%, 50%)'

更改線條粗細

類似於改變顏色,一開始會先給寬度初始值,但不同的是當到達一定程度時,希望寬度能隨著移動減少寬度而不是歸零,並在等於 0 時變成增加寬度

let width = 100;
let widthVelocity = 1;

function draw(e) {
    // 開始畫線
    ctx.lineWidth = width;
    ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(e.x, e.y);
    ctx.stroke();
    
    // 紀錄最後座標
    lastX = e.x;
    lastY = e.y;
    
    // 改變顏色
    if (hue >= 360) {
      hue = 0;
    } else if (hue > -1) {
      hue++;
    }
    
    // 改變粗細
    if (width <= 1 || width > 100) {
      widthVelocity = -widthVelocity;
    }
    width += widthVelocity;
}

這裡解釋一下,寬度一開始先設定 100,並期望寬度隨著每次移動而減少,所以變數 widthVelocity 就是在控制減少的變因。
當寬度加超過 100 時,將 widthVelocity 轉為 -1 就能做到反轉的效果,並隨著寬度減少至 1 時更改成 1,此時寬度變成增加了。

設定結束

現在可以作畫了,但卻無法結束啊!所以需要再設定監聽事件,當 mouseup 發生或是滑鼠移出畫面(mouseleave)時停止 draw() 的功能。

這裡的做法是設定變數 let isDrawing = false 來判定目前是否應該執行 draw() ,並在上述兩種狀況以外時(也就是按下按鍵時)將狀態改成 true

let isDrawing = false;

canvas.addEventListener('mousedown', function(e) {
    isDrawing = true;
    lastX = e.offsetX;
    lastY = e.offsetY;
});

canvas.addEventListener('mousemove', draw);

canvas.addEventListener('mouseup', function() {
    isDrawing = false;
});

canvas.addEventListener('mouseleave', function() {
    isDrawing = false;
});

最後,線條看起來其實不太圓滑,所以再改變一些屬性點綴一下:

ctx.lineCap = 'round';
ctx.lineJoin = 'round';

到這裡就大功告成了!太好了!

Reference


上一篇
JS30 Day 7 - Array Cardio Day 2
下一篇
JS30 Day 9 - Dev Tools Domination
系列文
一起挑戰 JavaScript 30 吧!30

尚未有邦友留言

立即登入留言