tentone 5 ani în urmă
părinte
comite
dbbf8e9b0d

+ 239 - 124
build/escher.js

@@ -3876,130 +3876,6 @@
 		this.repetition = data.repetition;
 	};
 
-	/**
-	 * Graph object is used to draw simple graph data into the canvas.
-	 *
-	 * Graph data is composed of X, Y values.
-	 *
-	 * @class
-	 * @extends {Object2D}
-	 */
-	function Graph()
-	{
-		Object2D.call(this);
-
-		/**
-		 * Graph object containing the size of the object.
-		 */
-		this.box = new Box2(new Vector2(-50, -35), new Vector2(50, 35));
-
-		/**
-		 * Color of the box border line.
-		 */
-		this.strokeStyle = "rgb(0, 153, 255)";
-
-		/**
-		 * Line width.
-		 */
-		this.lineWidth = 1;
-
-		/**
-		 * Background color of the box.
-		 */
-		this.fillStyle = "rgba(0, 153, 255, 0.3)";
-
-		/**
-		 * Minimum value of the graph.
-		 */
-		this.min = 0;
-
-		/**
-		 * Maximum value of the graph.
-		 */
-		this.max = 10;
-
-		/**
-		 * Data to be presented in the graph.
-		 *
-		 * The array should store numeric values.
-		 */
-		this.data = [];
-	}
-
-	Graph.prototype = Object.create(Object2D.prototype);
-	Graph.prototype.constructor = Graph;
-	Graph.prototype.type = "Graph";
-	Object2D.register(Graph, "Graph");
-
-	Graph.prototype.isInside = function(point)
-	{
-		return this.box.containsPoint(point);
-	};
-
-	Graph.prototype.draw = function(context, viewport, canvas)
-	{
-		if(this.data.length === 0)
-		{
-			return;
-		}
-		
-		var width = this.box.max.x - this.box.min.x;
-		var height = this.box.max.y - this.box.min.y;
-
-		context.lineWidth = this.lineWidth;
-		context.strokeStyle = this.strokeStyle;
-		context.beginPath();
-			
-		var step = width / (this.data.length - 1);
-		var gamma = this.max - this.min;
-
-		context.moveTo(this.box.min.x, this.box.max.y - ((this.data[0] - this.min) / gamma) * height);
-		
-		for(var i = 1, s = step; i < this.data.length; s += step, i++)
-		{
-			context.lineTo(this.box.min.x + s, this.box.max.y - ((this.data[i] - this.min) / gamma) * height);
-		}
-
-		context.stroke();
-
-		if(this.fillStyle !== null)
-		{
-			context.fillStyle = this.fillStyle;
-
-			context.lineTo(this.box.max.x, this.box.max.y);
-			context.lineTo(this.box.min.x, this.box.max.y);
-			context.fill();
-		}
-	};
-
-	Graph.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;
-		data.min = this.min;
-		data.max = this.max;
-		data.data = this.data;
-
-		return data;
-	};
-
-	Graph.prototype.parse = function(data, root)
-	{
-		Object2D.prototype.parse.call(this, data, root);
-
-		this.box.fromArray(data.box);
-		this.strokeStyle = data.strokeStyle;
-		this.lineWidth = data.lineWidth;
-		this.fillStyle = data.fillStyle;
-		this.min = data.min;
-		this.max = data.max;
-		this.data = data.data;
-	};
-
 	/**
 	 * Multiple line text drawing directly into the canvas.
 	 *
@@ -4381,6 +4257,244 @@
 		this.radius = data.radius;
 	};
 
+	/**
+	 * Graph object is used to draw simple graph data into the canvas.
+	 *
+	 * Graph data is composed of X, Y values.
+	 *
+	 * @class
+	 * @extends {Object2D}
+	 */
+	function Graph()
+	{
+		Object2D.call(this);
+
+		/**
+		 * Graph object containing the size of the object.
+		 */
+		this.box = new Box2(new Vector2(-50, -35), new Vector2(50, 35));
+
+		/**
+		 * Color of the box border line.
+		 */
+		this.strokeStyle = "rgb(0, 153, 255)";
+
+		/**
+		 * Line width.
+		 */
+		this.lineWidth = 1;
+
+		/**
+		 * Background color of the box.
+		 */
+		this.fillStyle = "rgba(0, 153, 255, 0.3)";
+
+		/**
+		 * Minimum value of the graph.
+		 */
+		this.min = 0;
+
+		/**
+		 * Maximum value of the graph.
+		 */
+		this.max = 10;
+
+		/**
+		 * Data to be presented in the graph.
+		 *
+		 * The array should store numeric values.
+		 */
+		this.data = [];
+	}
+
+	Graph.prototype = Object.create(Object2D.prototype);
+	Graph.prototype.constructor = Graph;
+	Graph.prototype.type = "Graph";
+	Object2D.register(Graph, "Graph");
+
+	Graph.prototype.isInside = function(point)
+	{
+		return this.box.containsPoint(point);
+	};
+
+	Graph.prototype.draw = function(context, viewport, canvas)
+	{
+		if(this.data.length === 0)
+		{
+			return;
+		}
+		
+		var width = this.box.max.x - this.box.min.x;
+		var height = this.box.max.y - this.box.min.y;
+
+		context.lineWidth = this.lineWidth;
+		context.strokeStyle = this.strokeStyle;
+		context.beginPath();
+			
+		var step = width / (this.data.length - 1);
+		var gamma = this.max - this.min;
+
+		context.moveTo(this.box.min.x, this.box.max.y - ((this.data[0] - this.min) / gamma) * height);
+		
+		for(var i = 1, s = step; i < this.data.length; s += step, i++)
+		{
+			context.lineTo(this.box.min.x + s, this.box.max.y - ((this.data[i] - this.min) / gamma) * height);
+		}
+
+		context.stroke();
+
+		if(this.fillStyle !== null)
+		{
+			context.fillStyle = this.fillStyle;
+
+			context.lineTo(this.box.max.x, this.box.max.y);
+			context.lineTo(this.box.min.x, this.box.max.y);
+			context.fill();
+		}
+	};
+
+	Graph.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;
+		data.min = this.min;
+		data.max = this.max;
+		data.data = this.data;
+
+		return data;
+	};
+
+	Graph.prototype.parse = function(data, root)
+	{
+		Object2D.prototype.parse.call(this, data, root);
+
+		this.box.fromArray(data.box);
+		this.strokeStyle = data.strokeStyle;
+		this.lineWidth = data.lineWidth;
+		this.fillStyle = data.fillStyle;
+		this.min = data.min;
+		this.max = data.max;
+		this.data = data.data;
+	};
+
+	/**
+	 * Gauge object is used to draw gauge like graphic.
+	 *
+	 * It has a defined range, start angle, end angle and style controls.
+	 *
+	 * @class
+	 * @extends {Object2D}
+	 */
+	function Gauge()
+	{
+		Object2D.call(this);
+
+		this.value = 50;
+
+		this.min = 0;
+		this.max = 100;
+
+		/**
+		 * Radius of the gauge object.
+		 *
+		 * @type {number}
+		 */
+		this.radius = 80;
+
+		this.lineWidth = 10;
+
+		this.startAngle = Math.PI;
+		this.endAngle = 2 * Math.PI;
+
+
+		/**
+		 * If true draw a circular dial at the end of the gauge bar.
+		 *
+		 * @type {boolean}
+		 */
+		this.dial = false;
+
+		this.baseStyle = "#e9ecf1";
+	}
+
+	Gauge.prototype = Object.create(Object2D.prototype);
+	Gauge.prototype.constructor = Gauge;
+	Gauge.prototype.type = "Gauge";
+	Object2D.register(Gauge, "Gauge");
+
+	Gauge.prototype.isInside = function(point)
+	{
+		return point.length() <= this.radius;
+	};
+
+	Gauge.prototype.draw = function(context, viewport, canvas)
+	{
+		var percentage = this.value / (this.max - this.min);
+
+		var range = [this.startAngle, this.endAngle];
+		var diff = range[1] - range[0];
+		var angle = range[0] + diff * percentage;
+		var center = [0, 0];
+
+		//Back
+		context.lineWidth = this.lineWidth;
+		context.lineCap = "round";
+		context.strokeStyle = this.baseStyle;
+		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);
+		gradient.addColorStop(0, "#61ff50");
+		gradient.addColorStop(0.5, "#ffbb50");
+		gradient.addColorStop(1, "#ff3269");
+		context.strokeStyle = gradient;
+
+		context.lineWidth = this.lineWidth;
+		context.beginPath();
+		context.arc(center[0], center[1], this.radius, range[0], angle);
+		context.stroke();
+
+		if(this.dial)
+		{
+			var dialAngle = (this.startAngle - this.endAngle) * percentage;
+			var dialCenter = [Math.cos(dialAngle) * this.radius, Math.sin(dialAngle) * this.radius];
+			dialCenter[0] = dialCenter[0] - center[0];
+			dialCenter[1] = dialCenter[1] - center[1];
+
+			context.fillStyle = "#FFFFFF";
+			context.beginPath();
+			context.arc(dialCenter[0], dialCenter[1], this.lineWidth / 2, 0, 2 * Math.PI);
+			context.fill();
+
+			context.fillStyle = gradient;
+			context.beginPath();
+			context.arc(dialCenter[0], dialCenter[1], this.lineWidth / 3, 0, 2 * Math.PI);
+			context.fill();
+		}
+	};
+
+	Gauge.prototype.serialize = function(recursive)
+	{
+		var data = Object2D.prototype.serialize.call(this, recursive);
+
+		// TODO <ADD CODE HERE>
+
+		return data;
+	};
+
+	Gauge.prototype.parse = function(data, root)
+	{
+		Object2D.prototype.parse.call(this, data, root);
+
+		// TODO <ADD CODE HERE>
+	};
+
 	/**
 	 * Node graph object should be used as a container for node elements.
 	 *
@@ -5300,6 +5414,7 @@
 	exports.DOM = DOM;
 	exports.EventManager = EventManager;
 	exports.FileUtils = FileUtils;
+	exports.Gauge = Gauge;
 	exports.Graph = Graph;
 	exports.Helpers = Helpers;
 	exports.Image = Image;

+ 6 - 0
examples/playground.html

@@ -120,6 +120,12 @@
 		image.draggable = true;
 		group.add(image);
 
+		var gauge = new Escher.Gauge();
+		gauge.position.set(500, 700);
+		gauge.layer = 5;
+		gauge.draggable = true;
+		group.add(gauge);
+
 		var graph = new Escher.Graph();
 		graph.box.min.set(-500, -50);
 		graph.box.max.set(500, 50);

+ 2 - 1
source/Escher.js

@@ -20,11 +20,12 @@ export {Text} from "./objects/Text.js";
 export {Image} from "./objects/Image.js";
 export {DOM} from "./objects/DOM.js";
 export {Pattern} from "./objects/Pattern.js";
-export {Graph} from "./objects/chart/Graph.js";
 export {MultiLineText} from "./objects/MultiLineText.js";
 export {BezierCurve} from "./objects/BezierCurve.js";
 export {QuadraticCurve} from "./objects/QuadraticCurve.js";
 export {RoundedBox} from "./objects/RoundedBox.js";
+export {Graph} from "./objects/chart/Graph.js";
+export {Gauge} from "./objects/chart/Gauge.js";
 
 export {Node} from "./objects/node/Node.js";
 export {NodeConnector} from "./objects/node/NodeConnector.js";

+ 76 - 5
source/objects/chart/Gauge.js

@@ -1,11 +1,9 @@
 import {Object2D} from "../../Object2D.js";
-import {Vector2} from "../../math/Vector2.js";
-import {Box2} from "../../math/Box2.js";
 
 /**
  * Gauge object is used to draw gauge like graphic.
  *
- * It has a defined range, value animation and style controls.
+ * It has a defined range, start angle, end angle and style controls.
  *
  * @class
  * @extends {Object2D}
@@ -14,7 +12,32 @@ function Gauge()
 {
 	Object2D.call(this);
 
-	// TODO <ADD CODE HERE>
+	this.value = 50;
+
+	this.min = 0;
+	this.max = 100;
+
+	/**
+	 * Radius of the gauge object.
+	 *
+	 * @type {number}
+	 */
+	this.radius = 80;
+
+	this.lineWidth = 10;
+
+	this.startAngle = Math.PI;
+	this.endAngle = 2 * Math.PI;
+
+
+	/**
+	 * If true draw a circular dial at the end of the gauge bar.
+	 *
+	 * @type {boolean}
+	 */
+	this.dial = false;
+
+	this.baseStyle = "#e9ecf1";
 }
 
 Gauge.prototype = Object.create(Object2D.prototype);
@@ -22,9 +45,57 @@ Gauge.prototype.constructor = Gauge;
 Gauge.prototype.type = "Gauge";
 Object2D.register(Gauge, "Gauge");
 
+Gauge.prototype.isInside = function(point)
+{
+	return point.length() <= this.radius;
+};
+
 Gauge.prototype.draw = function(context, viewport, canvas)
 {
-	// TODO <ADD CODE HERE>
+	var percentage = this.value / (this.max - this.min);
+
+	var range = [this.startAngle, this.endAngle];
+	var diff = range[1] - range[0];
+	var angle = range[0] + diff * percentage;
+	var center = [0, 0];
+
+	//Back
+	context.lineWidth = this.lineWidth;
+	context.lineCap = "round";
+	context.strokeStyle = this.baseStyle;
+	context.beginPath();
+	context.arc(center[0], center[1], this.radius, range[0], range[1]);
+	context.stroke();
+
+	// Fill gradient
+	var gradient = context.createLinearGradient(-this.radius, 0, this.radius, 0);
+	gradient.addColorStop(0, "#61ff50");
+	gradient.addColorStop(0.5, "#ffbb50");
+	gradient.addColorStop(1, "#ff3269");
+	context.strokeStyle = gradient;
+
+	context.lineWidth = this.lineWidth;
+	context.beginPath();
+	context.arc(center[0], center[1], this.radius, range[0], angle);
+	context.stroke();
+
+	if(this.dial)
+	{
+		var dialAngle = (this.startAngle - this.endAngle) * percentage;
+		var dialCenter = [Math.cos(dialAngle) * this.radius, Math.sin(dialAngle) * this.radius];
+		dialCenter[0] = dialCenter[0] - center[0];
+		dialCenter[1] = dialCenter[1] - center[1];
+
+		context.fillStyle = "#FFFFFF";
+		context.beginPath();
+		context.arc(dialCenter[0], dialCenter[1], this.lineWidth / 2, 0, 2 * Math.PI);
+		context.fill();
+
+		context.fillStyle = gradient;
+		context.beginPath();
+		context.arc(dialCenter[0], dialCenter[1], this.lineWidth / 3, 0, 2 * Math.PI);
+		context.fill();
+	}
 };
 
 Gauge.prototype.serialize = function(recursive)

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

@@ -0,0 +1,32 @@
+import {Style} from "./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)
+{
+    /**
+     * Color of this style object.
+     *
+     * @type {string}
+     */
+    this.color = color || "#000000";
+}
+
+ColorStyle.prototype = Object.create(Style);
+
+ColorStyle.prototype.generate = function(context)
+{
+    return this.color;
+};
+
+ColorStyle.prototype.toJSON = function()
+{
+
+};
+
+export {ColorStyle};

+ 55 - 0
source/objects/style/GradientStyle.js

@@ -0,0 +1,55 @@
+import {Style} from "./Style";
+
+/**
+ * Gradient style describes a gradient by its colors, directions origin, type (linear or radial, etc.
+ *
+ * The object returns a CanvasGradient https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient when generated.
+ *
+ * @class
+ * @extends {Style}
+ */
+function GradientStyle()
+{
+
+}
+
+GradientStyle.prototype = Object.create(Style);
+
+/**
+ * Linear gradient style, represents a gradient of colors from a point to another interpolating in between.
+ *
+ * Behind the of the two points used the color is solid.
+ *
+ * @tpye {number}
+ */
+GradientStyle.LINEAR = 100;
+
+/**
+ * Radial gradient interpolates colors from a point all around up to a radius value.
+ *
+ * Outside of the radius the color is solid.
+ *
+ * @tpye {number}
+ */
+GradientStyle.RADIAL = 101;
+
+/**
+ * Add a new color stop defined by an offset and a color to the gradient.
+ *
+ * If the offset is not between 0 and 1 inclusive, or if color can't be parsed as a CSS color, an error is raised.
+ *
+ * @param {number} offset Offset of the color stop between 0 and 1 inclusive.
+ * @param {string} color CSS color value.
+ */
+GradientStyle.prototype.addColorStop = function(offset, color)
+{
+
+};
+
+GradientStyle.prototype.generate = function(context)
+{
+    // context.createLinearGradient()
+    // context.createRadialGradient()
+};
+
+export {GradientStyle};

+ 24 - 0
source/objects/style/Style.js

@@ -0,0 +1,24 @@
+import {ColorStyle} from "./ColorStyle";
+
+/**
+ * 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() {}
+
+/**
+ * Generate 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.prototype.generate = function(context) {};
+
+Style.prototype.toJSON = function() {};
+
+Style.fromJSON = function () {};
+
+export {Style};