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

<<:  Python list 进阶

>>:  LeetCode解题 Day12

伸缩自如的Flask [day16] API

活在前後端分离的年代,我觉得後端重要的工作之一就是写出好用、好沟通的API。 可以先看一下HTTP ...

Day 16:108. Convert Sorted Array to Binary Search Tree

今日题目 题目连结:108. Convert Sorted Array to Binary Sear...

[Day 17] 资料产品生命周期管理-辅助决策

如同前面所说,资料模型需要运用到实际环境中才会发挥价值 Initiation 延续之前模型的初始条件...

离职倒数20天:我想要创造新的连结,让我可以不要在这条新的路上这麽无助

每年生日刚好是伊豆诸岛的旺季开始前一周,通常天气宜人,海水清澈到可以目视钓鱼,离东京只要搭船三小时,...

110/07 - 建立自己的 ResultContracts

前面讲完官方的14种Contracts,但我们也能建立属於自己的Contracts,以下范例是实作一...