iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 12
2
Modern Web

Fabricjs 筆記系列 第 12

Day 12 -利用序列化與反序列化來實作存檔功能及還原功能

  • 分享至 

  • xImage
  •  

昨天提到利用序列化來將 canvas 變成 json 的格式,今天就來介紹如何把 JSON 格式變回畫布繼續讓使用者使用,今天介紹完反序列化後,就接著來實作序列化和反序列實際的應用。

今天主要大綱

  • 反序列化介紹 - loadFromJSON、loadSVGFromURL、loadSVGFromString
  • 存檔讀取功能實作
  • 還原功能實作

反序列化 Deserialize

三種反序列化的方式

  1. loadFromJSON - 讀取 JSON 到 canvas 中
  2. loadSVGFromURL - 使用 URL 讀取 SVG
  3. loadSVGFromString - 使用 svg path 來讀取
    以上 1 為在 fabric.Canvas 之下的唯一方法。
    2 3 為在 fabric 底下的靜態方法。

loadFromJSON

這個方法很簡單就和它字面意思一樣,我們只要使用 loadFromJSON 就能將我們昨天序列化出來的 json 給匯入進去了。

const save = '{"version":"2.4.1","objects":[{"type":"rect","version":"2.4.1","originX":"left","originY":"top","left":0,"top":0,"width":100,"height":100,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"name":"Nono"}],"background":"#222"}'
const canvas = new fabric.Canvas('canvas')
canvas.loadFromJSON(save)

讀取 SVG

loadSVGFromString

可以直接讀取 svg string

<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>

這邊使用 fabric.loadSVGFromString 來讀取 SVG,後面第二個參數 callback 回傳路徑的物件,因為 svg 可以由很多的封閉的物件所組成,這邊我們還要使用 fabric.util.groupSVGElements(objects, options) 來將所有物件群組起來,才不會散散。

fabric.loadSVGFromString(SVGString, (objects, options) => {
  const obj = fabric.util.groupSVGElements(objects, options)
  canvas.add(obj).renderAll()
})

loadSVGFromURL

這個 method 有跨網域限制,所以無法直接使用其他網域的 svg 檔案。
使用方法和 loadSVGFromURL 只差在第一個參數是帶入 URL。

實作練習

存檔以及讀檔

這邊我們簡單實作存檔和讀檔的功能

  1. 建立存檔函數
    這邊很簡單就只要將 JSON.stringify(canvas) 存在變數裡就行了。
function save () {
  saveJSON = JSON.stringify(canvas)
  alert('save canvas!')
  textarea.innerHTML = saveJSON
}
  1. 建立讀取函數
    這邊也很簡單這要將我們儲存的 saveJSON 函數,透過 canvas.loadFromJSON 讀取出來就可以了~
function load () {
  alert('load canvas!')
  textarea.innerHTML = ''
  canvas.loadFromJSON(saveJSON)
}
  1. 最後在綁定事件在按鈕上
saveBtn.addEventListener('click', save)
loadBtn.addEventListener('click', load)

我們就很輕鬆地做出存檔讀取的功能啦!

結果

如果只儲存在前端使用者重開存檔的資料就會不見囉。

一般來說,這邊我們會配合後端 API,在 save 時,透過 api 將資料儲存至後端,而在 load 時去從後端讀取資料。

完成程式 - https://codepen.io/nono1526/pen/OBdJye

上一步、下一步功能實作

再來我們要利用存檔、讀檔功能,配合 canvas 的 'object:modified' 事件,來做更進階的上一步和下一步功能。

先做上一步功能

  1. 建立一個 state 變數方便我們隨時儲存目前的狀態。
  2. 建立 undo 為陣列型態,方便我們儲存之前做過的狀態。
// 目前狀態
let state = canvas.toJSON()
// 儲存之前的步驟
const undo = []
  1. 設定 canvas object:modified 事件,每當物件狀態有被更新時,這時我們的 state 變數會還在更新前的狀態,我們要把這個狀態利用 push 儲存到 undo 陣列中,最後在更新狀態。
// 此事件為物件被修改後觸發
canvas.on('object:modified', e => {
  // 把之前的狀態儲存
  undo.push(state)
  // 更新狀態
  state = JSON.stringify(canvas)
  // 修改後不會有下一步儲存,故 下一步 陣列清空
  redo.length = 0

})

  1. 建立 doUndo 函數,綁在按鈕上
  2. doUndo 首先要判斷若 undo 是空的我們就不做任何事情。
  3. 利用 Array.pop() 函數把最後一筆的存檔資料取出,再把 state 換成上一步的狀態。
。
function doUndo () {
  if (undo.length) {
    alert('目前沒有動作可復原')
    return
  }
  // 取出 undo 最後一筆資料讀取
  let lastJSON = undo.pop()
  canvas.loadFromJSON(lastJSON)
  // 換成上一步的狀態
  state = lastJSON
}
undoBtn.addEventListener('click', doUndo)

到這邊我們已經簡單的完成 上一步 的功能啦!

接下來我們來做 下一步 功能

  1. 先看看我們之前做的 doUndo 功能,這邊為了做下一步功能,我們在更新狀態前,要先把目前狀態儲存到 redo 陣列。
function doUndo () {
  ...略
  // 在做上一步時把目前狀態 push 到 redo 陣列
  redo.push(state)
  // 換成目前的狀態
  state = lastJSON
}
  1. 建立 doRedo 函數,其實就和 doRedo 原理都差不多。
function doRedo () {
  if (!redo.length) {
    alert('目前沒有動作可復原')
    return
  }
  let lastJSON = redo.pop()
  canvas.loadFromJSON(lastJSON)
  // 在做下一步時把目前
狀態 push 到 undo 陣列
  undo.push(state)
  // 換成目前的狀態
  state = lastJSON
}
redoBtn.addEventListener('click', doRedo)

結果

本日小結


上一篇
Day 11 - Fabricjs 把畫布序列化
下一篇
Day 13 - 把物件群組起來
系列文
Fabricjs 筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
williamyeh
iT邦新手 5 級 ‧ 2018-12-05 12:24:22

存擋 --> 檔

Nono iT邦新手 5 級 ‧ 2018-12-05 14:20:59 檢舉

/images/emoticon/emoticon13.gif改了謝謝

0
advancedor96
iT邦新手 5 級 ‧ 2018-12-05 14:31:14

██████████████████████████████████████
高雄卡訊電子 徵才 | UI 設計師  
██████████████████████████████████████

哈囉,我們是高雄的卡訊電子,做麥克風、會議系統的。目前需要一位設計師來協助產品的UI介面設計。

【工作內容】
與前端工程師協作,開發 web 操作介面。

1.基本條件

有美感,會做UI,願意溝通討論,履歷記得附上作品集。

2.公司提供 Adobe CC、Axure、雙 24” 繪圖螢幕、Wacom Intuos Pro 繪圖板.

【月薪區間】
3萬~4萬5

訪問前設計師對這份工作的想法:

【優點】
與他合作的工程師有一些 sense
只要在 Design guideline 下大致上是開放的
只要能說服老闆,設計是會被採用的。(老闆不會直接跟你說no)

【缺點】
對設計師來說這裡的產品比較不多元,都是操作介面

詳細徵才資訊:https://www.104.com.tw/job/?jobno=5buv5
104 上官方列的基本條件,沒有很重要:

  • 熟悉 Web App UI/UX
  • 熟悉各式常見 Design Guidelines
  • 熟悉使用 UI Flow、Wireframe、Mockup 等文件來和工程師討論
  • 熟悉 Photoshop、Illustrator、XD 等工具
  • 能獨立作業

真正重要的是上面第1點,只要有美感,會做UI,可以溝通即可。

Nono iT邦新手 5 級 ‧ 2018-12-05 17:28:18 檢舉

安捏姆湯喔

我要留言

立即登入留言