作品
畫版
畫板
規則
- 繪圖區請使用 Canvas 來設計,上方的控制列與下方的畫筆調整可不用
- SAVE :點擊後可直接下載轉出的 PNG 圖片
- CLEAR ALL:清除畫版樣式
- UNDO、REDO:上一步、下一步
- 點擊箭頭時,功能列介面皆可進行收闔
- 【擴充功能】請再自行增加「兩個功能」
規劃
- 了解 canvas 基礎運作模式
- 取得滑鼠當前座標接著執行以下動作後並繪製
- 設計上方功能列功能
- 設計下方工具列功能
- 設計功能列與工具列摺疊效果
- 設計額外功能
- 取得
input type="color"
數值,讓畫筆顏色有更多選擇
- 取得
input type="range"
數值,讓畫筆粗細可調整
- 取得視窗大小,讓畫版大小自動調整
- 繪製九宮格對照功能
Canvas
- 為網頁標籤之一,具有結束標籤
<canvas></canvas>
- 只有寬高屬性,而圖片多了 src 與 alt 屬性
- 原點
(0, 0)
在左上角,x 軸正數向右,y 軸正數向下
繪製方式
如同取用網頁元素一樣,先取得該元素 :
- 暫時設定 ID 名稱為 draw
document.getElementById('draw')
- 該元素其中一個方法為
getContext()
- 其繪製的圖形為點陣圖,MDN 建議直接使用內建寬高屬性而非利用 CSS 來設定寬高,否則可能會造成扭曲
接著,讓我們來畫個正方形,它可以幫我們了解原點與相對的位置。
1 2
| <canvas id="draw" class="canvas--border" width="300" height="300"></canvas>
|
1 2 3 4 5 6
| // 加上 border 比較容易知道位置 .canvas { &--border{ border: 1px black solid; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| let draw = document.getElementById('draw')
let ctx = draw.getContext('2d')
ctx.fillStyle = "rgba(0, 0, 200, 0.5)"
ctx.fillRect (250, 250, 50, 50)
ctx.clearRect(250, 250,25,25)
ctx.strokeRect(115,115,70,70)
|
我們再畫一條直線試試 :
1 2 3 4 5 6 7 8
| ctx.beginPath(); ctx.moveTo(150,150); ctx.lineTo(175,75); ctx.strokeStyle = '#FFA500' ctx.lineWidth = 10 ctx.lineCap = 'round' ctx.stroke()
|
現在我們知道原點與相對位置以及線條繪製方式,而且還知道可以設定顏色與線條粗細,那麼就可以利用滑鼠座標來畫畫了。
滑鼠座標
在瀏覽器中,有許多的監聽事件,滑鼠事件也是其中之一,還可以再細分成按下時、移動時以及放開時等等事件,首先,我們先來取得目前的滑鼠座標。
取得滑鼠座標
1 2 3 4 5 6 7
|
window.addEventListener('mousedown', (e)=> { console.log( `x 軸座標為 : ${e.offsetX},y 軸座標為 ${e.offsetY}` ) })
|
若要限定在畫版中才有動作,將對象 window 改為要監聽的網頁元素即可。
滑鼠連續事件
上面我們已經知道如何取得滑鼠座標,其實已經可以繪製連續的圖形了,建立以下事件 :
- 建立事件 mousedown,取得開始座標
- 建立事件 mousemove,取得移動座標
- 在此事件中執行繪製函式
- 將新的移動座標,作為開始座標
- 原本的開始座標,作為結束座標
- 不想建立太多暫存變數,自己將 x 與 y 座標放入一個陣列作為暫存座標
- 建立事件 mouseup,取消 mousemove 事件
上方功能列
undo、redo、clearAll
當我們繪製圖形時,每一筆都是一個新圖形,所以可以將圖形暫存下來像是這樣 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| const drawDisplay = document.querySelector('.js-draw');
let drawStorage = ['畫第一筆', '畫第二筆', '畫第三筆'] let base64 = ''
let step = -1
let ctx = drawDisplay.getContext('2d')
const canvas = () => { ctx.beginPath() ctx.stroke() base64 = drawDisplay.toDataURL() }
const mouseMove = () => { canvas() }
const mouseUp = () => { step++ if (step < drawStorage.length) { drawStorage.length = step } drawStorage.push(base64) }
const undo = () => { let lastDraw = new Image() if (step >= 0) { step-- lastDraw.src = drawStorage[step] ctx.beginPath(); ctx.clearRect(0,0, 畫版寬, 畫版高) lastDraw.onload = () => { ctx.drawImage(lastDraw, 0, 0) } } }
const redo = () => { step++ }
|
save
a 連結的屬性加入 download 並設定預設檔名,點擊時就能下載
1
| <a href="放入 base64 格式的圖檔" download="yourDraw"></a>
|
下方工具列
選擇畫筆顏色
單純將顏色填入也是可以,不過既然是畫版就想取得更多顏色,於是利用 input
的類型來取得顏色,利用函式將顏色回填至畫筆選擇區。
不過取得顏色時,遇到一個問題,就是這個類型利用 JS 取值時似乎只能取得 hex 格式,若利用 JS 寫 sass 格式的 darken ,是不會再次編譯的,也就無法取得相近色,因此暫時利用 hex 轉成 rgba 來取得相近顏色。
1
| <input type="color" value="#000000" class="js-colorInput">
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| const colorInput = document.querySelector('.js-colorInput')
const colorSelect = (e) => { colorsInit(e.target.value) }
const colorsInit = (color) => { newColors = [] let r = parseInt(color.substr(1,2), 16) let g = parseInt(color.substr(3,2), 16) let b = parseInt(color.substr(5,2), 16) let secondaryColor = `rgba(${r}, ${g}, ${b}, 0.75)` let thridColor = `rgba(${r}, ${g}, ${b}, 0.55)` let newArray = Array.from(colorBtns) newArray[2].style.backgroundColor = color newArray[3].style.backgroundColor = secondaryColor newArray[4].style.backgroundColor = thridColor newColors.push(color, secondaryColor , thridColor) }
|
擴充功能
九宮格
疊兩個圖層,一個為畫版,一個為已繪製九宮格畫版,這裡利用 position 來做,目標是讓畫版圖層保持在上方。
- 繪製四條直線,兩條橫,兩條直
- 分別設定為寬高之 0.33 與 0.66
- 設定兩個畫版背景色相同
- 當勾選下方工具列之九宮格選項時,讓畫版圖層變更為透明
自動調整畫版大小
在全域取得視窗寬高,再利用事件 “resize” 回寫畫版寬高。
- window.innerWidth ,視窗寬
- window.innerHeight,視窗高
- 利用 resize 事件回寫畫版寬高
DOM 與 Canvas
DOM 繪製圖形
直接操作網頁元素來繪製圖形,像是 CSS 與 SVG,
CSS :
1 2 3 4 5 6
| h1 { background-color: red; } ul { background-color: blue; }
|
SVG :
1 2 3 4
| <svg height="1000px" width="1000px"> <rect id="myRect" height="100px" width="100px" fill="blue"/> </svg>
|
它們直接對 DOM 做圖形渲染的效果,
- 佔用大量的記憶體空間
- 能繪製的圖形效果有限
- 相對的,修改效果時較為簡便
以下是一些實際運用例子 :
Canvas 繪製圖形
在 DOM 中只有一個元素,也就是 <canvas>
- 不佔用記憶體空間
- 能繪製許多圖形效果
- 相對的,修改時需要了解複雜的圖形方法
以下是一些實際運用例子 :
參考來源
- canvasJS
- MDN - Canvas 基本用途
- MaxLee - JS地下城[7F] - Canvas畫布
- lb01910483 - Day 14 - Canvas 圖片保存 Part 1
- drawImage()方法繪製圖片不顯示的問題
- Elisa Chang -【JavaScript】RGB 與 HEX 色碼轉換器實作
- HTML5 input type Color read single RGB values
- Kirupa - DOM vs. Canvas
- SVG vs canvas: how to choose