首页 > 解决方案 > Fabric JS在数据库中存储步骤

问题描述

这个问题可能有点自以为是,对此提前表示抱歉。有什么方法可以有效地存储在 FabricJS 画布上完成的步骤?假设我是一个用户,我想稍后继续编辑我的画布,所以我关闭了窗口,下次打开它时,我们可以从数据库中加载所有之前的步骤吗?我正在考虑存储canvas.toJSON()到数据库中,但它非常大,比我需要的要大得多,因为所做的更改通常非常小。是否有任何更短且“可加载”到画布的功能或约定?我正在考虑为此创建自己的约定,仅存储实际更改,即增量,这是个好主意吗?

标签: javascriptreactjsfabricjs

解决方案


TL;博士;

您可以删除不必要的(默认)对象数据并使用压缩lz-string


结果如此长的原因是它为您提供了所有属性,包括默认值。所以你可以通过删除默认值来解决这个问题。

此示例脚本删除每个值为0or的对象属性null

var canvas = new fabric.Canvas('c');
canvas.add(new fabric.Rect({left: 50,  top: 50, height: 20, width: 20,  fill: 'green'}));
canvas.add(new fabric.Circle({left: 100,  top: 100, radius: 50, fill: 'red'}));

let output = canvas.toJSON();
let copy = {...output, objects:[]};

(output.objects || []).map(object => {
  let objectCopy = {};
  for (let key in object) {
    val = object[key];
    if (val !== null && val !== 0){
        objectCopy[key] = object[key]
    } else {
        // console.log('skipped', key, object[key])
    }
  }
  copy.objects.push(objectCopy);
})
var canvas2 = new fabric.Canvas('d');
canvas2.loadFromJSON(JSON.stringify(canvas));

console.log(JSON.stringify(canvas).length);
console.log(JSON.stringify(copy).length);
#canvas-wrapper {
  position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js" integrity="sha512-ACqMrfAtm537AWzgx/xQ57JnFxXeq8RylQMGg4y/e6M2ew4Z8NycE8aId/Bt2ZE+w1gNsox3MgwxKl7SGMRdtA==" crossorigin="anonymous"></script>
<div id="canvas-wrapper"><canvas id="c" width="400" height="200" /></div>
<div id="canvas-wrapper"><canvas id="d" width="400" height="200" /></div>

这给了我们大约 20% 的改进。

此外,这种方法很幼稚,还有很大的改进空间。它不能处理组(嵌套对象),如果您将默认值 1 覆盖为 0(即strokeWidth),它将忽略它并导致错误的结果。因此,该解决方案必须考虑每种对象类型的完整默认设置列表,但它可以很容易地为您提供超过 50% 的常用压缩率。

另一种选择是使用压缩库(如lz-string)来压缩您的字符串结果。这可以开箱即用地为您带来 %70-%80 的改进。这更快,更可靠。

恕我直言,理想的情况是两者都做,这可以让你降低到原来的 5-10%


推荐阅读