昨天分享了許多監聽的方法,今天就利用這些技能來完成一個畫版。大家還記得昨天的文章最後有問到實作畫版可能會用到幾種監聽?你們覺得呢?其實這次的實作我總共用到了「五種」監聽方法完成下方這個畫版,附上還沒紅的名作 《The Lady Bug》!!!歡迎大家也來玩玩看,截圖跟我分享你的巨作,立刻點我去畫畫

畫版主要可以分為 ToolBox 和 Board 兩個元件,ToolBox 用來控制畫線的顏色與畫筆的粗度,分別對應到 canvas 就是 stroke style 以及 linewidth,我們監聽表單的 Change,選好後可以直接把值 set 給 canvas,這樣 canvas 就會拿到我們設定的畫線樣式囉!
除了畫線之外也別忘了給他清空的功能,清空就相對簡單很多,給清空的按鈕監聽 Click,然後使用 cleanRect (),就可以讓 Canvas 完全被清空。
接著是畫版的部分,畫版主要功能就是畫線,畫線得整個這個行為可以拆分成「點擊下去 mousedown、長按 mousemove、放開點擊 mouseup 」,我們在點擊的時候去抓點擊起始的位置,持續移動滑鼠鼠標的時候呼叫繪圖函式,放掉滑鼠時結束繪畫,加上 ctx.stroke() ctx.beginPath() 的函示把圖完成。

完成五個監聽後,我們來看看繪圖函式做了什麼。先給畫筆設定樣式,然後使用 lineTo() 繪製線條,點的位置是透過與瀏覽器和 Canvas 邊界的距離而定,確認後再以 stroke() 繪製。這樣就能做出看起來很難但實際上很簡單的畫版。

整個繪圖板只有繪圖的區域是用 Canvas Tag,先附上好懂的 html :
// html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>網頁互動繪圖板</title>
</head>
<body>
<section class="container">
<div id="toolbox">
<h1>ToolBox</h1>
<label for="stroke">Color</label>
<input id="stroke" name='stroke' type="color">
<label for="lineWidth">Pen Width</label>
<input id="lineWidth" name='lineWidth' type="number" value="3">
<button id="clear">Clear Board</button>
</div>
<div class="drawing-board">
<canvas id="drawing-board"></canvas>
</div>
</section>
<script src="./index.js"></script>
</body>
</html>
以及 JavaScript 的程式碼:
// JavaScript
const board = document.getElementById("drawing-board");
const toolbox = document.getElementById("toolbox");
const ctx = board.getContext("2d");
const canvasOffsetX = board.offsetLeft;
const canvasOffsetY = board.offsetTop;
board.width = window.innerWidth - canvasOffsetX;
board.height = window.innerHeight - canvasOffsetY;
let isPainting = false;
let lineWidth = 3;
let penXLocation = 0;
let penYLocation = 0;
toolbox.addEventListener("click", (e) => {
if (e.target.id === "clear") {
ctx.clearRect(0, 0, board.width, board.height);
}
});
toolbox.addEventListener("change", (e) => {
if (e.target.id === "stroke") {
ctx.strokeStyle = e.target.value;
}
if (e.target.id === "lineWidth") {
lineWidth = e.target.value;
}
});
const draw = (e) => {
if (!isPainting) {
return;
}
ctx.lineWidth = lineWidth;
ctx.lineCap = "round";
ctx.lineTo(e.clientX - canvasOffsetX, e.clientY);
ctx.stroke();
};
board.addEventListener("mousedown", (e) => {
isPainting = true;
penXLocation = e.clientX;
penYLocation = e.clientY;
});
board.addEventListener("mouseup", (e) => {
isPainting = false;
ctx.stroke();
ctx.beginPath();
});
board.addEventListener("mousemove", draw);
以上就是今天的畫版實作,畫版有很多可能性,可以拿來當溝通、發想的產品基礎,也能給小朋友畫畫,或是做成傳情畫意的遊戲(有種史萊姆好玩遊戲區的味道),希望大家喜歡今天的 Canvas 監聽實作分享~非常歡迎畫畫留言給我 <3
嗨嗨謝謝你的教學~
發現不用CODEPEN的話
ctx.lineTo(e.clientX - canvasOffsetX, e.clientY);
改成
ctx.lineTo(e.clientX - canvasOffsetX, e.clientY - canvasOffsetY);
才不會造成偏移
雖然我還不太清楚原因xD