iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0

08 - Fun with HTML5 Canvas

專案簡介

第八天的目標是在畫面上創造一塊畫布,畫布的功能是利用滑鼠點擊及拖曳畫出線條,線條需會變色及放大縮小

課程影片:JS30 08
導讀影片:Alex

初始文件

Github 檔案位置:08 - Fun with HTML5 Canvas

網頁一開始的樣子如下,就是白的

可以先去看看 最後的成品

正式製作

流程

將程式的要求拆分步驟後,我們需要做的事情如下

  1. 為 Canvas 元素加上滑鼠事件監聽
  2. 利用 JS 達成在 Canvas 畫布上繪圖
  3. 增加畫筆大小、顏色、形狀的變換

為 Canvas 元素加上滑鼠事件監聽

一樣用之前學到的東西加上監聽,再設個 isDrawing 確認是否在螢幕內按下時才會偵測到


const canvas = document.querySelector('#draw');
let isDrawing = false;

canvas.addEventListener('mousedown', function(e){
    console.log(e)
    isDrawing = true; 
})

canvas.addEventListener('mousemove', function(e){
    if(!isDrawing) return;
    console.log(e);
})

canvas.addEventListener('mouseup', () => isDrawing = false)
canvas.addEventListener('mouseout', () => isDrawing = false)

我們點擊看看

利用 JS 達成在 Canvas 畫布上繪圖

接下來要正式開始畫圖了,canvas 的直線畫圖方式是給起始點和線的終點,再藉由線連起來

由於我們在點擊時才會開始畫圖,可能會在畫布上任意位置開始,因此我們需先在觸發 mousedown 時紀錄 x, y 位置

let drawX = 0, drawY = 0;

canvas.addEventListener('mousedown', function(e){
    // console.log(e);
    isDrawing = true;  
    [drawX, drawY] = [e.offsetX, e.offsetY];
})

這邊依序介紹四句函式

  1. ctx.beginPath() 產生畫圖路徑(初始化)
  2. ctx.moveTo(x, y) 將畫筆移到目前位置(初始化)
  3. ctx.lineTo() 產生線條連接畫筆位置到目標位置(尚未畫)
  4. ctx.stroke() 畫實際的線段上去(預設為黑色)
  5. [drawX, drawY] = [e.offsetX, e.offsetY] 重新設定滑鼠所在的 (x, y)
canvas.addEventListener('mousemove', function(e){
    if(!isDrawing) return;
    // console.log(e);

    ctx.beginPath();
    ctx.moveTo(drawX, drawY);
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
    [drawX, drawY] = [e.offsetX, e.offsetY];
})

到這裡我們就可以在頁面上畫圖了

增加畫筆大小、顏色、形狀的變換

接下來我們要設定畫筆的各種屬性

一樣依序介紹四項屬性

  1. ctx.strokeStyle = '#BADA55'; 指定畫筆的顏色
  2. ctx.lineJoin = 'round'; 使線條的轉角為圓形
  3. ctx.lineCap = 'round'; 使畫筆的筆尖為圓形
  4. ctx.lineWidth = 50; 指定畫筆的粗細
ctx.strokeStyle = '#BADA55'; 
ctx.lineJoin = 'round'; // 轉角為圓形
ctx.lineCap = 'round'; // 畫筆為圓形
ctx.lineWidth = 50;

我們就可以看到畫筆被賦上的屬性帶來的影響

接下來我們希望畫筆有更多的特效,所以利用簡單的方式讓畫筆放大縮小再放大,並且會隨著 hsl 色盤而變換顏色

let lineWidth = -100;
let colorDeg = 0;

canvas.addEventListener('mousemove', function(e){
    if(!isDrawing) return;
    // console.log(e);
    
    ctx.lineWidth = Math.abs(lineWidth);
    ctx.strokeStyle = `hsl(${colorDeg}, 100%, 50%)`;
    
    ctx.beginPath();
    ctx.moveTo(drawX, drawY);
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
    [drawX, drawY] = [e.offsetX, e.offsetY];

    lineWidth < 100 ? lineWidth += 1.5 : lineWidth = -100;
    colorDeg < 360 ? colorDeg += 1 : colorDeg = 0;
})

最後程式碼

const canvas = document.querySelector('#draw');
const ctx = canvas.getContext('2d');
ctx.strokeStyle = '#BADA55'; 
ctx.lineJoin = 'round'; // 轉角為圓形
ctx.lineCap = 'round'; // 畫筆為圓形

let isDrawing = false;
let drawX = 0;
let drawY = 0;
let lineWidth = -100;
let colorDeg = 0;

canvas.addEventListener('mousedown', function(e){
    // console.log(e);
    isDrawing = true;  
    [drawX, drawY] = [e.offsetX, e.offsetY];
})

canvas.addEventListener('mousemove', function(e){
    if(!isDrawing) return;
    // console.log(e);

    ctx.lineWidth = Math.abs(lineWidth);
    ctx.strokeStyle = `hsl(${colorDeg}, 100%, 50%)`;

    ctx.beginPath();
    ctx.moveTo(drawX, drawY);
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
    [drawX, drawY] = [e.offsetX, e.offsetY];

    lineWidth < 100 ? lineWidth += 1.5 : lineWidth = -100;
    colorDeg < 360 ? colorDeg += 1 : colorDeg = 0;
})

canvas.addEventListener('mouseup', () => isDrawing = false)
canvas.addEventListener('mouseout', () => isDrawing = false)

完成結果圖

最後的成品

結語

以上是第八天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<

Let's build something fun with HTML5 Canvas - #JavaScript30 8/30
[ Alex 宅幹嘛 ] 深入淺出 Javascript30 快速導覽 | Day 8:Fun with HTML5 Canvas
MDN Web Docs


上一篇
JS30 -> 07 - Array Cardio Day 2
下一篇
JS30 -> 09 - Dev Tools Domination
系列文
剛接觸前端一個月的小白 - JavaScript30 挑戰筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言