iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 11
2
Modern Web

Fabricjs 筆記系列 第 11

Day 11 - Fabricjs 把畫布序列化

  • 分享至 

  • xImage
  •  

今天我們要來了解 Fabricjs 的序列化功能。一般我們會在什麼情境下用到這個功能呢?
就是存檔讀檔啦!

使用者若有存取和讀取自己所設計的圖片的需求,我們會利用將 canvas 中的內容整個序列化,變成 json 的格式,當使用者想再次修改時,就從後端把之前做過序列化的資料讀取出來,被且再透過 fabricjs 的解析,又變成一個能夠自由修改的畫布啦!。

另外 fabricjs 還提供了 canvas 轉成 svg path 的序列化,也相當的實用。

今天就主要介紹幾種序列化的方法

  1. toJSON 轉成 json 格式
  2. toObject 轉成物件格式
  3. toSVG 轉成 svg path

轉成 json 格式

我們能夠輕鬆地將 canvas 序列化成 json 的格式,這邊有兩種方式。

  • JSON.stringify(canvas) - 直接將 canvas 序列化
  • canvas.toJSON() - 使用 fabicjs.Canvas 提供的方法

toJSON() 方法也是回傳 javascript 物件,所以必須要使用 JSON.stringify(canvas.toJSON) 才能拿到 json 字串呦!

JSON.stringify(canvas)

我們先什麼都不做直接將 canvas 給序列化

const canvas = new fabric.Canvas('canvas')
console.log(JSON.stringify(canvas))

我們知道其實 JSON 格式就是 javascript 的物件變成用字串的方式組合。

這邊把序列化後的資料透過 console 出來後,我的得到了 fabricjs 的版本以及一個空的 objects 陣列:

{"version":"2.4.1","objects":[]}

因為我們什麼都還沒有加入,所以我們可以猜測 objects 這個物件會放之後 add 進 canvas 裏頭的物件。

在來加入背景顏色和一個矩形後再來序列化

{"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}],"background":"#222"}

哇!我們不過加入了一個矩形而已,資料竟然就暴增了這麼多,不過 objects 物件確實就是裝著被我們 add 進 canvas 中的 rect 物件。

這邊可以看到我有用粗體標記的部分

"type":"rect"

裝在 objects 中,也就是我們新增出來的矩形。

"background:"#222"

這個就是我們幫 canvas 上的背景顏色,也被儲存了起來。

toObject & toJSON

  • toObject 回傳 javascript object
  • toJSON 回傳 json

toJSON 不會直接回傳 json string,必須要自己使用 JSON.stringiy()
不過我自己嘗試了以後發現,toObject 和 toJSON 都回傳了 javascript Object

console.log(canvas.toObject())
console.log(canvas.toJSON())

得到

後來在 fabric 原始碼發現

所以其實是一樣的?

好吧~那這邊主要就來用講解一下 toObject

toObject

其實不只 canvas 可以呼叫 toObject,其實在 fabric.Object 也有 toObject 方法,而 canvas 的 toObject 就是把所有底下的物件都呼叫 toObject 並且儲存起來到序列化中的 objects 物件之下。

這邊我們可以做個實驗。

我們偷偷修改 recttoObject 的方法。並在一次做序列化,來查看資料是否有變。

// 偷偷增加在 rect 中變更 toObject 方法
rect.toObject = function () {
  return {
    custom: true,
    sayHi: 'Halo'
  }
}

{"version":"2.4.1","objects":[{"custom":true,"sayHi":"Halo"}],"background":"#222"}
發現資料被修改囉!

新增自己的屬性

今天我們可能想為了我們所新增的物件,添加自己的屬性,若直接使用序列化是無法被編寫上去的,這時只要透過我們剛剛學到的: 修改物件的 toObject 方法。

我們可以透過更改物件上 toObject 方法,來讓物件在序列化時,也儲存我們的自訂屬性。

假設今天我們想為我們的 rect 加上 name 屬性

rect.name = 'Nono'

這時直接使用序列化是不行的,會發現序列化後沒有這個屬性。

透過:

rect.toObject = (function(toObject) {
  return function() {
    return fabric.util.object.extend(toObject.call(this), {
      name: this.name
    })
  }
})(rect.toObject)

這邊比較複雜一些,稍微看了一下,大概的作法就是將 toObject 先呼叫一次取得目前的 object 後讓兩個物件合併起來。

{"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"}

這樣一來我們就能將我們的自訂屬性正常的序列化囉!

toSVG 將 fabricjs 物件轉成 svg

我們可以簡單的直接將 fabricjs 的物件轉成 svg。

透過:

rect.toSVG()

簡單又快速的就把 canvas 轉成 svg 囉

什麼不會一起被序列化

這裡必須要注意到 fabricjs 主要是能夠序列化 物件,所以要記得事件是不會一起被序列化的喔!
下面這個不會被序列化喔

我們在一次加入事件後,在做序列化

canvas.on('mouse:move', (e) => {
  console.log(e)
})

這時使用序列化也不會將事件儲存起來喔!

今日小結

把 canvas 序列化變成

  • json
  • object
  • svg

並且了解 fabricjs 序列化的深入用法: 自訂屬性
明天再來使用反序列化把畫布還原。


上一篇
Day 10 - 為圖形填入漸層色
下一篇
Day 12 -利用序列化與反序列化來實作存檔功能及還原功能
系列文
Fabricjs 筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言