Fabric.js 负责绘制对象、处理鼠标交互,并把画布转成 JSON。可一个画布编辑器需要的不止这些。Fabric.js 文档引擎把这些能力组织成一份文档,让你可以保存、重新打开、撤销和恢复。
toJSON 和 loadFromJSON 没帮你做的事
大多数编辑器一开始都用 canvas.toJSON() 和 canvas.loadFromJSON()。做演示没问题,放进真实产品后,下面这些问题会一个个冒出来:
- 自定义属性丢失。
toJSON会丢掉它不认识的属性,除非你每次调用都把它们列出来。 - 对象没有稳定的 id。 你没法把一个图形和评论或数据库里的一行关联起来,因为保存前后没有东西能标识它。
- 加载失败后画布只剩一半。 只要有一张图片丢了,
loadFromJSON可能已经清空画布,只加载了部分内容。 - 两次加载互相抢。 用户先打开文档 A,又马上打开 B。如果 A 最后才加载完,显示的就是 A。
- 旧的保存覆盖新的。 一次很慢的保存可能晚于更新的保存完成。另一个标签页也可能不声不响地覆盖你的内容。
- 没有撤销。 Fabric.js 本身没有撤销重做。每次改动都给整个画布拍快照,图一大就会变慢。
引擎补上了什么
| 问题 | 引擎的做法 |
|---|---|
| 没有 id | 每个对象,包括编组里的子对象,都有稳定的对象 id |
| 自定义属性丢失 | 类和它的属性注册一次就够了 |
| 画布只加载了一半 | 动画布之前,先校验文档并检查每张图片 |
| 加载互相抢 | 最新的加载生效,较早的被取消 |
| 旧保存覆盖新保存 | 同一时间只有一次保存,并用修订号发现其他标签页的改动 |
| 没有撤销 | 每个用户操作一步撤销,只存变化的部分 |
| 崩溃后内容丢失 | 用户编辑时,未保存的内容会复制到 IndexedDB |
画布、工具栏和界面都还是你自己的。Fabric.js 文档引擎只监听画布,只在你加载、撤销或恢复时才改动它。
它不做的事
- 不画工具栏,也不提供任何界面。按钮由你的应用渲染。
- 不托管你的数据。你接入自己的存储,或者用内置的 localStorage 适配器。
- 不替代 Fabric.js。对象还是用 Fabric.js 的类来创建。
- 不做实时协作。修订号能发现冲突,但两个人不能同时在线编辑。
什么时候用它
当用户会在你的画布编辑器里保存作品,并希望之后还能找到它时,就适合用 Fabric.js 文档引擎:设计工具、户型图、标签设计器、白板、图片标注等。只画一次、从不保存的场景,用 Fabric.js 本身就够了。