---
title: "【JavaScript】JS地下城-7F-畫版"
description: "這次是我第一次使用BootStrap，之前從來都沒有用過，所以一開始查了蠻多資料了，也不知道用的方法正不正確，不過官方文檔寫得很棒所以其實上手並不難。Canvas API的部分，最基礎的畫畫功能其實很簡單，參考Google到的文章，很快就可以寫出最基本的東西，之後加上去的功能...花的時間比較多。"
canonical_url: "https://hannoeru.me/posts/javascript-dungeon-7f-paint-board"
---

> Index of every page on this site: [llms.txt](https://hannoeru.me/llms.txt)

## 7F-畫版

![wp-image-361](https://hannoeru.me/images/2019/05/screenshot-2019-05-30-17.48.18.png)

### 連結

[Demo](https://gh.hannoeru.me/canvas-panel/)

[Code](https://github.com/hannoeru/canvas-panel)

### 使用語言

HTML、CSS、Bootstrap、JavaScript（ES6）、Canvas API

### BOSS 弱點

1. 【特定技術】遊戲規則

  1. 繪圖區請使用 Canvas 來設計，上方的控制列與下方的畫筆調整可不用
  2. SAVE ：點擊後可直接下載轉出的 PNG 圖片
  3. CLEAR ALL：清除畫版樣式
  4. UNDO、REDO：上一步、下一步
  5. 點擊箭頭時，功能列介面皆可進行收闔
2. 【擴充功能】請再自行增加「兩個功能」，我相信勇者們都是很有梗的~

### 擴充功能

- 支援手機操作
- 支援手機版型
- 橡皮擦

### 心得

這次是我第一次使用 Bootstrap，之前從來都沒有用過，所以一開始查了蠻多資料了，也不知道用的方法正不正確，不過官方文檔寫得很棒所以其實上手並不難。

Canvas API 的部分，最基礎的畫畫功能其實很簡單，參考 Google<br />


到的文章，很快就可以寫出最基本的東西，之後加上去的功能…花的時間比較多。

點一下畫筆可以切換橡皮擦跟畫筆，橡皮擦是用背景顏色去做的。

之前從來沒有寫過 CSS 的動畫，所以一開始也是去翻文檔，這部分卡了比較久一點，版型我花了超久才弄好…

### 功能

#### SAVE

生成一個 Element 把該填的資料填進去，之後再用 `click()` 觸發。

```js
const link = document.createElement('a')
link.href = canvas.toDataURL()
link.download = 'canvas.png'
link.click()
```

#### CLEAR ALL

用 `clearRect()` 指定範圍清空。

```js
ctx.clearRect(0, 0, canvas.width, canvas.height)
```

#### UNDO & REDO

參考資料：[連結](https://qiita.com/ampersand/items/69c8d632ed9f60358418)

做法是用兩個陣列 `undoDataStack[]` 跟 `redoDataStack[]` 儲存 UNDO & REDO 的<br />

`ctx.getImageData()` 資料。

還有一個選項是 `STACK_MAX_SIZE` 可以設定最高紀錄多少步驟，防止瀏覽器效能不足。

控制 `.disable` 在沒有下一步時關閉按鈕。

```js
const STACK_MAX_SIZE = 30
const undoDataStack = []
let redoDataStack = []
const saveDraw = () => {
  redoDataStack = []
  document.querySelector('.nav-redo').classList.add('disable')
  if (undoDataStack.length >= STACK_MAX_SIZE) { undoDataStack.pop() }

  undoDataStack.unshift(ctx.getImageData(0, 0, canvas.width, canvas.height))
  document.querySelector('.nav-undo').classList.remove('disable')
}
const undo = () => {
  if (undoDataStack.length <= 0) return
  redoDataStack.unshift(ctx.getImageData(0, 0, canvas.width, canvas.height))
  document.querySelector('.nav-redo').classList.remove('disable')
  const imageData = undoDataStack.shift()
  ctx.putImageData(imageData, 0, 0)
  if (undoDataStack.length <= 0) { document.querySelector('.nav-undo').classList.add('disable') }

}
const redo = () => {
  if (redoDataStack.length <= 0) return
  undoDataStack.unshift(ctx.getImageData(0, 0, canvas.width, canvas.height))
  document.querySelector('.nav-undo').classList.remove('disable')
  const imageData = redoDataStack.shift()
  ctx.putImageData(imageData, 0, 0)
  if (redoDataStack.length <= 0) { document.querySelector('.nav-redo').classList.add('disable') }

}
```

#### 手機版操作

觸控螢幕監聽事件

```js
canvas.addEventListener('touchstart', touchStart) // mousedown
canvas.addEventListener('touchmove', touchMove) // mousemove
canvas.addEventListener('touchend', touchEnd) // mouseup
```

### 參考資料

[Canvas APIの基礎](https://www.atmarkit.co.jp/ait/articles/1208/01/news151.html)

[Bootstrap - Document]<span>

3

</span>



[HTML5 Canvas 簡易手繪板]<span>

4

</span>



[Canvas 教學文件- Web APIs | MDN]<span>

5

</span>



[canvasを画像としてダウンロードさせたかった話]<span>

6

</span>



[Canvasで元に戻す（Undo），やり直し（Redo）を実装する方法](https://qiita.com/ampersand/items/69c8d632ed9f60358418)

[Webデザインの知識がなくてもOK！Bootstrapの使い方【入門者向け】]<span>

7

</span>



<span>

3

</span>

: [https://getbootstrap.com/docs/4.3/getting-started/introduction/](https://getbootstrap.com/docs/4.3/getting-started/introduction/) # 當時使用 Bootstrap 4.3，目前最新版為 5.x<br />

<span>

4

</span>

: [https://developer.mozilla.org/zh-TW/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes](https://developer.mozilla.org/zh-TW/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes)<br />

<span>

5

</span>

: [https://developer.mozilla.org/zh-TW/docs/Web/API/Canvas_API/Tutorial](https://developer.mozilla.org/zh-TW/docs/Web/API/Canvas_API/Tutorial)<br />

<span>

6

</span>

: [https://qiita.com/iwaimagic/items/1d16a721b36f04e91aed](https://qiita.com/iwaimagic/items/1d16a721b36f04e91aed)<br />

<span>

7

</span>

: [https://techacademy.jp/magazine/6270](https://techacademy.jp/magazine/6270)

## Sitemap

See the full [sitemap](https://hannoeru.me/sitemap.md) for all pages.
