Bladeren bron

Object serialization

tentone 5 jaren geleden
bovenliggende
commit
1b88eb19b5

File diff suppressed because it is too large
+ 628 - 231
build/escher.js


+ 2 - 2
build/escher.module.js

@@ -3761,7 +3761,7 @@ function NodeSocket(node, direction, type, name)
 	 *
 	 *
 	 * @type {string}
 	 * @type {string}
 	 */
 	 */
-	this.type = type !== undefined ? type : "";
+	this.category = type !== undefined ? type : "";
 
 
 	/**
 	/**
 	 * Direction of the node hook, indicates the data flow of the socket.
 	 * Direction of the node hook, indicates the data flow of the socket.
@@ -3909,7 +3909,7 @@ NodeSocket.prototype.attachConnector = function(connector)
  */
  */
 NodeSocket.prototype.isCompatible = function(socket)
 NodeSocket.prototype.isCompatible = function(socket)
 {
 {
-	return this.direction !== socket.direction && this.type === socket.type;
+	return this.direction !== socket.direction && this.category === socket.category;
 };
 };
 
 
 NodeSocket.prototype.destroy = function()
 NodeSocket.prototype.destroy = function()

+ 1 - 1
examples/node.html

@@ -91,7 +91,7 @@
 
 
 				this.box.set(new Escher.Vector2(-50, -30), new Escher.Vector2(50, 30));
 				this.box.set(new Escher.Vector2(-50, -30), new Escher.Vector2(50, 30));
 
 
-				this.div = new Escher.DOM(canvas.parentElement, "input");
+				this.div = new Escher.DOM("input");
 				this.div.size.set(70, 20);
 				this.div.size.set(70, 20);
 				this.div.origin.set(35, 10);
 				this.div.origin.set(35, 10);
 				this.div.element.style.pointerEvents = "auto";
 				this.div.element.style.pointerEvents = "auto";

+ 3 - 3
examples/playground.html

@@ -158,7 +158,7 @@
 		Escher.Helpers.boxResizeTool(boxA);
 		Escher.Helpers.boxResizeTool(boxA);
 
 
 		// DOM
 		// DOM
-		var div = new Escher.DOM(division);
+		var div = new Escher.DOM();
 		div.size.set(100, 50);
 		div.size.set(100, 50);
 		div.origin.set(50, 25);
 		div.origin.set(50, 25);
 		boxA.add(div);
 		boxA.add(div);
@@ -170,7 +170,7 @@
 		div.element.appendChild(text);
 		div.element.appendChild(text);
 
 
 		// DOM Fixed
 		// DOM Fixed
-		var div = new Escher.DOM(division);
+		var div = new Escher.DOM();
 		div.size.set(100, 50);
 		div.size.set(100, 50);
 		div.origin.set(50, 25);
 		div.origin.set(50, 25);
 		div.position.set(200, 200);
 		div.position.set(200, 200);
@@ -191,7 +191,7 @@
 		group.add(boxB);
 		group.add(boxB);
 		
 		
 		// DOM
 		// DOM
-		var div = new Escher.DOM(division);
+		var div = new Escher.DOM();
 		div.size.set(100, 50);
 		div.size.set(100, 50);
 		div.origin.set(50, 25);
 		div.origin.set(50, 25);
 		boxB.add(div);
 		boxB.add(div);

+ 2 - 2
examples/stress.html

@@ -62,7 +62,7 @@
 			box.position.set(Math.random() * 1e3, Math.random() * 1e3)
 			box.position.set(Math.random() * 1e3, Math.random() * 1e3)
 			group.add(box);
 			group.add(box);
 	
 	
-			var div = new Escher.DOM(division);
+			var div = new Escher.DOM();
 			div.size.set(100, 50);
 			div.size.set(100, 50);
 			div.origin.set(50, 25);
 			div.origin.set(50, 25);
 			box.add(div);
 			box.add(div);
@@ -91,4 +91,4 @@
 		});
 		});
 	</script>
 	</script>
 </body>
 </body>
-</html>
+</html>

+ 141 - 3
source/Object2D.js

@@ -203,6 +203,29 @@ function Object2D()
 
 
 Object2D.prototype.constructor = Object2D;
 Object2D.prototype.constructor = Object2D;
 
 
+/**
+ * Type of the object, used for data serialization and/or checking the object type.
+ *
+ * The name used should match the object constructor name. But it is not required.
+ *
+ * If this type is from an external library you can add the library name to the object type name to prevent collisions.
+ *
+ * @type {string}
+ */
+Object2D.prototype.type = "Object2D";
+
+/**
+ * List of available object types known by the application. Stores the object constructor by object type.
+ *
+ * Newly created types should be introduced in this map for data serialization support.
+ *
+ * New object types should be added using the Object2D.register() method.
+ *
+ * @static
+ * @type {Map<string, Function>}
+ */
+Object2D.types = new Map([]);
+
 /**
 /**
  * Check if a point in world coordinates intersects this object or its children and get a list of the objects intersected.
  * Check if a point in world coordinates intersects this object or its children and get a list of the objects intersected.
  *
  *
@@ -406,8 +429,9 @@ Object2D.prototype.updateMatrix = function(context)
  *
  *
  * @param {CanvasRenderingContext2D} context Canvas 2d drawing context.
  * @param {CanvasRenderingContext2D} context Canvas 2d drawing context.
  * @param {Viewport} viewport Viewport applied to the canvas.
  * @param {Viewport} viewport Viewport applied to the canvas.
+ * @param {Element} canvas DOM canvas element where the content is being drawn.
  */
  */
-Object2D.prototype.transform = function(context, viewport)
+Object2D.prototype.transform = function(context, viewport, canvas)
 {
 {
 	this.globalMatrix.tranformContext(context);
 	this.globalMatrix.tranformContext(context);
 };
 };
@@ -421,7 +445,7 @@ Object2D.prototype.transform = function(context, viewport)
  *
  *
  * @param {CanvasRenderingContext2D} context Canvas 2d drawing context.
  * @param {CanvasRenderingContext2D} context Canvas 2d drawing context.
  * @param {Viewport} viewport Viewport used to view the canvas content.
  * @param {Viewport} viewport Viewport used to view the canvas content.
- * @param {DOM} canvas DOM canvas element where the content is being drawn.
+ * @param {Element} canvas DOM canvas element where the content is being drawn.
  */
  */
 Object2D.prototype.style = null; // function(context, viewport, canvas){};
 Object2D.prototype.style = null; // function(context, viewport, canvas){};
 
 
@@ -432,7 +456,7 @@ Object2D.prototype.style = null; // function(context, viewport, canvas){};
  *
  *
  * @param {CanvasRenderingContext2D} context Canvas 2d drawing context.
  * @param {CanvasRenderingContext2D} context Canvas 2d drawing context.
  * @param {Viewport} viewport Viewport used to view the canvas content.
  * @param {Viewport} viewport Viewport used to view the canvas content.
- * @param {DOM} canvas DOM canvas element where the content is being drawn.
+ * @param {Element} canvas DOM canvas element where the content is being drawn.
  */
  */
 Object2D.prototype.draw = null; // function(context, viewport, canvas){};
 Object2D.prototype.draw = null; // function(context, viewport, canvas){};
 
 
@@ -552,4 +576,118 @@ Object2D.prototype.onButtonDown = null;
  */
  */
 Object2D.prototype.onButtonUp = null;
 Object2D.prototype.onButtonUp = null;
 
 
+/**
+ * Serialize the object data into a JSON object. That can be written into a file, sent using HTTP request etc.
+ *
+ * All required attributes to recreate the object in its current state should be stored. Relations between children should be stored by their UUID only.
+ *
+ * Data has to be parsed back into a usable object.
+ *
+ * @param {boolean} recursive If set false the children list is not serialized, otherwise all children are serialized.
+ * @return {Object} Serialized object data.
+ */
+Object2D.prototype.serialize = function(recursive)
+{
+	var data = {
+		uuid: this.uuid,
+		type: this.type,
+		position: this.position.toArray(),
+		origin: this.origin.toArray(),
+		scale: this.scale.toArray(),
+		rotation: this.rotation,
+		visible: this.visible,
+		layer: this.layer,
+		matrix: this.matrix.m,
+		globalMatrix: this.globalMatrix.m,
+		inverseGlobalMatrix: this.inverseGlobalMatrix.m,
+		matrixAutoUpdate: this.matrixAutoUpdate,
+		draggable: this.draggable,
+		pointerEvents: this.pointerEvents,
+		ignoreViewport: this.ignoreViewport,
+		saveContextState: this.saveContextState,
+		restoreContextState: this.restoreContextState,
+		pointerInside: this.pointerInside,
+		beingDragged: this.beingDragged,
+		children: [],
+		masks: []
+	};
+
+	if(recursive !== false)
+	{
+		for(var i = 0; i < this.children.length; i++)
+		{
+			data.children.push(this.children[i].serialize());
+		}
+	}
+
+	for(var i = 0; i < this.masks.length; i++)
+	{
+		data.masks.push(this.masks[i].uuid);
+	}
+
+	return data;
+};
+
+/**
+ * Parse serialized object data and fill the object attributes.
+ *
+ * Implementations of this method should only load the attributes added to the structure, the based method already loads common attributes.
+ *
+ * Dont forget to register object types using the Object2D.register() method.
+ *
+ * @param {Object} data Object data loaded from JSON.
+ */
+Object2D.prototype.parse = function(data)
+{
+	this.uuid = data.uuid;
+	this.position.fromArray(data.position);
+	this.origin.fromArray(data.origin);
+	this.scale.fromArray(data.scale);
+	this.rotation = data.rotation;
+	this.visible = data.visible;
+	this.layer = data.layer;
+	this.matrix = new Matrix(data.matrix);
+	this.globalMatrix = new Matrix(data.globalMatrix);
+	this.inverseGlobalMatrix = new Matrix(data.inverseGlobalMatrix);
+	this.matrixAutoUpdate = data.matrixAutoUpdate;
+	this.draggable = data.draggable;
+	this.pointerEvents = data.pointerEvents;
+	this.ignoreViewport = data.ignoreViewport;
+	this.saveContextState = data.saveContextState;
+	this.restoreContextState = data.restoreContextState;
+	this.pointerInside = data.pointerInside;
+	this.beingDragged = data.beingDragged;
+};
+
+/**
+ * Create objects from serialized object data into the proper data structures.
+ *
+ * All objects should implement serialization methods to serialize and load data properly.
+ *
+ * @static
+ * @param {Object} data Object data loaded from JSON.
+ * @return {Object2D} Parsed object data.
+ */
+Object2D.parse = function(data)
+{
+	var object = new Object2D.types.get(data.type)();
+	object.parse(data);
+
+	for(var i = 0; i < data.children.length; i++)
+	{
+		this.add(Object2D.parse(data.children[i]));
+	}
+
+
+	// TODO <ADD CODE HERE>
+	/*
+	for(var i = 0; i < this.masks.length; i++)
+	{
+		data.masks.push(this.masks[i].uuid);
+	}
+	*/
+
+	return object;
+};
+
 export {Object2D};
 export {Object2D};

+ 0 - 40
source/Serialization.js

@@ -1,40 +0,0 @@
-import {Object2D} from "./Object2D";
-
-/**
- * Handles object serialization to and from JSON.
- *
- * All objects should implement serialization methods to serialize and load data from generic object.
- *
- * @class
- */
-function Serialization(){}
-
-/**
- * Serialize a object into JSON object. That can be written into a file, sent using HTTP request etc.
- *
- * Booth the object and all its children are serialized.
- *
- * Data has to be parsed into the correct object types before it can be used using the parse() method.
- *
- * @static
- * @param {Object2D} object Object to be serialized.
- * @return {Object} Serialized object data.
- */
-Serialization.serialize = function(object)
-{
-	// TODO <ADD CODE HERE>
-};
-
-/**
- * Parse serialized object data into the proper data structures to be rendered into the screen.
- *
- * @static
- * @param {Object} data Object data loaded from JSON.
- * @return {Object2D} Parsed object data.
- */
-Serialization.parse = function(data)
-{
-	// TODO <ADD CODE HERE>
-};
-
-export {Serialization};

+ 21 - 0
source/math/Box2.js

@@ -269,4 +269,25 @@ Box2.prototype.equals = function(box)
 	return box.min.equals(this.min) && box.max.equals(this.max);
 	return box.min.equals(this.min) && box.max.equals(this.max);
 };
 };
 
 
+/**
+ * Store the box data into a numeric array.
+ *
+ * @return {number[]} Numeric array with box data min and max.
+ */
+Box2.prototype.toArray = function()
+{
+	return [this.box.min.x, this.box.min.y, this.box.max.x, this.box.max.y];
+};
+
+/**
+ * Set box data min and max from numeric array.
+ *
+ * @param {number[]} array Numeric array with box data min and max.
+ */
+Box2.prototype.fromArray = function(array)
+{
+	this.box.min.set(array[0], array[1]);
+	this.box.max.set(array[2], array[3]);
+};
+
 export {Box2};
 export {Box2};

+ 8 - 1
source/math/Matrix.js

@@ -3,7 +3,7 @@ import {Vector2} from "./Vector2.js";
 /**
 /**
  * 2D 3x2 transformation matrix, used to represent linear geometric transformations over objects.
  * 2D 3x2 transformation matrix, used to represent linear geometric transformations over objects.
  *
  *
- * The values of the matrix are stored in a numeric array and can be applied to the canvas or DOM elements.
+ * The values of the matrix are stored as numeric array. The matrix can be applied to the canvas or DOM elements using CSS transforms.
  *
  *
  * @class
  * @class
  * @param {number[]} values Array of matrix values by row, needs to have exactly 6 values.
  * @param {number[]} values Array of matrix values by row, needs to have exactly 6 values.
@@ -12,6 +12,13 @@ function Matrix(values)
 {
 {
 	if(values !== undefined)
 	if(values !== undefined)
 	{
 	{
+		/**
+		 * Array that contains the matrix data by row. This matrix should have 6 values.
+		 *
+		 * Matrix can be directly edited by accessing this attribute.
+		 *
+		 * @type {number[]}
+		 */
 		this.m = values;
 		this.m = values;
 	}
 	}
 	else
 	else

+ 20 - 0
source/objects/BezierCurve.js

@@ -2,6 +2,7 @@ import {Object2D} from "../Object2D.js";
 import {Vector2} from "../math/Vector2.js";
 import {Vector2} from "../math/Vector2.js";
 import {Circle} from "./Circle.js";
 import {Circle} from "./Circle.js";
 import {Line} from "./Line.js";
 import {Line} from "./Line.js";
+import {QuadraticCurve} from "./QuadraticCurve";
 
 
 /**
 /**
  * Bezier curve object draw as bezier curve between two points.
  * Bezier curve object draw as bezier curve between two points.
@@ -30,6 +31,7 @@ function BezierCurve()
 
 
 BezierCurve.prototype = Object.create(Line.prototype);
 BezierCurve.prototype = Object.create(Line.prototype);
 BezierCurve.prototype.constructor = BezierCurve;
 BezierCurve.prototype.constructor = BezierCurve;
+BezierCurve.prototype.type = "BezierCurve";
 
 
 /**
 /**
  * Create a bezier curve helper, to edit the bezier curve anchor points.
  * Create a bezier curve helper, to edit the bezier curve anchor points.
@@ -82,4 +84,22 @@ BezierCurve.prototype.draw = function(context, viewport, canvas)
 	context.stroke();
 	context.stroke();
 };
 };
 
 
+BezierCurve.prototype.serialize = function(recursive)
+{
+	var data = Line.prototype.serialize.call(this, recursive);
+
+	data.fromCp = this.fromCp.toArray();
+	data.toCp = this.toCp.toArray();
+
+	return data;
+};
+
+BezierCurve.prototype.parse = function(data)
+{
+	Line.prototype.parse.call(this, data);
+
+	this.fromCp.fromArray(data.fromCp);
+	this.toCp.fromArray(data.toCp);
+};
+
 export {BezierCurve};
 export {BezierCurve};

+ 24 - 0
source/objects/Box.js

@@ -2,6 +2,7 @@ import {Object2D} from "../Object2D.js";
 import {Vector2} from "../math/Vector2.js";
 import {Vector2} from "../math/Vector2.js";
 import {Box2} from "../math/Box2.js";
 import {Box2} from "../math/Box2.js";
 import {BezierCurve} from "./BezierCurve";
 import {BezierCurve} from "./BezierCurve";
+import {Text} from "./Text";
 
 
 /**
 /**
  * Box object draw a rectangular object.
  * Box object draw a rectangular object.
@@ -42,6 +43,7 @@ function Box()
 
 
 Box.prototype = Object.create(Object2D.prototype);
 Box.prototype = Object.create(Object2D.prototype);
 Box.prototype.constructor = Box;
 Box.prototype.constructor = Box;
+Box.prototype.type = "Box";
 
 
 Box.prototype.onPointerEnter = function(pointer, viewport)
 Box.prototype.onPointerEnter = function(pointer, viewport)
 {
 {
@@ -77,4 +79,26 @@ Box.prototype.draw = function(context, viewport, canvas)
 	}
 	}
 };
 };
 
 
+Box.prototype.serialize = function(recursive)
+{
+	var data = Object2D.prototype.serialize.call(this, recursive);
+
+	data.box = this.box.toArray();
+	data.strokeStyle = this.strokeStyle;
+	data.lineWidth = this.lineWidth;
+	data.fillStyle = this.fillStyle;
+
+	return data;
+};
+
+Box.prototype.parse = function(data)
+{
+	Object2D.prototype.parse.call(this, data);
+
+	this.box.fromArray(data.box);
+	this.strokeStyle = data.strokeStyle;
+	this.lineWidth = data.lineWidth;
+	this.fillStyle = data.fillStyle;
+};
+
 export {Box};
 export {Box};

+ 23 - 0
source/objects/Circle.js

@@ -40,6 +40,7 @@ function Circle()
 
 
 Circle.prototype = Object.create(Object2D.prototype);
 Circle.prototype = Object.create(Object2D.prototype);
 Circle.prototype.constructor = Circle;
 Circle.prototype.constructor = Circle;
+Circle.prototype.type = "Circle";
 
 
 Circle.prototype.isInside = function(point)
 Circle.prototype.isInside = function(point)
 {
 {
@@ -75,4 +76,26 @@ Circle.prototype.draw = function(context, viewport, canvas)
 	}
 	}
 };
 };
 
 
+Circle.prototype.serialize = function(recursive)
+{
+	var data = Object2D.prototype.serialize.call(this, recursive);
+
+	data.radius = this.radius;
+	data.strokeStyle = this.strokeStyle;
+	data.lineWidth = this.lineWidth;
+	data.fillStyle = this.fillStyle;
+
+	return data;
+};
+
+Circle.prototype.parse = function(data)
+{
+	Object2D.prototype.parse.call(this, data);
+
+	this.radius = data.radius;
+	this.strokeStyle = data.strokeStyle;
+	this.lineWidth = data.lineWidth;
+	this.fillStyle = data.fillStyle;
+};
+
 export {Circle};
 export {Circle};

+ 45 - 9
source/objects/DOM.js

@@ -1,29 +1,29 @@
 import {Object2D} from "../Object2D.js";
 import {Object2D} from "../Object2D.js";
 import {Vector2} from "../math/Vector2.js";
 import {Vector2} from "../math/Vector2.js";
-import {Circle} from "./Circle";
 
 
 /**
 /**
  * A DOM object transformed using CSS3D to be included in the scene.
  * A DOM object transformed using CSS3D to be included in the scene.
  *
  *
- * DOM objects always stay on top of everything else, it is not possible to layer these object with regular canvas objects.
+ * DOM objects always stay on top or bellow (depending on the DOM parent placement) of everything else. It is not possible to layer these object with regular canvas objects.
  *
  *
  * By default mouse events are not supported for these objects (it does not implement pointer collision checking). Use the DOM events for interaction with these types of objects.
  * By default mouse events are not supported for these objects (it does not implement pointer collision checking). Use the DOM events for interaction with these types of objects.
  *
  *
  * @class
  * @class
- * @param {Element} parentDOM Parent DOM element that contains the drawing canvas.
  * @param {string} type Type of the DOM element (e.g. "div", "p", ...)
  * @param {string} type Type of the DOM element (e.g. "div", "p", ...)
  * @extends {Object2D}
  * @extends {Object2D}
  */
  */
-function DOM(parentDOM, type)
+function DOM(type)
 {
 {
 	Object2D.call(this);
 	Object2D.call(this);
 
 
 	/**
 	/**
-	 * Parent element that contains this DOM div.
+	 * Parent element that contains this DOM object.
+	 *
+	 * The DOM parent element if not set manually is automatically set to the parent of the drawing canvas.
 	 *
 	 *
 	 * @type {Element}
 	 * @type {Element}
 	 */
 	 */
-	this.parentDOM = parentDOM;
+	this.parentElement = null;
 
 
 	/**
 	/**
 	 * DOM element contained by this object.
 	 * DOM element contained by this object.
@@ -49,25 +49,39 @@ function DOM(parentDOM, type)
 
 
 DOM.prototype = Object.create(Object2D.prototype);
 DOM.prototype = Object.create(Object2D.prototype);
 DOM.prototype.constructor = DOM;
 DOM.prototype.constructor = DOM;
+DOM.prototype.type = "DOM";
 
 
 /**
 /**
  * DOM object implements onAdd() method to automatically attach the DOM object to the DOM tree.
  * DOM object implements onAdd() method to automatically attach the DOM object to the DOM tree.
  */
  */
 DOM.prototype.onAdd = function()
 DOM.prototype.onAdd = function()
 {
 {
-	this.parentDOM.appendChild(this.element);
+	if(this.parentElement !== null)
+	{
+		this.parentElement.appendChild(this.element);
+	}
 };
 };
 
 
 /**
 /**
- * DOM object implements onAdd() method to automatically remove the DOM object to the DOM tree.
+ * DOM object implements onRemove() method to automatically remove the DOM object to the DOM tree.
  */
  */
 DOM.prototype.onRemove = function()
 DOM.prototype.onRemove = function()
 {
 {
-	this.parentDOM.removeChild(this.element);
+	if(this.parentElement !== null)
+	{
+		this.parentElement.removeChild(this.element);
+	}
 };
 };
 
 
 DOM.prototype.transform = function(context, viewport, canvas)
 DOM.prototype.transform = function(context, viewport, canvas)
 {
 {
+	// Check if the DOM element parent is null
+	if(this.parentElement === null)
+	{
+		this.parentElement = canvas.parentElement;
+		this.parentElement.appendChild(this.element);
+	}
+
 	// CSS transformation matrix
 	// CSS transformation matrix
 	if(this.ignoreViewport)
 	if(this.ignoreViewport)
 	{
 	{
@@ -88,4 +102,26 @@ DOM.prototype.transform = function(context, viewport, canvas)
 	this.element.style.display = this.visible ? "block" : "none"; 
 	this.element.style.display = this.visible ? "block" : "none"; 
 };
 };
 
 
+DOM.prototype.serialize = function(recursive)
+{
+	var data = Object2D.prototype.serialize.call(this, recursive);
+
+	data.size = this.size.toArray();
+	data.element = this.element.outerHTML;
+
+	return data;
+};
+
+DOM.prototype.parse = function(data)
+{
+	Object2D.prototype.parse.call(this, data);
+
+	this.size.fromArray(data.size);
+
+	var parser = new DOMParser();
+	var doc = parser.parseFromString(this.element.outerHTML, 'text/html');
+	this.element = doc.body.children[0];
+};
+
+
 export {DOM};
 export {DOM};

+ 1 - 1
source/objects/Graph.js

@@ -1,7 +1,6 @@
 import {Object2D} from "../Object2D.js";
 import {Object2D} from "../Object2D.js";
 import {Vector2} from "../math/Vector2.js";
 import {Vector2} from "../math/Vector2.js";
 import {Box2} from "../math/Box2.js";
 import {Box2} from "../math/Box2.js";
-import {DOM} from "./DOM";
 
 
 /**
 /**
  * Graph object is used to draw simple graph data into the canvas.
  * Graph object is used to draw simple graph data into the canvas.
@@ -55,6 +54,7 @@ function Graph()
 
 
 Graph.prototype = Object.create(Object2D.prototype);
 Graph.prototype = Object.create(Object2D.prototype);
 Graph.prototype.constructor = Graph;
 Graph.prototype.constructor = Graph;
+Graph.prototype.type = "Graph";
 
 
 Graph.prototype.isInside = function(point)
 Graph.prototype.isInside = function(point)
 {
 {

+ 1 - 0
source/objects/Image.js

@@ -31,6 +31,7 @@ function Image(src)
 
 
 Image.prototype = Object.create(Object2D.prototype);
 Image.prototype = Object.create(Object2D.prototype);
 Image.prototype.constructor = Image;
 Image.prototype.constructor = Image;
+Image.prototype.type = "Image";
 
 
 /**
 /**
  * Set the image of the object.
  * Set the image of the object.

+ 36 - 0
source/objects/Line.js

@@ -1,6 +1,7 @@
 import {Object2D} from "../Object2D.js";
 import {Object2D} from "../Object2D.js";
 import {Vector2} from "../math/Vector2.js";
 import {Vector2} from "../math/Vector2.js";
 import {Image} from "./Image";
 import {Image} from "./Image";
+import {Text} from "./Text";
 
 
 /**
 /**
  * Line object draw a line from one point to another without any kind of interpolation.
  * Line object draw a line from one point to another without any kind of interpolation.
@@ -18,6 +19,8 @@ function Line()
 	 * Initial point of the line.
 	 * Initial point of the line.
 	 *
 	 *
 	 * Can be equal to the position object of another object. Making it automatically follow that object.
 	 * Can be equal to the position object of another object. Making it automatically follow that object.
+	 *
+	 * @type {Vector2}
 	 */
 	 */
 	this.from = new Vector2();
 	this.from = new Vector2();
 
 
@@ -25,6 +28,8 @@ function Line()
 	 * Final point of the line.
 	 * Final point of the line.
 	 *
 	 *
 	 * Can be equal to the position object of another object. Making it automatically follow that object.
 	 * Can be equal to the position object of another object. Making it automatically follow that object.
+	 *
+	 * @type {Vector2}
 	 */
 	 */
 	this.to = new Vector2();
 	this.to = new Vector2();
 
 
@@ -34,22 +39,29 @@ function Line()
 	 * Dash pattern is defined as the size of dashes as pairs of space with no line and with line.
 	 * Dash pattern is defined as the size of dashes as pairs of space with no line and with line.
 	 *
 	 *
 	 * E.g if the dash pattern is [1, 2] we get 1 point with line, 2 without line repeat infinitelly.
 	 * E.g if the dash pattern is [1, 2] we get 1 point with line, 2 without line repeat infinitelly.
+	 *
+	 * @type {number[]}
 	 */
 	 */
 	this.dashPattern = [5, 5];
 	this.dashPattern = [5, 5];
 
 
 	/**
 	/**
 	 * Style of the object line.
 	 * Style of the object line.
+	 *
+	 * @type {string}
 	 */
 	 */
 	this.strokeStyle = "#000000";
 	this.strokeStyle = "#000000";
 
 
 	/**
 	/**
 	 * Line width of the line.
 	 * Line width of the line.
+	 *
+	 * @type {number}
 	 */
 	 */
 	this.lineWidth = 1;
 	this.lineWidth = 1;
 }
 }
 
 
 Line.prototype = Object.create(Object2D.prototype);
 Line.prototype = Object.create(Object2D.prototype);
 Line.prototype.constructor = Line;
 Line.prototype.constructor = Line;
+Line.prototype.type = "Line";
 
 
 Line.prototype.style = function(context, viewport, canvas)
 Line.prototype.style = function(context, viewport, canvas)
 {
 {
@@ -66,4 +78,28 @@ Line.prototype.draw = function(context, viewport, canvas)
 	context.stroke();
 	context.stroke();
 };
 };
 
 
+Line.prototype.serialize = function(recursive)
+{
+	var data = Object2D.prototype.serialize.call(this, recursive);
+
+	data.from = this.from.toArray();
+	data.to = this.to.toArray();
+	data.dashPattern = this.dashPattern;
+	data.strokeStyle = this.strokeStyle;
+	data.lineWidth = this.lineWidth;
+
+	return data;
+};
+
+Line.prototype.parse = function(data)
+{
+	Object2D.prototype.parse.call(this, data);
+
+	this.to.fromArray(data.to);
+	this.from.fromArray(data.from);
+	this.dashPattern = data.dashPattern;
+	this.strokeStyle = data.strokeStyle;
+	this.lineWidth = data.lineWidth;
+};
+
 export {Line};
 export {Line};

+ 20 - 0
source/objects/MultiLineText.js

@@ -1,5 +1,6 @@
 import {Text} from "./Text.js";
 import {Text} from "./Text.js";
 import {Line} from "./Line";
 import {Line} from "./Line";
+import {Object2D} from "../Object2D";
 
 
 /**
 /**
  * Multiple line text drawing directly into the canvas.
  * Multiple line text drawing directly into the canvas.
@@ -34,6 +35,7 @@ function MultiLineText()
 
 
 MultiLineText.prototype = Object.create(Text.prototype);
 MultiLineText.prototype = Object.create(Text.prototype);
 MultiLineText.prototype.constructor = MultiLineText;
 MultiLineText.prototype.constructor = MultiLineText;
+MultiLineText.prototype.type = "MultiLineText";
 
 
 MultiLineText.prototype.draw = function(context, viewport, canvas)
 MultiLineText.prototype.draw = function(context, viewport, canvas)
 {
 {
@@ -96,4 +98,22 @@ MultiLineText.prototype.draw = function(context, viewport, canvas)
 	}
 	}
 };
 };
 
 
+MultiLineText.prototype.serialize = function(recursive)
+{
+	var data = Text.prototype.serialize.call(this, recursive);
+
+	data.maxWidth = this.maxWidth;
+	data.lineHeight = this.lineHeight;
+
+	return data;
+};
+
+MultiLineText.prototype.parse = function(data)
+{
+	Text.prototype.parse.call(this, data);
+
+	this.maxWidth = data.maxWidth;
+	this.lineHeight = data.lineHeight;
+};
+
 export {MultiLineText};
 export {MultiLineText};

+ 11 - 3
source/objects/Pattern.js

@@ -1,6 +1,5 @@
 import {Object2D} from "../Object2D.js";
 import {Object2D} from "../Object2D.js";
 import {Box2} from "../math/Box2.js";
 import {Box2} from "../math/Box2.js";
-import {MultiLineText} from "./MultiLineText";
 
 
 /**
 /**
  * Pattern object draw a image repeated as a pattern.
  * Pattern object draw a image repeated as a pattern.
@@ -17,16 +16,22 @@ function Pattern(src)
 
 
 	/**
 	/**
 	 * Box object containing the size of the object.
 	 * Box object containing the size of the object.
+	 *
+	 * @type {Box2}
 	 */
 	 */
 	this.box = new Box2();
 	this.box = new Box2();
 
 
 	/**
 	/**
 	 * Image source DOM element.
 	 * Image source DOM element.
+	 *
+	 * @type {Element}
 	 */
 	 */
 	this.image = document.createElement("img");
 	this.image = document.createElement("img");
 
 
 	/**
 	/**
-	 * A DOMString indicating how to repeat the pattern image.
+	 * Repetition indicates how the pattern image should be repeated.
+	 *
+	 * @type {string}
 	 */
 	 */
 	this.repetition = "repeat"
 	this.repetition = "repeat"
 
 
@@ -38,11 +43,14 @@ function Pattern(src)
 
 
 Pattern.prototype = Object.create(Object2D.prototype);
 Pattern.prototype = Object.create(Object2D.prototype);
 Pattern.prototype.constructor = Pattern;
 Pattern.prototype.constructor = Pattern;
+Pattern.prototype.type = "Pattern";
 
 
 /**
 /**
- * Set the image of the object.
+ * Set the image source of the object. Can be anything accepted by the src field of an img element.
  *
  *
  * Automatically sets the box size to match the image.
  * Automatically sets the box size to match the image.
+ *
+ * @param {string} src Image source string.
  */
  */
 Pattern.prototype.setImage = function(src)
 Pattern.prototype.setImage = function(src)
 {
 {

+ 17 - 1
source/objects/QuadraticCurve.js

@@ -2,7 +2,6 @@ import {Object2D} from "../Object2D.js";
 import {Vector2} from "../math/Vector2.js";
 import {Vector2} from "../math/Vector2.js";
 import {Circle} from "./Circle.js";
 import {Circle} from "./Circle.js";
 import {Line} from "./Line.js";
 import {Line} from "./Line.js";
-import {Pattern} from "./Pattern";
 
 
 /**
 /**
  * Bezier curve object draw as bezier curve between two points.
  * Bezier curve object draw as bezier curve between two points.
@@ -26,6 +25,7 @@ function QuadraticCurve()
 
 
 QuadraticCurve.prototype = Object.create(Line.prototype);
 QuadraticCurve.prototype = Object.create(Line.prototype);
 QuadraticCurve.prototype.constructor = QuadraticCurve;
 QuadraticCurve.prototype.constructor = QuadraticCurve;
+QuadraticCurve.prototype.type = "QuadraticCurve";
 
 
 /**
 /**
  * Create a quadratic curve helper, to edit the curve control point.
  * Create a quadratic curve helper, to edit the curve control point.
@@ -68,4 +68,20 @@ QuadraticCurve.prototype.draw = function(context, viewport, canvas)
 	context.stroke();
 	context.stroke();
 };
 };
 
 
+QuadraticCurve.prototype.serialize = function(recursive)
+{
+	var data = Line.prototype.serialize.call(this, recursive);
+
+	data.controlPoint = this.controlPoint.toArray();
+
+	return data;
+};
+
+QuadraticCurve.prototype.parse = function(data)
+{
+	Line.prototype.parse.call(this, data);
+
+	this.controlPoint.fromArray(data.controlPoint);
+};
+
 export {QuadraticCurve};
 export {QuadraticCurve};

+ 18 - 1
source/objects/RoundedBox.js

@@ -1,5 +1,4 @@
 import {Box} from "./Box";
 import {Box} from "./Box";
-import {QuadraticCurve} from "./QuadraticCurve";
 
 
 /**
 /**
  * Rounded box object draw a rectangular object with rounded corners.
  * Rounded box object draw a rectangular object with rounded corners.
@@ -21,6 +20,7 @@ function RoundedBox()
 
 
 RoundedBox.prototype = Object.create(Box.prototype);
 RoundedBox.prototype = Object.create(Box.prototype);
 RoundedBox.prototype.constructor = RoundedBox;
 RoundedBox.prototype.constructor = RoundedBox;
+RoundedBox.prototype.type = "RoundedBox";
 
 
 /**
 /**
  * Draw a rounded rectangle into the canvas context using path to draw the rounded rectangle.
  * Draw a rounded rectangle into the canvas context using path to draw the rounded rectangle.
@@ -68,4 +68,21 @@ RoundedBox.prototype.draw = function(context, viewport, canvas)
 	}
 	}
 };
 };
 
 
+RoundedBox.prototype.serialize = function(recursive)
+{
+	var data = Box.prototype.serialize.call(this, recursive);
+
+	data.radius = this.radius;
+
+	return data;
+};
+
+RoundedBox.prototype.parse = function(data)
+{
+	Box.prototype.parse.call(this, data);
+
+	this.radius = data.radius;
+};
+
+
 export {RoundedBox};
 export {RoundedBox};

+ 29 - 0
source/objects/Text.js

@@ -69,6 +69,7 @@ function Text()
 
 
 Text.prototype = Object.create(Object2D.prototype);
 Text.prototype = Object.create(Object2D.prototype);
 Text.prototype.constructor = Text;
 Text.prototype.constructor = Text;
+Text.prototype.type = "Text";
 
 
 Text.prototype.draw = function(context, viewport, canvas)
 Text.prototype.draw = function(context, viewport, canvas)
 {
 {
@@ -89,4 +90,32 @@ Text.prototype.draw = function(context, viewport, canvas)
 	}
 	}
 };
 };
 
 
+Text.prototype.serialize = function(recursive)
+{
+	var data = Object2D.prototype.serialize.call(this, recursive);
+
+	data.text = this.text;
+	data.font = this.font;
+	data.strokeStyle = this.strokeStyle;
+	data.lineWidth = this.lineWidth;
+	data.fillStyle = this.fillStyle;
+	data.textAlign = this.textAlign;
+	data.textBaseline = this.textBaseline;
+
+	return data;
+};
+
+Text.prototype.parse = function(data)
+{
+	Object2D.prototype.parse.call(this, data);
+
+	this.text = data.text;
+	this.font = data.font;
+	this.strokeStyle = data.strokeStyle;
+	this.lineWidth = data.lineWidth;
+	this.fillStyle = data.fillStyle;
+	this.textAlign = data.textAlign;
+	this.textBaseline = data.textBaseline;
+};
+
 export {Text};
 export {Text};

+ 1 - 0
source/objects/mask/BoxMask.js

@@ -32,6 +32,7 @@ function BoxMask()
 
 
 BoxMask.prototype = Object.create(Mask.prototype);
 BoxMask.prototype = Object.create(Mask.prototype);
 BoxMask.prototype.constructor = BoxMask;
 BoxMask.prototype.constructor = BoxMask;
+BoxMask.prototype.type = "BoxMask";
 
 
 BoxMask.prototype.isInside = function(point)
 BoxMask.prototype.isInside = function(point)
 {
 {

+ 1 - 0
source/objects/mask/Mask.js

@@ -20,6 +20,7 @@ function Mask()
 
 
 Mask.prototype = Object.create(Object2D.prototype);
 Mask.prototype = Object.create(Object2D.prototype);
 Mask.prototype.constructor = Mask;
 Mask.prototype.constructor = Mask;
+Mask.prototype.type = "Mask";
 Mask.prototype.isMask = true;
 Mask.prototype.isMask = true;
 
 
 /**
 /**

+ 1 - 0
source/objects/node/Node.js

@@ -35,6 +35,7 @@ function Node()
 
 
 Node.prototype = Object.create(RoundedBox.prototype);
 Node.prototype = Object.create(RoundedBox.prototype);
 Node.prototype.constructor = Node;
 Node.prototype.constructor = Node;
+Node.prototype.type = "Node";
 
 
 /**
 /**
  * This method should be used for the node to register their socket inputs/outputs.
  * This method should be used for the node to register their socket inputs/outputs.

+ 1 - 0
source/objects/node/NodeGraph.js

@@ -18,6 +18,7 @@ function NodeGraph()
 
 
 NodeGraph.prototype = Object.create(Object2D.prototype);
 NodeGraph.prototype = Object.create(Object2D.prototype);
 NodeGraph.prototype.constructor = NodeGraph;
 NodeGraph.prototype.constructor = NodeGraph;
+NodeGraph.prototype.type = "NodeGraph";
 
 
 /**
 /**
  * Create and add a new node of specific node type to the graph.
  * Create and add a new node of specific node type to the graph.

+ 6 - 5
source/objects/node/NodeSocket.js

@@ -13,10 +13,10 @@ import {NodeGraph} from "./NodeGraph";
  * @extends {Circle}
  * @extends {Circle}
  * @param {Node} node Node of this hook.
  * @param {Node} node Node of this hook.
  * @param {number} direction Direction of the hook.
  * @param {number} direction Direction of the hook.
- * @param {string} type Data type of the node socket.
+ * @param {string} category Data category of the node socket.
  * @param {string} name Name of the node socket.
  * @param {string} name Name of the node socket.
  */
  */
-function NodeSocket(node, direction, type, name)
+function NodeSocket(node, direction, category, name)
 {
 {
 	Circle.call(this);
 	Circle.call(this);
 
 
@@ -32,13 +32,13 @@ function NodeSocket(node, direction, type, name)
 	this.name = name !== undefined ? name : "";
 	this.name = name !== undefined ? name : "";
 
 
 	/**
 	/**
-	 * Type of data available from this socket. Only sockets of the same type can be connected.
+	 * Category of data available from this socket. Only sockets of the same category can be connected.
 	 *
 	 *
 	 * Should directly store the data type name (e.g. "string", "number", "Object", etc).
 	 * Should directly store the data type name (e.g. "string", "number", "Object", etc).
 	 *
 	 *
 	 * @type {string}
 	 * @type {string}
 	 */
 	 */
-	this.type = type !== undefined ? type : "";
+	this.category = category !== undefined ? category : "";
 
 
 	/**
 	/**
 	 * Direction of the node hook, indicates the data flow of the socket.
 	 * Direction of the node hook, indicates the data flow of the socket.
@@ -91,6 +91,7 @@ function NodeSocket(node, direction, type, name)
 
 
 NodeSocket.prototype = Object.create(Circle.prototype);
 NodeSocket.prototype = Object.create(Circle.prototype);
 NodeSocket.prototype.constructor = NodeSocket;
 NodeSocket.prototype.constructor = NodeSocket;
+NodeSocket.prototype.type = "NodeSocket";
 
 
 /**
 /**
  * Input hook can only be connected to an output.
  * Input hook can only be connected to an output.
@@ -187,7 +188,7 @@ NodeSocket.prototype.attachConnector = function(connector)
  */
  */
 NodeSocket.prototype.isCompatible = function(socket)
 NodeSocket.prototype.isCompatible = function(socket)
 {
 {
-	return this.direction !== socket.direction && this.type === socket.type;
+	return this.direction !== socket.direction && this.category === socket.category;
 };
 };
 
 
 NodeSocket.prototype.destroy = function()
 NodeSocket.prototype.destroy = function()

Some files were not shown because too many files changed in this diff