iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0
Modern Web

30天30個前端任務系列 第 12

#12. Drawing App(原生JS版)

#12. Drawing App

這次要挑戰的是比小畫家還陽春的繪圖app,會利用到canvas api,請看倌直接到CodePen裡試試看。

實作邏輯

  1. 先切好UI部分
  2. 透過canvas api實作出函式,先有一個點,再來處理線條部分
  3. 上述函式會接受一些參數,比如畫筆尺寸、顏色等等,這些就另外設定按鈕,掛上監聽器來修改參數值。

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))

上一篇
#11. Color theme switcher + Clock(原生JS版)
下一篇
#13. Split Landing Page(原生JS版), #14. RGB to Hex Converter(原生JS版)
系列文
30天30個前端任務19

尚未有邦友留言

立即登入留言