這次要挑戰的是比小畫家還陽春的繪圖app,會利用到canvas api,請看倌直接到CodePen裡試試看。
實作邏輯
html
<canvas id="canvas"></canvas>
<div class="toolbox">
<button id="decrease">-</button>
<span id="size">10</span>
<button id="increase">+</button>
<input type="color" id="color">
<button id="clear">X</button>
</div>
CSS(節錄)
canvas {
border: 2px solid steelblue;
width: 70vw;
height: 700px
}
.toolbox {
background-color: steelblue;
border: 1px solid slateblue;
display: flex;
width: 70vw;
height: 700px
padding: 1rem;
}
/* 指定.toolbox內的所有元素 */
.toolbox > * {
background-color: #fff;
border: none;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 2rem;
height: 50px;
width: 50px;
margin: 0.5rem;
padding: 0.25rem;
cursor: pointer;
}
/* 將最後一個元素推到最左側 */
.toolbox > *:last-child {
margin-left: auto;
}
Javascript
const canvas = document.getElementById('canvas');
const increaseBtn = document.getElementById('increase');
const decreaseBtn = document.getElementById('decrease');
const sizeEL = document.getElementById('size');
const colorEl = document.getElementById('color');
const clearEl = document.getElementById('clear');
// 取得二維繪圖板
const ctx = canvas.getContext('2d');
let size = 10
let isPressed = false
colorEl.value = 'black'
let color = colorEl.value
let x
let y
// 滑鼠按下點擊的時候,取得x與y的定位
canvas.addEventListener('mousedown', (e) => {
isPressed = true
x = e.offsetX
y = e.offsetY
})
// 滑鼠離開的時候就取消x與y的定位
document.addEventListener('mouseup', (e) => {
isPressed = false
x = undefined
y = undefined
})
// 滑鼠點擊且移動的時候,表示正在進行繪圖行為
canvas.addEventListener('mousemove', (e) => {
if(isPressed) {
// 取得最新的定位點x2與y2
const x2 = e.offsetX
const y2 = e.offsetY
// 先完成一維的圓點
drawCircle(x2, y2)
// 若滑鼠有位移動作,繪製二維線條
drawLine(x, y, x2, y2)
// 完成繪圖後,將x與y賦值一開始取得的定位點(隨著位移不斷更新)
x = x2
y = y2
}
})
// 運用canvas api產生圓點
function drawCircle(x, y) {
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2)
ctx.fillStyle = color
ctx.fill()
}
// 運用canvas api產生線條
function drawLine(x1, y1, x2, y2) {
ctx.beginPath()
ctx.moveTo(x1, y1)
ctx.lineTo(x2, y2)
ctx.strokeStyle = color
// 因為是二維關係,size要以平方值來計算才行
ctx.lineWidth = size * 2
ctx.stroke()
}
// 更新sizeEl的size
function updateSizeOnScreen() {
sizeEL.innerText = size
}
// 將+按鈕掛載監聽器,控制size數值
increaseBtn.addEventListener('click', () => {
size += 5
if(size > 50) {
size = 50
}
// 做為參數引入函式中
updateSizeOnScreen()
})
// 將 - 按鈕掛載監聽器,控制size數值
decreaseBtn.addEventListener('click', () => {
size -= 5
if(size < 5) {
size = 5
}
updateSizeOnScreen()
})
// 透過html5提供的<input>選色模板,來控制變數color的值
colorEl.addEventListener('change', (e) => color = e.target.value)
// 將X按鈕掛上監聽器,帶入canvas api所提供的清除指令,將繪圖板清空
clearEl.addEventListener('click', () => ctx.clearRect(0,0, canvas.width, canvas.height))