I am trying to save data in JSON and load it back into the canvas with fabric.js I keep getting errors likep with the following simple code:
canvas.add(new fabric.Rect({ width: 50, height: 50, fill: 'red', top: 100, left: 100 }));
var c = canvas.toJSON();
canvas.clear();
canvas.loadFromJSON(c);
I get:
SyntaxError: JSON.parse: unexpected character
[Break On This Error] var Cufon=(function(){var k=function()....Image.fromElement.async=true})(this);
When I use my own JSON, It validates well, but I still get errors when I use whatever was output by fabric's method canvas.toJSON(). Anyone would have working examples of loading back into an empty canvas data saved from a previous canvas state in fabric.js? It would be greatly appreciated!
fabric.Canvas#toJSON
actually returns an object, not a JSON string.
Sorry, if this is confusing.
The reason this works like that is due to JSON.stringify
. The thing about JSON.stringify
is that it supports custom serialization; all you need to do is pass an object that has toJSON
method. And this is exactly what I did in fabric — fabric.Canvas has toJSON
method, which is essentially an alias to toObject
method.
This allows us to serialize canvas by doing something as simple as:
JSON.stringify(canvas);
.. where canvas
is a reference to fabric.Canvas
instance.
The difference between toObject
and toDatalessObject
(as well as toJSON
and toDatalessJSON
) is that toDatalessObject
returns "url" instead of actual path data. This is done to save on size of canvas representation with shapes of large size. If you load large SVG shape, its path data could literally result in multi-million character string. If you later need to serialize this data (say, for saving purposes), it makes much more sense to replace path data with URL of svg shape. Just imagine having to upload/download such huge strings to the server back and forth.
So, instead of this:
{ "angle" : 3,
"fill" : "#00274D",
"flipX" : false,
"flipY" : false,
"height" : 115,
"left" : 353,
"opacity" : 1,
"overlayFill" : null,
"path" : [ [ "M",
67.390000000000001,
22.390000000000001
],
[ "c",
2.5899999999999999,
-0.42999999999999999,
5.1100000000000003,
1.4399999999999999,
5.54,
4.1799999999999997
],
[ "c",
0.42999999999999999,
2.6600000000000001,
-1.3,
5.2599999999999998,
-3.8900000000000001,
5.6900000000000004
],
[ "c",
-1.8,
0.28999999999999998,
-3.6000000000000001,
-0.57999999999999996,
-4.6100000000000003,
-2.02
],
[ "L",
44.5,
34.560000000000002
],
[ "l",
10.869999999999999,
59.619999999999997
],
[ "c",
17.420000000000002,
-4.46,
26.059999999999999,
-14.18,
27.5,
-29.02
],
[ "l",
-10.01,
-0.71999999999999997
],
[ "L",
88.700000000000003,
51.909999999999997
],
[ "l",
9.4299999999999997,
21.239999999999998
],
[ "c",
-3.3799999999999999,
-1.95,
-5.9000000000000004,
-5.1100000000000003,
-9.2899999999999991,
-7.0599999999999996
],
[ "c",
-0.28999999999999998,
25.059999999999999,
-27.140000000000001,
32.759999999999998,
-33.770000000000003,
47.950000000000003
],
[ "C",
44.420000000000002,
100.08,
26.5,
114.77,
6.9100000000000001,
82.799999999999997
],
[ "L",
0,
92.450000000000003
],
[ "l",
1.51,
-21.600000000000001
],
[ "l",
19.66,
4.6799999999999997
],
[ "l",
-9.4299999999999997,
3.6699999999999999
],
[ "c",
7.4900000000000002,
11.59,
17.57,
19.870000000000001,
36.43,
16.420000000000002
],
[ "L",
36.219999999999999,
36.57
],
[ "l",
-18.649999999999999,
2.3799999999999999
],
[ "c",
-0.14000000000000001,
2.1600000000000001,
-1.73,
4.0300000000000002,
-3.8900000000000001,
4.3899999999999997
],
[ "c",
-2.5899999999999999,
0.42999999999999999,
-5.04,
-1.4399999999999999,
-5.54,
-4.0999999999999996
],
[ "c",
-0.42999999999999999,
-2.7400000000000002,
1.3,
-5.2599999999999998,
3.8900000000000001,
-5.6900000000000004
],
[ "c",
1.9399999999999999,
-0.35999999999999999,
3.8900000000000001,
0.65000000000000002,
4.9000000000000004,
2.2999999999999998
],
[ "l",
17.93,
-4.8200000000000003
],
[ "l",
-1.3700000000000001,
-6.8399999999999999
],
[ "c",
-4.8200000000000003,
-0.79000000000000004,
-8.9299999999999997,
-4.75,
-9.7899999999999991,
-10.08
],
[ "c",
-1.1499999999999999,
-6.6200000000000001,
3.1000000000000001,
-12.890000000000001,
9.4299999999999997,
-13.970000000000001
],
[ "c",
6.4100000000000001,
-1.01,
12.460000000000001,
3.46,
13.539999999999999,
10.08
],
[ "c",
0.85999999999999999,
5.1799999999999997,
-1.5800000000000001,
10.15,
-5.6900000000000004,
12.6
],
[ "l",
1.8700000000000001,
6.1200000000000001
],
[ "l",
20.739999999999998,
-2.8799999999999999
],
[ "C",
64.010000000000005,
24.260000000000002,
65.519999999999996,
22.75,
67.390000000000001,
22.390000000000001
],
[ "L",
67.390000000000001,
22.390000000000001
],
[ "z" ],
[ "M",
33.909999999999997,
5.1799999999999997
],
[ "c",
-3.46,
0.57999999999999996,
-5.7599999999999998,
3.96,
-5.1100000000000003,
7.5599999999999996
],
[ "c",
0.57999999999999996,
3.6000000000000001,
3.8900000000000001,
6.0499999999999998,
7.2699999999999996,
5.4699999999999998
],
[ "c",
3.46,
-0.57999999999999996,
5.7599999999999998,
-3.96,
5.1799999999999997,
-7.5599999999999996
],
[ "C",
40.609999999999999,
7.0499999999999998,
37.369999999999997,
4.6100000000000003,
33.909999999999997,
5.1799999999999997
],
[ "z" ]
],
"scaleX" : 3.0299999999999998,
"scaleY" : 3.0299999999999998,
"selectable" : true,
"stroke" : null,
"strokeWidth" : 1,
"top" : 220,
"type" : "path",
"width" : 99
}
you would have this:
{ "angle" : 3,
"fill" : "#00274D",
"flipX" : false,
"flipY" : false,
"height" : 115,
"left" : 353,
"opacity" : 1,
"overlayFill" : null,
"path" : "http://example.com",
"scaleX" : 3.0299999999999998,
"scaleY" : 3.0299999999999998,
"selectable" : true,
"stroke" : null,
"strokeWidth" : 1,
"top" : 220,
"type" : "path",
"width" : 99
}
Notice how large that data is, and how relatively small it becomes by replacing path chunk with url.
And that's a representation of a very simple shape.
The only requirement here is to set object's "sourcePath" using setSourcePath
method before calling toDatalessObject
/toDatalessJSON
on it ("sourcePath" is internally copied to "path").
Hope this clears things up a little.