觀察 index-Start.html,嗯...很乾淨就只有一個 canvas 元素
Canvas 元素是什麼,如英文單字字面上意思「畫布」透過 Javascript Canvas API 操作繪製產生畫面,兩者缺一不可,Canvas 應用非常廣泛,可用於網頁遊戲、動畫、地圖繪製、檔案電子簽名,可以說是你想的到的,canvas 都做得出來,前端知名設計軟體Figma底層也是使用 Canvas。還有另一個 Web API 也搭配 canvas 元素使用,那就是:WebGL API。這邊簡潔整理兩者差異:Canvas 著重 2D 畫面,若要進行 3D 設計則使用 WebGL API。
<canvas id="draw" width="800" height="800"></canvas>
ctx
中,接下來我們的任何操作都是使用ctx
操作2D stroke() method了。const canvas = document.querySelector("#draw");
const ctx = canvas.getContext("2d");
//清除上次路徑
ctx.beginPath();
//設定線頭 ctx.moveTo(X座標,Y座標)
ctx.moveTo(0, 0);
//設定線尾 ctx.lineTo(X座標,Y座標)
ctx.lineTo(100, 100);
// 繪製至cnavas上顯示
ctx.stroke();
MouseEvent {
clientX: 77,
clientY: 127,
}
那我們何不每次記住上次事件的 X、Y 值當作線頭,這次觸發事件的 X、Y 值當作線尾持續畫線呢?
function drawLine(ctx, pastX, pastY, currentX, currentY) {
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.moveTo(pastX, pastY);
ctx.lineTo(currentX, currentY);
ctx.stroke();
}
X
、Y
變數拿來儲存上次觸發滑鼠滑動的事件,以及isDrawing
變數來判定要不要畫線,因為需求是滑鼠按著狀態下的滑動才會出現線條,可以想像成 true = 打該筆蓋/false = 蓋上筆蓋。let isDrawing = false;
let x;
let y;
// 當滑鼠按下,賦值當前坐標進X、Y,切換成isDrawing5狀態成true(打開筆蓋)
canvas.addEventListener("mousedown", (e) => {
isDrawing = true;
x = e.clientX;
y = e.clientY;
});
// 當滑鼠滑動,判斷是否繪畫,如果true 執行畫線函式後,再將這次事件座標賦改進X、Y值
canvas.addEventListener("mousemove", (e) => {
if (isDrawing) {
drawLine(ctx, x, y, e.clientX, e.clientY);
x = e.clientX;
y = e.clientY;
}
});
//如果滑鼠彈起或滑鼠離開畫布,則切換isDrawing5狀態成false(蓋上筆蓋)
canvas.addEventListener("mouseup", (e) => (isDrawing = false));
canvas.addEventListener("mouseleave", (e) => (isDrawing = false));
//全域宣告線條粗度變數供遞增遞減
let lineWidth = 0;
//全域宣告hsv色相變數供遞增遞減
let color = 0;
function drawLine(ctx, pastX, pastY, currentX, currentY) {
ctx.beginPath();
//線條頭尾補上半圓形
ctx.lineCap = "round";
//hsv色相 0~360 來回遞增遞減達成彩虹效果
if (color === 0) colorDistance = 3;
if (color === 360) colorDistance = -3;
color += colorDistance;
//筆畫粗細 0~100 來回遞增遞減
if (lineWidth === 0) distance = 1;
if (lineWidth === 100) distance = -1;
lineWidth += distance;
ctx.strokeStyle = `hsl(${color},100%,50%)`;
ctx.lineWidth = lineWidth;
ctx.moveTo(pastX, pastY);
ctx.lineTo(currentX, currentY);
ctx.stroke();
}