tentone 5 роки тому
батько
коміт
0b35ac7756

+ 210 - 43
build/escher.js

@@ -707,6 +707,9 @@
 
 	/**
 	 * Apply skew to this matrix.
+	 *
+	 * @param {number} radianX
+	 * @param {number} radianY
 	 */
 	Matrix.prototype.skew = function(radianX, radianY)
 	{
@@ -3148,6 +3151,126 @@
 		context.clip();
 	};
 
+	/**
+	 * Style represents in a generic way a style applied to canvas drawing.
+	 *
+	 * Some styles (e.g. gradients, patterns) required a context to be generated this provides a generic way to share styles between objects.
+	 *
+	 * @class
+	 */
+	function Style$1()
+	{
+	    /**
+	     * Cached style object pre-generated from previous calls. To avoid regenerating the same style object every cycle.
+	     *
+	     * @type {string | CanvasGradient | CanvasPattern}
+	     */
+	    this.cache = null;
+	    // TODO <USE THIS>
+
+	    /**
+	     * Indicates if the style object needs to be updated, should be used after applying changed to the style in order to generate a new object.
+	     *
+	     * @type {boolean}
+	     */
+	    this.needsUpdate = true;
+	    // TODO <USE THIS>
+	}
+
+	/**
+	 * Get generated style object from style data and the drawing context.
+	 *
+	 * @param {CanvasRenderingContext2D} context Context being used to draw the object.
+	 * @return {string | CanvasGradient | CanvasPattern} Return the canvas style object generated.
+	 */
+	Style$1.prototype.get = function(context) {};
+
+	/**
+	 * Serialize the style to JSON object, called by the objects using these styles.
+	 *
+	 * @return {Object} Serialized style data.
+	 */
+	Style$1.prototype.serialize = function() {};
+
+	/**
+	 * Parse the style attributes from JSON object data created with the serialize() method.
+	 *
+	 * @param {Object} data Serialized style data.
+	 */
+	Style$1.prototype.parse = function(data) {};
+
+	/**
+	 * List of available style types known by the application. Stores the object constructor by object type.
+	 *
+	 * @static
+	 * @type {Map<string, Function>}
+	 */
+	Style$1.types = new Map([]);
+
+	/**
+	 * Register a style type to be serializable. Associates the type string to the object constructor.
+	 *
+	 * @param {Function} constructor Style constructor.
+	 * @param {string} type Style type name.
+	 */
+	Style$1.register = function(constructor, type)
+	{
+	    Style$1.types.set(type, constructor);
+	};
+
+	/**
+	 * Parse style from JSON serialized data, created a style of the correct data type automatically and parses its data.
+	 *
+	 * @param data JSON serialized data.
+	 * @returns {Style} Parsed style from the provided data.
+	 */
+	Style$1.parse = function (data)
+	{
+	    var style = new (Style$1.types.get(data.type))();
+	    style.parse(data);
+	    return style;
+	};
+
+	/**
+	 * Simple solid color style represented and stored as a CSS color.
+	 *
+	 * @class
+	 * @extends {Style}
+	 * @param {string} color Color of the style, if undefined it is set to black.
+	 */
+	function ColorStyle(color)
+	{
+	    Style$1.call(this);
+
+	    /**
+	     * Color of this style object.
+	     *
+	     * @type {string}
+	     */
+	    this.color = color || "#000000";
+	}
+
+	ColorStyle.prototype = Object.create(Style$1.prototype);
+	Style$1.register(ColorStyle, "Color");
+
+	ColorStyle.prototype.get = function(context)
+	{
+	    return this.color;
+	};
+
+	ColorStyle.prototype.serialize = function()
+	{
+	    return {
+	        type: "Color",
+	        color: this.color
+	    };
+	};
+
+	ColorStyle.prototype.parse = function(data)
+	{
+	    this.color = data.color;
+	};
+
 	/**
 	 * Box object draw a rectangular object.
 	 *
@@ -3170,7 +3293,7 @@
 		 *
 		 * If set null it is ignored.
 		 */
-		this.strokeStyle = "#000000";
+		this.strokeStyle = new ColorStyle("#000000");
 
 		/**
 		 * Line width, only used if a valid strokeStyle is defined.
@@ -3181,8 +3304,10 @@
 		 * Background color of the box.
 		 *
 		 * If set null it is ignored.
+		 *
+		 * @param {Style}
 		 */
-		this.fillStyle = "#FFFFFF";
+		this.fillStyle = new ColorStyle("#FFFFFF");
 	}
 
 	Box.prototype = Object.create(Object2D.prototype);
@@ -3192,12 +3317,12 @@
 
 	Box.prototype.onPointerEnter = function(pointer, viewport)
 	{
-		this.fillStyle = "#CCCCCC";
+		this.fillStyle = new ColorStyle("#CCCCCC");
 	};
 
 	Box.prototype.onPointerLeave = function(pointer, viewport)
 	{
-		this.fillStyle = "#FFFFFF";
+		this.fillStyle = new ColorStyle("#FFFFFF");
 	};
 
 	Box.prototype.isInside = function(point)
@@ -3212,14 +3337,14 @@
 
 		if(this.fillStyle !== null)
 		{	
-			context.fillStyle = this.fillStyle;
+			context.fillStyle = this.fillStyle.get();
 			context.fillRect(this.box.min.x, this.box.min.y, width, height);
 		}
 
 		if(this.strokeStyle !== null)
 		{
 			context.lineWidth = this.lineWidth;
-			context.strokeStyle = this.strokeStyle;
+			context.strokeStyle = this.strokeStyle.get();
 			context.strokeRect(this.box.min.x, this.box.min.y, width, height);
 		}
 	};
@@ -3229,9 +3354,9 @@
 		var data = Object2D.prototype.serialize.call(this, recursive);
 
 		data.box = this.box.toArray();
-		data.strokeStyle = this.strokeStyle;
+		data.strokeStyle = this.strokeStyle.serialize();
 		data.lineWidth = this.lineWidth;
-		data.fillStyle = this.fillStyle;
+		data.fillStyle = this.fillStyle.serialize();
 
 		return data;
 	};
@@ -3241,9 +3366,9 @@
 		Object2D.prototype.parse.call(this, data, root);
 
 		this.box.fromArray(data.box);
-		this.strokeStyle = data.strokeStyle;
+		this.strokeStyle = Style$1.parse(data.strokeStyle);
 		this.lineWidth = data.lineWidth;
-		this.fillStyle = data.fillStyle;
+		this.fillStyle = Style$1.parse(data.fillStyle);
 	};
 
 	/**
@@ -3267,11 +3392,15 @@
 		 * Style of the object border line.
 		 *
 		 * If set null it is ignored.
+		 *
+		 * @type {Style}
 		 */
-		this.strokeStyle = "#000000";
+		this.strokeStyle = new ColorStyle("#000000");
 
 		/**
 		 * Line width, only used if a valid strokeStyle is defined.
+		 *
+		 * @type {number}
 		 */
 		this.lineWidth = 1;
 
@@ -3279,8 +3408,10 @@
 		 * Background color of the circle.
 		 *
 		 * If set null it is ignored.
+		 *
+		 * @type {Style}
 		 */
-		this.fillStyle = "#FFFFFF";
+		this.fillStyle = new ColorStyle("#FFFFFF");
 	}
 
 	Circle.prototype = Object.create(Object2D.prototype);
@@ -3295,12 +3426,12 @@
 
 	Circle.prototype.onPointerEnter = function(pointer, viewport)
 	{
-		this.fillStyle = "#CCCCCC";
+		this.fillStyle = new ColorStyle("#CCCCCC");
 	};
 
 	Circle.prototype.onPointerLeave = function(pointer, viewport)
 	{
-		this.fillStyle = "#FFFFFF";
+		this.fillStyle = new ColorStyle("#FFFFFF");
 	};
 
 	Circle.prototype.draw = function(context, viewport, canvas)
@@ -3310,14 +3441,14 @@
 		
 		if(this.fillStyle !== null)
 		{	
-			context.fillStyle = this.fillStyle;
+			context.fillStyle = this.fillStyle.get();
 			context.fill();
 		}
 
 		if(this.strokeStyle !== null)
 		{
 			context.lineWidth = this.lineWidth;
-			context.strokeStyle = this.strokeStyle;
+			context.strokeStyle = this.strokeStyle.get();
 			context.stroke();
 		}
 	};
@@ -3327,9 +3458,9 @@
 		var data = Object2D.prototype.serialize.call(this, recursive);
 
 		data.radius = this.radius;
-		data.strokeStyle = this.strokeStyle;
+		data.strokeStyle = this.strokeStyle.serialize();
 		data.lineWidth = this.lineWidth;
-		data.fillStyle = this.fillStyle;
+		data.fillStyle = this.fillStyle.serialize();
 
 		return data;
 	};
@@ -3339,9 +3470,9 @@
 		Object2D.prototype.parse.call(this, data, root);
 
 		this.radius = data.radius;
-		this.strokeStyle = data.strokeStyle;
+		this.strokeStyle = Style$1.parse(data.strokeStyle);
 		this.lineWidth = data.lineWidth;
-		this.fillStyle = data.fillStyle;
+		this.fillStyle = Style$1.parse(data.fillStyle);
 	};
 
 	/**
@@ -3388,9 +3519,9 @@
 		/**
 		 * Style of the object line.
 		 *
-		 * @type {string}
+		 * @type {Style}
 		 */
-		this.strokeStyle = "#000000";
+		this.strokeStyle = new ColorStyle("#000000");
 
 		/**
 		 * Line width of the line.
@@ -3408,7 +3539,7 @@
 	Line.prototype.style = function(context, viewport, canvas)
 	{
 		context.lineWidth = this.lineWidth;
-		context.strokeStyle = this.strokeStyle;
+		context.strokeStyle = this.strokeStyle.get();
 		context.setLineDash(this.dashPattern);
 	};
 
@@ -3427,7 +3558,7 @@
 		data.from = this.from.toArray();
 		data.to = this.to.toArray();
 		data.dashPattern = this.dashPattern;
-		data.strokeStyle = this.strokeStyle;
+		data.strokeStyle = this.strokeStyle.serialize();
 		data.lineWidth = this.lineWidth;
 
 		return data;
@@ -3440,7 +3571,7 @@
 		this.to.fromArray(data.to);
 		this.from.fromArray(data.from);
 		this.dashPattern = data.dashPattern;
-		this.strokeStyle = data.strokeStyle;
+		this.strokeStyle = Style$1.parse(data.strokeStyle);
 		this.lineWidth = data.lineWidth;
 	};
 
@@ -3473,7 +3604,7 @@
 		/**
 		 * Style of the object border line. If set null it is ignored.
 		 *
-		 * @type {string}
+		 * @type {Style}
 		 */
 		this.strokeStyle = null;
 
@@ -3487,9 +3618,9 @@
 		/**
 		 * CSS background color of the box. If set null it is ignored.
 		 *
-		 * @type {string}
+		 * @type {Style}
 		 */
-		this.fillStyle = "#000000";
+		this.fillStyle = new ColorStyle("#000000");
 
 		/**
 		 * Text align property. Same values as used for canvas text applies
@@ -3519,17 +3650,17 @@
 	{
 		context.font = this.font;
 		context.textAlign = this.textAlign;
-		context.textBaseline = this.textBaseline ;
+		context.textBaseline = this.textBaseline;
 		
 		if(this.fillStyle !== null)
 		{
-			context.fillStyle = this.fillStyle;
+			context.fillStyle = this.fillStyle.get();
 			context.fillText(this.text, 0, 0);
 		}
 
 		if(this.strokeStyle !== null)
 		{
-			context.strokeStyle = this.strokeStyle;
+			context.strokeStyle = this.strokeStyle.get();
 			context.strokeText(this.text, 0, 0);
 		}
 	};
@@ -3540,9 +3671,9 @@
 
 		data.text = this.text;
 		data.font = this.font;
-		data.strokeStyle = this.strokeStyle;
+		data.strokeStyle = this.strokeStyle.serialize();
 		data.lineWidth = this.lineWidth;
-		data.fillStyle = this.fillStyle;
+		data.fillStyle = this.fillStyle.serialize();
 		data.textAlign = this.textAlign;
 		data.textBaseline = this.textBaseline;
 
@@ -3555,9 +3686,9 @@
 
 		this.text = data.text;
 		this.font = data.font;
-		this.strokeStyle = data.strokeStyle;
+		this.strokeStyle = Style.parse(data.strokeStyle);
 		this.lineWidth = data.lineWidth;
-		this.fillStyle = data.fillStyle;
+		this.fillStyle = Style.parse(data.fillStyle);
 		this.textAlign = data.textAlign;
 		this.textBaseline = data.textBaseline;
 	};
@@ -3958,13 +4089,13 @@
 			{
 				if(this.fillStyle !== null)
 				{
-					context.fillStyle = this.fillStyle;
+					context.fillStyle = this.fillStyle.get();
 					context.fillText(sublines[j], this.position.x, this.position.y + offsetY);
 				}
 
 				if(this.strokeStyle !== null)
 				{
-					context.strokeStyle = this.strokeStyle;
+					context.strokeStyle = this.strokeStyle.get();
 					context.strokeText(sublines[j], this.position.x, this.position.y + offsetY);
 				}
 
@@ -4227,7 +4358,7 @@
 
 		if(this.fillStyle !== null)
 		{	
-			context.fillStyle = this.fillStyle;
+			context.fillStyle = this.fillStyle.get();
 			RoundedBox.roundRect(context, this.box.min.x, this.box.min.y, width, height, this.radius);
 			context.fill();
 		}
@@ -4235,7 +4366,7 @@
 		if(this.strokeStyle !== null)
 		{
 			context.lineWidth = this.lineWidth;
-			context.strokeStyle = this.strokeStyle;
+			context.strokeStyle = this.strokeStyle.get();
 			RoundedBox.roundRect(context, this.box.min.x, this.box.min.y, width, height, this.radius);
 			context.stroke();
 		}
@@ -4393,9 +4524,25 @@
 	{
 		Object2D.call(this);
 
+		/**
+		 * Value displayed by this gauge. It is displayed based on min and max values.
+		 *
+		 * @type {number}
+		 */
 		this.value = 50;
 
+		/**
+		 * Minimum value of the gauge. Necessary to display the value correctly to scale.
+		 *
+		 * @type {number}
+		 */
 		this.min = 0;
+
+		/**
+		 * Maximum value of the gauge. Necessary to display the value correctly to scale.
+		 *
+		 * @type {number}
+		 */
 		this.max = 100;
 
 		/**
@@ -4405,11 +4552,26 @@
 		 */
 		this.radius = 80;
 
+		/**
+		 * The line width of the gauge semi-circle.
+		 *
+		 * @type {number}
+		 */
 		this.lineWidth = 10;
 
+		/**
+		 * Start angle of the gauge.
+		 *
+		 * @type {number}
+		 */
 		this.startAngle = Math.PI;
-		this.endAngle = 2 * Math.PI;
 
+		/**
+		 * End angle of the gauge.
+		 *
+		 * @type {number}
+		 */
+		this.endAngle = 2 * Math.PI;
 
 		/**
 		 * If true draw a circular dial at the end of the gauge bar.
@@ -4418,7 +4580,12 @@
 		 */
 		this.dial = false;
 
-		this.baseStyle = "#e9ecf1";
+		/**
+		 * Style of the base of the gauge object, (the background of the gauge bar).
+		 *
+		 * @type {Style}
+		 */
+		this.baseStyle = new ColorStyle("#e9ecf1");
 	}
 
 	Gauge.prototype = Object.create(Object2D.prototype);
@@ -4443,13 +4610,13 @@
 		//Back
 		context.lineWidth = this.lineWidth;
 		context.lineCap = "round";
-		context.strokeStyle = this.baseStyle;
+		context.strokeStyle = this.baseStyle.get();
 		context.beginPath();
 		context.arc(center[0], center[1], this.radius, range[0], range[1]);
 		context.stroke();
 
 		// Fill gradient
-		var gradient = context.createLinearGradient(0, 0, width, 0);
+		var gradient = context.createLinearGradient(-this.radius, 0, this.radius, 0);
 		gradient.addColorStop(0, "#61ff50");
 		gradient.addColorStop(0.5, "#ffbb50");
 		gradient.addColorStop(1, "#ff3269");

+ 2 - 2
examples/playground.html

@@ -227,8 +227,8 @@
 		text.text = "Double-click to center!";
 		text.font = "30px Comic Sans MS";
 		text.position.set(0, -75);
-		text.strokeStyle = "#000000";
-		text.fillStyle = "#FFFFFF";
+		text.strokeStyle = new Escher.ColorStyle("#000000");
+		text.fillStyle = new Escher.ColorStyle("#FFFFFF");
 		circle.add(text);
 
 		// Line (connection)

+ 8 - 0
source/Escher.js

@@ -27,6 +27,14 @@ export {RoundedBox} from "./objects/RoundedBox.js";
 export {Graph} from "./objects/chart/Graph.js";
 export {Gauge} from "./objects/chart/Gauge.js";
 
+export {Style} from "./objects/style/Style.js";
+export {ColorStyle} from "./objects/style/ColorStyle.js";
+export {PatternStyle} from "./objects/style/PatternStyle.js";
+export {GradientStyle} from "./objects/style/GradientStyle.js";
+export {GradientColorStop} from "./objects/style/GradientColorStop.js";
+export {LinearGradientStyle} from "./objects/style/LinearGradientStyle.js";
+export {RadialGradientStyle} from "./objects/style/RadialGradientStyle.js";
+
 export {Node} from "./objects/node/Node.js";
 export {NodeConnector} from "./objects/node/NodeConnector.js";
 export {NodeSocket} from "./objects/node/NodeSocket.js";

+ 3 - 0
source/math/Matrix.js

@@ -205,6 +205,9 @@ Matrix.prototype.getPosition = function()
 
 /**
  * Apply skew to this matrix.
+ *
+ * @param {number} radianX
+ * @param {number} radianY
  */
 Matrix.prototype.skew = function(radianX, radianY)
 {

+ 2 - 0
source/objects/Box.js

@@ -37,6 +37,8 @@ function Box()
 	 * Background color of the box.
 	 *
 	 * If set null it is ignored.
+	 *
+	 * @param {Style}
 	 */
 	this.fillStyle = new ColorStyle("#FFFFFF");
 }

+ 18 - 10
source/objects/Circle.js

@@ -1,4 +1,6 @@
 import {Object2D} from "../Object2D.js";
+import {ColorStyle} from "./style/ColorStyle";
+import {Style} from "./style/Style";
 
 /**
  * Circle object draw a circular object, into the canvas.
@@ -21,11 +23,15 @@ function Circle()
 	 * Style of the object border line.
 	 *
 	 * If set null it is ignored.
+	 *
+	 * @type {Style}
 	 */
-	this.strokeStyle = "#000000";
+	this.strokeStyle = new ColorStyle("#000000");
 
 	/**
 	 * Line width, only used if a valid strokeStyle is defined.
+	 *
+	 * @type {number}
 	 */
 	this.lineWidth = 1;
 
@@ -33,8 +39,10 @@ function Circle()
 	 * Background color of the circle.
 	 *
 	 * If set null it is ignored.
+	 *
+	 * @type {Style}
 	 */
-	this.fillStyle = "#FFFFFF";
+	this.fillStyle = new ColorStyle("#FFFFFF");
 }
 
 Circle.prototype = Object.create(Object2D.prototype);
@@ -49,12 +57,12 @@ Circle.prototype.isInside = function(point)
 
 Circle.prototype.onPointerEnter = function(pointer, viewport)
 {
-	this.fillStyle = "#CCCCCC";
+	this.fillStyle = new ColorStyle("#CCCCCC");
 };
 
 Circle.prototype.onPointerLeave = function(pointer, viewport)
 {
-	this.fillStyle = "#FFFFFF";
+	this.fillStyle = new ColorStyle("#FFFFFF");
 };
 
 Circle.prototype.draw = function(context, viewport, canvas)
@@ -64,14 +72,14 @@ Circle.prototype.draw = function(context, viewport, canvas)
 	
 	if(this.fillStyle !== null)
 	{	
-		context.fillStyle = this.fillStyle;
+		context.fillStyle = this.fillStyle.get();
 		context.fill();
 	}
 
 	if(this.strokeStyle !== null)
 	{
 		context.lineWidth = this.lineWidth;
-		context.strokeStyle = this.strokeStyle;
+		context.strokeStyle = this.strokeStyle.get();
 		context.stroke();
 	}
 };
@@ -81,9 +89,9 @@ Circle.prototype.serialize = function(recursive)
 	var data = Object2D.prototype.serialize.call(this, recursive);
 
 	data.radius = this.radius;
-	data.strokeStyle = this.strokeStyle;
+	data.strokeStyle = this.strokeStyle.serialize();
 	data.lineWidth = this.lineWidth;
-	data.fillStyle = this.fillStyle;
+	data.fillStyle = this.fillStyle.serialize();
 
 	return data;
 };
@@ -93,9 +101,9 @@ Circle.prototype.parse = function(data, root)
 	Object2D.prototype.parse.call(this, data, root);
 
 	this.radius = data.radius;
-	this.strokeStyle = data.strokeStyle;
+	this.strokeStyle = Style.parse(data.strokeStyle);
 	this.lineWidth = data.lineWidth;
-	this.fillStyle = data.fillStyle;
+	this.fillStyle = Style.parse(data.fillStyle);
 };
 
 export {Circle};

+ 7 - 5
source/objects/Line.js

@@ -1,5 +1,7 @@
 import {Object2D} from "../Object2D.js";
 import {Vector2} from "../math/Vector2.js";
+import {ColorStyle} from "./style/ColorStyle";
+import {Style} from "./style/Style";
 
 /**
  * Line object draw a line from one point to another without any kind of interpolation.
@@ -45,9 +47,9 @@ function Line()
 	/**
 	 * Style of the object line.
 	 *
-	 * @type {string}
+	 * @type {Style}
 	 */
-	this.strokeStyle = "#000000";
+	this.strokeStyle = new ColorStyle("#000000");
 
 	/**
 	 * Line width of the line.
@@ -65,7 +67,7 @@ Object2D.register(Line, "Line");
 Line.prototype.style = function(context, viewport, canvas)
 {
 	context.lineWidth = this.lineWidth;
-	context.strokeStyle = this.strokeStyle;
+	context.strokeStyle = this.strokeStyle.get();
 	context.setLineDash(this.dashPattern);
 };
 
@@ -84,7 +86,7 @@ Line.prototype.serialize = function(recursive)
 	data.from = this.from.toArray();
 	data.to = this.to.toArray();
 	data.dashPattern = this.dashPattern;
-	data.strokeStyle = this.strokeStyle;
+	data.strokeStyle = this.strokeStyle.serialize();
 	data.lineWidth = this.lineWidth;
 
 	return data;
@@ -97,7 +99,7 @@ Line.prototype.parse = function(data, root)
 	this.to.fromArray(data.to);
 	this.from.fromArray(data.from);
 	this.dashPattern = data.dashPattern;
-	this.strokeStyle = data.strokeStyle;
+	this.strokeStyle = Style.parse(data.strokeStyle);
 	this.lineWidth = data.lineWidth;
 };
 

+ 2 - 2
source/objects/MultiLineText.js

@@ -83,13 +83,13 @@ MultiLineText.prototype.draw = function(context, viewport, canvas)
 		{
 			if(this.fillStyle !== null)
 			{
-				context.fillStyle = this.fillStyle;
+				context.fillStyle = this.fillStyle.get();
 				context.fillText(sublines[j], this.position.x, this.position.y + offsetY);
 			}
 
 			if(this.strokeStyle !== null)
 			{
-				context.strokeStyle = this.strokeStyle;
+				context.strokeStyle = this.strokeStyle.get();
 				context.strokeText(sublines[j], this.position.x, this.position.y + offsetY);
 			}
 

+ 2 - 2
source/objects/RoundedBox.js

@@ -56,7 +56,7 @@ RoundedBox.prototype.draw = function(context, viewport, canvas)
 
 	if(this.fillStyle !== null)
 	{	
-		context.fillStyle = this.fillStyle;
+		context.fillStyle = this.fillStyle.get();
 		RoundedBox.roundRect(context, this.box.min.x, this.box.min.y, width, height, this.radius);
 		context.fill();
 	}
@@ -64,7 +64,7 @@ RoundedBox.prototype.draw = function(context, viewport, canvas)
 	if(this.strokeStyle !== null)
 	{
 		context.lineWidth = this.lineWidth;
-		context.strokeStyle = this.strokeStyle;
+		context.strokeStyle = this.strokeStyle.get();
 		RoundedBox.roundRect(context, this.box.min.x, this.box.min.y, width, height, this.radius);
 		context.stroke();
 	}

+ 11 - 10
source/objects/Text.js

@@ -1,4 +1,5 @@
 import {Object2D} from "../Object2D.js";
+import {ColorStyle} from "./style/ColorStyle";
 
 /**
  * Text element, used to draw single line text into the canvas.
@@ -29,7 +30,7 @@ function Text()
 	/**
 	 * Style of the object border line. If set null it is ignored.
 	 *
-	 * @type {string}
+	 * @type {Style}
 	 */
 	this.strokeStyle = null;
 
@@ -43,9 +44,9 @@ function Text()
 	/**
 	 * CSS background color of the box. If set null it is ignored.
 	 *
-	 * @type {string}
+	 * @type {Style}
 	 */
-	this.fillStyle = "#000000";
+	this.fillStyle = new ColorStyle("#000000");
 
 	/**
 	 * Text align property. Same values as used for canvas text applies
@@ -75,17 +76,17 @@ Text.prototype.draw = function(context, viewport, canvas)
 {
 	context.font = this.font;
 	context.textAlign = this.textAlign;
-	context.textBaseline = this.textBaseline ;
+	context.textBaseline = this.textBaseline;
 	
 	if(this.fillStyle !== null)
 	{
-		context.fillStyle = this.fillStyle;
+		context.fillStyle = this.fillStyle.get();
 		context.fillText(this.text, 0, 0);
 	}
 
 	if(this.strokeStyle !== null)
 	{
-		context.strokeStyle = this.strokeStyle;
+		context.strokeStyle = this.strokeStyle.get();
 		context.strokeText(this.text, 0, 0);
 	}
 };
@@ -96,9 +97,9 @@ Text.prototype.serialize = function(recursive)
 
 	data.text = this.text;
 	data.font = this.font;
-	data.strokeStyle = this.strokeStyle;
+	data.strokeStyle = this.strokeStyle.serialize();
 	data.lineWidth = this.lineWidth;
-	data.fillStyle = this.fillStyle;
+	data.fillStyle = this.fillStyle.serialize();
 	data.textAlign = this.textAlign;
 	data.textBaseline = this.textBaseline;
 
@@ -111,9 +112,9 @@ Text.prototype.parse = function(data, root)
 
 	this.text = data.text;
 	this.font = data.font;
-	this.strokeStyle = data.strokeStyle;
+	this.strokeStyle = Style.parse(data.strokeStyle);
 	this.lineWidth = data.lineWidth;
-	this.fillStyle = data.fillStyle;
+	this.fillStyle = Style.parse(data.fillStyle);
 	this.textAlign = data.textAlign;
 	this.textBaseline = data.textBaseline;
 };

+ 40 - 3
source/objects/chart/Gauge.js

@@ -1,4 +1,5 @@
 import {Object2D} from "../../Object2D.js";
+import {ColorStyle} from "../style/ColorStyle";
 
 /**
  * Gauge object is used to draw gauge like graphic.
@@ -12,9 +13,25 @@ function Gauge()
 {
 	Object2D.call(this);
 
+	/**
+	 * Value displayed by this gauge. It is displayed based on min and max values.
+	 *
+	 * @type {number}
+	 */
 	this.value = 50;
 
+	/**
+	 * Minimum value of the gauge. Necessary to display the value correctly to scale.
+	 *
+	 * @type {number}
+	 */
 	this.min = 0;
+
+	/**
+	 * Maximum value of the gauge. Necessary to display the value correctly to scale.
+	 *
+	 * @type {number}
+	 */
 	this.max = 100;
 
 	/**
@@ -24,11 +41,26 @@ function Gauge()
 	 */
 	this.radius = 80;
 
+	/**
+	 * The line width of the gauge semi-circle.
+	 *
+	 * @type {number}
+	 */
 	this.lineWidth = 10;
 
+	/**
+	 * Start angle of the gauge.
+	 *
+	 * @type {number}
+	 */
 	this.startAngle = Math.PI;
-	this.endAngle = 2 * Math.PI;
 
+	/**
+	 * End angle of the gauge.
+	 *
+	 * @type {number}
+	 */
+	this.endAngle = 2 * Math.PI;
 
 	/**
 	 * If true draw a circular dial at the end of the gauge bar.
@@ -37,7 +69,12 @@ function Gauge()
 	 */
 	this.dial = false;
 
-	this.baseStyle = "#e9ecf1";
+	/**
+	 * Style of the base of the gauge object, (the background of the gauge bar).
+	 *
+	 * @type {Style}
+	 */
+	this.baseStyle = new ColorStyle("#e9ecf1");
 }
 
 Gauge.prototype = Object.create(Object2D.prototype);
@@ -62,7 +99,7 @@ Gauge.prototype.draw = function(context, viewport, canvas)
 	//Back
 	context.lineWidth = this.lineWidth;
 	context.lineCap = "round";
-	context.strokeStyle = this.baseStyle;
+	context.strokeStyle = this.baseStyle.get();
 	context.beginPath();
 	context.arc(center[0], center[1], this.radius, range[0], range[1]);
 	context.stroke();

+ 2 - 0
source/objects/style/ColorStyle.js

@@ -9,6 +9,8 @@ import {Style} from "./Style";
  */
 function ColorStyle(color)
 {
+    Style.call(this);
+
     /**
      * Color of this style object.
      *

+ 27 - 0
source/objects/style/GradientColorStop.js

@@ -0,0 +1,27 @@
+/**
+ * Gradient color stop is used to create the gradients by their color sections.
+ *
+ * The gradients are ordered, each stop has a target color that becomes solid on its offset value triggering the next color stop if there is one.
+ *
+ * @param offset Offset of the color stop between 0 and 1 inclusive.
+ * @param color CSS color value.
+ * @constructor
+ */
+function GradientColorStop(offset, color)
+{
+    /**
+     * Offset of the color stop between 0 and 1 inclusive.
+     *
+     * @type {number}
+     */
+    this.offset = offset;
+
+    /**
+     * CSS color value.
+     *
+     * @type {string}
+     */
+    this.color = color;
+}
+
+export {GradientColorStop};

+ 4 - 28
source/objects/style/GradientStyle.js

@@ -1,5 +1,5 @@
 import {Style} from "./Style";
-import {RadialGradientStyle} from "./RadialGradientStyle";
+import {GradientColorStop} from "./GradientColorStop";
 
 /**
  * Gradient style is used to represent any type of gradient based style.
@@ -11,6 +11,8 @@ import {RadialGradientStyle} from "./RadialGradientStyle";
  */
 function GradientStyle()
 {
+    Style.call(this);
+
     /**
      * List of colors that compose this gradient ordered.
      *
@@ -21,32 +23,6 @@ function GradientStyle()
     this.colors = [];
 }
 
-/**
- * Gradient color stop is used to create the gradients by their color sections.
- *
- * The gradients are ordered, each stop has a target color that becomes solid on its offset value triggering the next color stop if there is one.
- *
- * @param offset Offset of the color stop between 0 and 1 inclusive.
- * @param color CSS color value.
- * @constructor
- */
-function GradientColorStop(offset, color)
-{
-    /**
-     * Offset of the color stop between 0 and 1 inclusive.
-     *
-     * @type {number}
-     */
-    this.offset = offset;
-
-    /**
-     * CSS color value.
-     *
-     * @type {string}
-     */
-    this.color = color;
-}
-
 GradientStyle.prototype = Object.create(Style.prototype);
 
 /**
@@ -80,4 +56,4 @@ GradientStyle.prototype.parse = function(data)
 };
 
 
-export {GradientStyle, GradientColorStop};
+export {GradientStyle};

+ 10 - 10
source/objects/style/LinearGradientStyle.js

@@ -35,16 +35,14 @@ Style.register(LinearGradientStyle, "LinearGradient");
 
 LinearGradientStyle.prototype.get = function(context)
 {
-    return context.createLinearGradient(this.start.x, this.start.y, this.end.x, this.end.y);
-};
+    var style = context.createLinearGradient(this.start.x, this.start.y, this.end.x, this.end.y);
 
-LinearGradientStyle.prototype.serialize = function ()
-{
-    return {
-        type: "LinearGradient",
-        start: this.start.toArray(),
-        end: this.end.toArray()
-    };
+    for(var i = 0; i < this.colors.length; i++)
+    {
+        style.addColorStop(this.colors[i].offset, this.colors[i].color);
+    }
+
+    return style;
 };
 
 LinearGradientStyle.prototype.serialize = function ()
@@ -52,7 +50,9 @@ LinearGradientStyle.prototype.serialize = function ()
     var data = GradientStyle.prototype.serialize.call(this);
 
     Object.assign(data, {
-        type: "LinearGradient"
+        type: "LinearGradient",
+        start: this.start.toArray(),
+        end: this.end.toArray()
     });
 
     return data;

+ 20 - 6
source/objects/style/PatternStyle.js

@@ -1,4 +1,5 @@
 import {Style} from "./Style";
+import {GradientStyle} from "./GradientStyle";
 
 /**
  * Pattern style represents an opaque object describing a pattern, based on an image, a canvas, or a video.
@@ -11,6 +12,8 @@ import {Style} from "./Style";
  */
 function PatternStyle(source)
 {
+    Style.call(this);
+
     /**
      * Source of the pattern style. Can be a image, video or another canvas element
      *
@@ -38,7 +41,7 @@ function PatternStyle(source)
      *
      * @type {Matrix}
      */
-    this.transform = new Matrix();
+    this.matrix = new Matrix();
 }
 
 PatternStyle.prototype = Object.create(Style.prototype);
@@ -57,20 +60,31 @@ PatternStyle.prototype.setTransform = function(transform)
 PatternStyle.prototype.get = function(context)
 {
     var style = context.createPattern(this.source, this.repetition);
-
-    // style.setTransform(this.transform);
-
+    style.setTransform(this.matrix.cssTransform());
     return style;
 };
 
 PatternStyle.prototype.serialize = function ()
 {
-    // TODO <ADD CODE HERE>
+    var data = GradientStyle.prototype.serialize.call(this);
+
+    Object.assign(data, {
+        type: "Pattern",
+        matrix: this.matrix.m,
+        repetition: this.repetition,
+        source: this.source
+    });
+
+    return data;
 };
 
 PatternStyle.prototype.parse = function (data)
 {
-    // TODO <ADD CODE HERE>
+    GradientStyle.prototype.parse.call(this, data);
+
+    this.matrix = new Matrix(data.matrix);
+    this.repetition = data.repetition;
+    this.source = data.source;
 };
 
 export {PatternStyle};

+ 8 - 1
source/objects/style/RadialGradientStyle.js

@@ -49,7 +49,14 @@ Style.register(RadialGradientStyle, "RadialGradient");
 
 RadialGradientStyle.prototype.get = function(context)
 {
-    return context.createRadialGradient(this.start.x, this.start.y, this.startRadius, this.end.x, this.end.y, this.endRadius);
+    var style = context.createRadialGradient(this.start.x, this.start.y, this.startRadius, this.end.x, this.end.y, this.endRadius);
+
+    for(var i = 0; i < this.colors.length; i++)
+    {
+        style.addColorStop(this.colors[i].offset, this.colors[i].color);
+    }
+
+    return style;
 };
 
 RadialGradientStyle.prototype.serialize = function ()