如何从JSON重新加载基于fabric.Polyline的自定义FabricJS Canvas对象?
loadFromJSON Error with Custom FabricJS Polyline Class Let's break down why you're hitting that Cannot read property 'x' of undefined error and fix it step by step.
Root Cause
The issue lies in how your fabric.TreeNode class initializes its parent fabric.Polyline class.
fabric.Polyline's constructor expects two arguments: first the array of points, then an options object. Your current initialize method only accepts an options parameter and passes that to the parent constructor—this means the polyline's points never get properly initialized under the hood. When you serialize and deserialize, Fabric tries to process invalid points data, leading to the TypeError.
Corrected Code
Here's the fixed version of your custom class and related code:
var canvas = new fabric.Canvas('c', { }); // Fixed custom TreeNode class fabric.TreeNode = fabric.util.createClass(fabric.Polyline, { type: 'treeNode', // Initialize now accepts points + options, matching Polyline's signature initialize: function (points, options) { options || (options = {}); // Pass points first, then options to the parent constructor this.callSuper('initialize', points, options); // Use Fabric's set() method for consistent property handling this.set('stroke', 'blue'); }, toObject: function () { // Extend parent's toObject output with our custom properties return fabric.util.object.extend(this.callSuper('toObject'), { stroke: this.get('stroke') }); }, _render: function (ctx) { this.callSuper('_render', ctx); } }); // Fix fromObject to leverage Polyline's point-handling logic fabric.TreeNode.fromObject = function (object, callback) { // Use Polyline's fromObject method, specifying our custom class name return fabric.Polyline.fromObject(object, callback, 'TreeNode'); }; // Rest of your code remains the same 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); var myJSON = JSON.stringify(canvas); canvas.loadFromJSON(myJSON, canvas.renderAll.bind(canvas));
Key Fixes Explained
Adjusted
initializeSignature:- Changed to accept
pointsas the first parameter, followed byoptions, matchingfabric.Polyline's constructor. - Passed both
pointsandoptionstocallSuperso the parent class correctly initializes the polyline's shape data.
- Changed to accept
Fixed
fromObjectMethod:- Instead of using
fabric.Object._fromObject, we usefabric.Polyline.fromObjectwhich already handles the parsing of polyline points. The third argument tells it to instantiate our customTreeNodeclass instead of a standardPolyline.
- Instead of using
Used Fabric's
set()Method:- Replaced direct property assignment (
this.stroke = 'blue') withthis.set('stroke', 'blue')to ensure Fabric tracks the property correctly for serialization/deserialization.
- Replaced direct property assignment (
With these changes, your custom TreeNode class will serialize and deserialize properly using canvas.loadFromJSON() without throwing errors.
内容的提问来源于stack exchange,提问作者Emile Haas

