這次的練習會運用到 HTML Canvas Graphics。
今天我想自己練習來作一個超級簡易版小畫家,效果包含:
- 顏色
- 筆刷粗細
- 橡皮擦
- 放上貼圖(構想)
HTML Canvas
HTML Canvas 會提供一個畫布空間,需要使用到JavaScript來作畫。
如何使用?
Canvas為一個正方形的區塊,預設就是空白的、沒有border。
HTML:
<canvas id="myCanvas" width="200" height="100"></canvas>
JavaScript:
取得 Canvas 的渲染環境及其繪圖函數
const canvas = document.querySelector('#myCanvas');
const ctx = canvas.getContext('2d');
設定 Canvas滿版
但放上去後發現就算更改的寬度和長度,還是無法讓畫布滿版、自適應整個螢幕。
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
基本content樣式設定
前面提到 canvas 就是一個空白的畫布,填上東西靠的是content。
通常會宣告為ctx
。
我們可以先對ctx
最一些基礎的設定(例如: 筆刷大小/ 顏色等)
ctx.strokeStyle = '#bada55'; // 筆觸顏色
ctx.lineJoin = 'round'; // 兩條線交匯處產生 "圓形" 邊角
ctx.lineCap = 'round'; // 筆觸預設為 "圓形"
ctx.lineWidth = 1; // 筆頭寬度
let isDrawing = false; // 是否 mousedown下筆狀態
/* 起點座標 */
let lastX = 0;
let lastY = 0;
- 管理狀態:save(), restore()
- 變形:scale(), rotate(), translate(), transform(), setTransform()
- 畫面組成:globalAlpha, globalCompositionOperation
- 色彩與風格: strokeStyle,fillStyle,createLinearGradient(),createRadialGradient(), createPattern()
- 線條邊角及組合:lineWidth, lineCap, lineJoin, miterLimit
- 陰影:shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor
- 方形繪出:clearRect(), fillRect(), strokeRect()
- 路徑API:beginPath(), closePath(), moveTo(), lineTo(), quadraticCurveTo(), bezierCurveTo(), arcTo(), rect(), arc(), fill(), stroke(), clip(), isPointInPath()
- 焦點管理:drawFocusRing()
- 文字:font, textAlien, textBaseline, fillText(), strokeText(), measureText()
- 影像:drawImage(), createImageData(), getImageData(), putImageData()
繪圖函數與下筆(mousedown)監聽
重點:
- 監聽: 只有在 mousedown 時才會畫圖,mouseup & mouseout 不會。
- 要試訂下筆起始點,不然起始點的預設是左上角的(0,0),按照預設的話會從左上角連到下筆的位置。
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY]; // 設定起始點
});
canvas.addEventListener('mousemove', draw);
// 繪製函數;在 mousemove 的時候使用
function draw(e) {
if(!isDrawing) return; // 沒有允許繪製即退出
/* 繪製路線 Setting */
ctx.beginPath(); // 產生一個新路徑,產生後再使用繪圖指令來設定路徑。
ctx.moveTo(lastX, lastY); // 設定起點
ctx.lineTo(e.offsetX, e.offsetY); // 設定終點
ctx.stroke(); // 依照設定開始繪製
[lastX, lastY] = [e.offsetX, e.offsetY]; // 位置更新
//當目前路徑為空(例如接著呼叫beginPath()完後)或是在一個新畫布上,不論為何,第一個路徑繪圖指令總是moveTo();因為每當重設路徑後,你幾乎都會需要設定繪圖起始點。
功能: 顏色
顏色使用 input type="color"
去監聽它的改變在動態寫入value
功能: 粗細
粗細的部分我已經寫好固定提供五個大小
五個圈圈搭被dataset,利用forEach 去監聽每個圈圈是否被點擊,點擊後動態寫入數值。