Fabric.js 把画布序列化

2018-11-27 23:10:56
1515次阅读
0个评论
今天我们要来了解 Fabricjs 的序列化功能。一般我们会在什麼情境下用到这个功能呢?
就是存档和读档啦!

使用者若有存取和读取自己所设计的图片的需求,我们会利用将 canvas 中的内容整个序列化,变成 json 的格式,当使用者想再次修改时,就从后端把之前做过序列化的资料读取出来,被且再透过 fabricjs 的解析,又变成一个能够自由修改的画布啦!。

另外 fabricjs 还提供了 canvas 转成 svg path 的序列化,也相当的实用。

今天就主要介绍几种序列化的方法

toJSON 转成 json 格式
toObject 转成物件格式
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 物件之下。

这边我们可以做个实验。

我们偷偷修改 rect 的 toObject 的方法。并在一次做序列化,来查看资料是否有变。

// 偷偷增加在 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)
})

这时使用序列化也不会将事件储存起来喔!
收藏00

登录 后评论。没有帐号? 注册 一个。