如何从 JSON 重新加载自定义 fabricJS canvas 对象?
How do I reload custom fabricJS canvas objects from JSON?
我正在使用 fabricJS 和自定义 classes.
我遇到了 canvas.loadFromJSON()
的问题,所以我从 学习了基本的 MRE 来找出我的自定义结构 class 有什么问题。问题中的示例工作正常,但它基于 fabric.Rect
.
创建了一个 class
我需要一个基于 fabric.Polyline
的自定义 class。我稍微修改了代码并得到了这个:
var canvas = new fabric.Canvas('c', {
});
// my custom TreeNode class
fabric.TreeNode = fabric.util.createClass(fabric.Polyline, {
type: 'treeNode',
initialize: function (options) {
options || (options = {});
// console.log(options);
this.callSuper('initialize', options);
this.stroke = 'blue';
},
toObject: function () {
return fabric.util.object.extend(this.callSuper('toObject'), {
stroke: this.get('stroke')
});
},
_render: function (ctx) {
this.callSuper('_render', ctx);
}
});
fabric.TreeNode.fromObject = function (object, callback) {
return fabric.Object._fromObject('TreeNode', object, callback);
};
var rect = new fabric.Rect({
left: 300,
top: 200,
fill: 'blue',
width: 50,
height: 50,
});
canvas.add(rect);
var node = new fabric.TreeNode([{ x: 50, y: 100 }, { x: 200, y: 300 }, { x: 10, y: 10 }]);
canvas.add(node);
// Serializing the whole canvas to JSON
var myJSON = JSON.stringify(canvas);
// console.log(myJSON);
// '{"version":"4.3.1","objects":[{"type":"rect","version":"4.3.1","originX":"left","originY":"top","left":300,"top":200,"width":50,"height":50,"fill":"blue","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"rx":0,"ry":0},{"type":"treeNode","version":"4.3.1","originX":"left","originY":"top","left":9.5,"top":9.5,"width":190,"height":290,"fill":"rgb(0,0,0)","stroke":"blue","strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":50,"y":100},{"x":200,"y":300},{"x":10,"y":10}]}]}'
// De-serializing doesn't work if fabric.TreeNode object is part of canvas
canvas.loadFromJSON(myJSON, canvas.renderAll.bind(canvas));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.js"
integrity="sha512-CzyxOXSECwo2nGJQZ2P8fdDxWVMVzn0jNdT2lYJ3afbqDJbaQ4qxgv9sLc85f6KP8HO2y929Bu+lnPKGC3ofSg=="
crossorigin="anonymous"></script>
</head>
<body>
<canvas id="c" width="1000" height="600" style="border: 1px solid rgb(219, 40, 40);"></canvas>
<!-- <script src="./loadJSON.js"></script> -->
</body>
</html>
如您所见,当尝试从 JSON 加载回 canvas 时,我得到 Uncaught TypeError: Cannot read property 'x' of undefined at find (fabric.js:2469) at min (fabric.js:2444)
在浏览器上我可以检查源代码中的错误来源,但我无法弄清楚问题出在哪里。非常感谢任何帮助。
我在 fabricJS gitHub 页面上发布了我的问题 (link here),
@asturur 非常友好地指出我必须更改 fromObject
函数。
the fromObject for the polyline specifically is:
> fabric.Polyline.fromObject = function(object, callback) {
> return fabric.Object._fromObject('Polyline', object, callback, 'points'); };
Try to have the correct initialize function and a
fromObject function that refer to points on the last argument, i
assume it could fix your issues
所以,话虽如此,我修改了我的代码片段,现在 loadFromJSON()
工作正常。此处示例:
var canvas = new fabric.Canvas('c', {
});
// my custom TreeNode class
fabric.TreeNode = fabric.util.createClass(fabric.Polyline, {
type: 'treeNode',
initialize: function (options) {
options || (options = {});
// console.log(options);
this.callSuper('initialize', options);
this.stroke = 'blue';
},
toObject: function () {
return fabric.util.object.extend(this.callSuper('toObject'), {
stroke: this.get('stroke')
});
},
_render: function (ctx) {
this.callSuper('_render', ctx);
}
});
fabric.TreeNode.fromObject = function (object, callback) {
// ** CHANGE : using the _fromObject() of Polyline
return fabric.Object._fromObject('Polyline', object, callback, 'points');
};
var rect = new fabric.Rect({
left: 300,
top: 200,
fill: 'blue',
width: 50,
height: 50,
});
canvas.add(rect);
var node = new fabric.TreeNode([{ x: 50, y: 100 }, { x: 200, y: 300 }, { x: 10, y: 10 }]);
canvas.add(node);
// Serializing the whole canvas to JSON
var myJSON = JSON.stringify(canvas);
console.log(myJSON);
// {"version":"4.3.1","objects":[{"type":"rect","version":"4.3.1","originX":"left","originY":"top","left":300,"top":200,"width":50,"height":50,"fill":"blue","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"rx":0,"ry":0},{"type":"treeNode","version":"4.3.1","originX":"left","originY":"top","left":9.5,"top":9.5,"width":190,"height":290,"fill":"rgb(0,0,0)","stroke":"blue","strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":50,"y":100},{"x":200,"y":300},{"x":10,"y":10}]}]}
// De-serializing now works for both rect and TreeNode objects
canvas.loadFromJSON(myJSON, canvas.renderAll.bind(canvas));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.js"
integrity="sha512-CzyxOXSECwo2nGJQZ2P8fdDxWVMVzn0jNdT2lYJ3afbqDJbaQ4qxgv9sLc85f6KP8HO2y929Bu+lnPKGC3ofSg=="
crossorigin="anonymous"></script>
</head>
<body>
<canvas id="c" width="1000" height="600" style="border: 1px solid rgb(219, 40, 40);"></canvas>
<!-- <script src="./loadJSON.js"></script> -->
</body>
</html>
我正在使用 fabricJS 和自定义 classes.
我遇到了 canvas.loadFromJSON()
的问题,所以我从 fabric.Rect
.
我需要一个基于 fabric.Polyline
的自定义 class。我稍微修改了代码并得到了这个:
var canvas = new fabric.Canvas('c', {
});
// my custom TreeNode class
fabric.TreeNode = fabric.util.createClass(fabric.Polyline, {
type: 'treeNode',
initialize: function (options) {
options || (options = {});
// console.log(options);
this.callSuper('initialize', options);
this.stroke = 'blue';
},
toObject: function () {
return fabric.util.object.extend(this.callSuper('toObject'), {
stroke: this.get('stroke')
});
},
_render: function (ctx) {
this.callSuper('_render', ctx);
}
});
fabric.TreeNode.fromObject = function (object, callback) {
return fabric.Object._fromObject('TreeNode', object, callback);
};
var rect = new fabric.Rect({
left: 300,
top: 200,
fill: 'blue',
width: 50,
height: 50,
});
canvas.add(rect);
var node = new fabric.TreeNode([{ x: 50, y: 100 }, { x: 200, y: 300 }, { x: 10, y: 10 }]);
canvas.add(node);
// Serializing the whole canvas to JSON
var myJSON = JSON.stringify(canvas);
// console.log(myJSON);
// '{"version":"4.3.1","objects":[{"type":"rect","version":"4.3.1","originX":"left","originY":"top","left":300,"top":200,"width":50,"height":50,"fill":"blue","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"rx":0,"ry":0},{"type":"treeNode","version":"4.3.1","originX":"left","originY":"top","left":9.5,"top":9.5,"width":190,"height":290,"fill":"rgb(0,0,0)","stroke":"blue","strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":50,"y":100},{"x":200,"y":300},{"x":10,"y":10}]}]}'
// De-serializing doesn't work if fabric.TreeNode object is part of canvas
canvas.loadFromJSON(myJSON, canvas.renderAll.bind(canvas));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.js"
integrity="sha512-CzyxOXSECwo2nGJQZ2P8fdDxWVMVzn0jNdT2lYJ3afbqDJbaQ4qxgv9sLc85f6KP8HO2y929Bu+lnPKGC3ofSg=="
crossorigin="anonymous"></script>
</head>
<body>
<canvas id="c" width="1000" height="600" style="border: 1px solid rgb(219, 40, 40);"></canvas>
<!-- <script src="./loadJSON.js"></script> -->
</body>
</html>
如您所见,当尝试从 JSON 加载回 canvas 时,我得到 Uncaught TypeError: Cannot read property 'x' of undefined at find (fabric.js:2469) at min (fabric.js:2444)
在浏览器上我可以检查源代码中的错误来源,但我无法弄清楚问题出在哪里。非常感谢任何帮助。
我在 fabricJS gitHub 页面上发布了我的问题 (link here),
@asturur 非常友好地指出我必须更改 fromObject
函数。
the fromObject for the polyline specifically is:
> fabric.Polyline.fromObject = function(object, callback) {
> return fabric.Object._fromObject('Polyline', object, callback, 'points'); };
Try to have the correct initialize function and a fromObject function that refer to points on the last argument, i assume it could fix your issues
所以,话虽如此,我修改了我的代码片段,现在 loadFromJSON()
工作正常。此处示例:
var canvas = new fabric.Canvas('c', {
});
// my custom TreeNode class
fabric.TreeNode = fabric.util.createClass(fabric.Polyline, {
type: 'treeNode',
initialize: function (options) {
options || (options = {});
// console.log(options);
this.callSuper('initialize', options);
this.stroke = 'blue';
},
toObject: function () {
return fabric.util.object.extend(this.callSuper('toObject'), {
stroke: this.get('stroke')
});
},
_render: function (ctx) {
this.callSuper('_render', ctx);
}
});
fabric.TreeNode.fromObject = function (object, callback) {
// ** CHANGE : using the _fromObject() of Polyline
return fabric.Object._fromObject('Polyline', object, callback, 'points');
};
var rect = new fabric.Rect({
left: 300,
top: 200,
fill: 'blue',
width: 50,
height: 50,
});
canvas.add(rect);
var node = new fabric.TreeNode([{ x: 50, y: 100 }, { x: 200, y: 300 }, { x: 10, y: 10 }]);
canvas.add(node);
// Serializing the whole canvas to JSON
var myJSON = JSON.stringify(canvas);
console.log(myJSON);
// {"version":"4.3.1","objects":[{"type":"rect","version":"4.3.1","originX":"left","originY":"top","left":300,"top":200,"width":50,"height":50,"fill":"blue","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"rx":0,"ry":0},{"type":"treeNode","version":"4.3.1","originX":"left","originY":"top","left":9.5,"top":9.5,"width":190,"height":290,"fill":"rgb(0,0,0)","stroke":"blue","strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":50,"y":100},{"x":200,"y":300},{"x":10,"y":10}]}]}
// De-serializing now works for both rect and TreeNode objects
canvas.loadFromJSON(myJSON, canvas.renderAll.bind(canvas));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.js"
integrity="sha512-CzyxOXSECwo2nGJQZ2P8fdDxWVMVzn0jNdT2lYJ3afbqDJbaQ4qxgv9sLc85f6KP8HO2y929Bu+lnPKGC3ofSg=="
crossorigin="anonymous"></script>
</head>
<body>
<canvas id="c" width="1000" height="600" style="border: 1px solid rgb(219, 40, 40);"></canvas>
<!-- <script src="./loadJSON.js"></script> -->
</body>
</html>