tentone 6 years ago
parent
commit
4357d22cb9

+ 62 - 0
examples/diagram.html

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<meta charset="utf-8">
+	<title>diagram.js</title>
+</head>
+<body>
+	<script type="text/javascript" src="../source/EventManager.js"></script>
+	<script type="text/javascript" src="../source/Object2D.js"></script>
+	<script type="text/javascript" src="../source/Viewport.js"></script>
+	<script type="text/javascript" src="../source/Renderer.js"></script>
+
+	<script type="text/javascript" src="../source/input/Key.js"></script>
+	<script type="text/javascript" src="../source/input/Mouse.js"></script>
+
+	<script type="text/javascript" src="../source/objects/Image.js"></script>
+	<script type="text/javascript" src="../source/objects/Text.js"></script>
+	<script type="text/javascript" src="../source/objects/Box.js"></script>
+	<script type="text/javascript" src="../source/objects/ConnectionLine.js"></script>
+
+	<script type="text/javascript" src="../source/math/Vector2.js"></script>
+	<script type="text/javascript" src="../source/math/Box2.js"></script>
+	<script type="text/javascript" src="../source/math/UUID.js"></script>
+	<script type="text/javascript" src="../source/math/Matrix.js"></script>
+
+	<script type="text/javascript">
+		var canvas = document.createElement("canvas");
+		canvas.width = 800;
+		canvas.height = 600;
+		canvas.style.border = "1px solid #000000";
+		canvas.oncontextmenu = function(event)
+		{
+			event.preventDefault();
+			return false;
+		};
+		document.body.appendChild(canvas);
+
+		var group = new Object2D();
+
+		var background = new Image("pfd.png");
+		background.position.set(0, 0);
+		background.scale.set(1, 1);
+		group.add(background);
+
+		var box = new Box();
+		group.add(box);
+
+		var viewport = new Viewport();
+
+		var renderer = new Renderer(canvas);
+
+		function loop()
+		{
+			renderer.update(group, viewport);
+			renderer.render(group, viewport);
+			requestAnimationFrame(loop);
+		}
+
+		loop();
+	</script>
+</body>
+</html>

BIN
examples/pfd.png


BIN
image.jpg


+ 0 - 78
index.html

@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-	<meta charset="utf-8">
-	<title>diagram.js</title>
-</head>
-<body>
-	<script type="text/javascript" src="source/EventManager.js"></script>
-	<script type="text/javascript" src="source/Object2D.js"></script>
-	<script type="text/javascript" src="source/Viewport.js"></script>
-	<script type="text/javascript" src="source/Renderer.js"></script>
-
-	<script type="text/javascript" src="source/input/Key.js"></script>
-	<script type="text/javascript" src="source/input/Mouse.js"></script>
-
-	<script type="text/javascript" src="source/objects/Image.js"></script>
-	<script type="text/javascript" src="source/objects/Text.js"></script>
-	<script type="text/javascript" src="source/objects/Box.js"></script>
-	<script type="text/javascript" src="source/objects/ConnectionLine.js"></script>
-
-	<script type="text/javascript" src="source/math/Vector2.js"></script>
-	<script type="text/javascript" src="source/math/Box2.js"></script>
-	<script type="text/javascript" src="source/math/UUID.js"></script>
-	<script type="text/javascript" src="source/math/Matrix.js"></script>
-
-	<script type="text/javascript">
-		var canvas = document.createElement("canvas");
-		canvas.width = 800;
-		canvas.height = 600;
-		canvas.style.border = "1px solid #000000";
-		canvas.oncontextmenu = function(event)
-		{
-			event.preventDefault();
-			return false;
-		};
-		document.body.appendChild(canvas);
-
-		var o = new Object2D();
-
-		var i = new Image("image.jpg");
-		i.position.set(100, 100);
-		i.scale.set(1, 2);
-		o.add(i);
-
-		var re = new Box();
-		re.position.set(0, 0);
-		o.add(re);
-
-		var ra = new Box();
-		ra.position.set(200, 0);
-		re.add(ra);
-
-		var rb = new Box();
-		rb.position.set(50, 300);
-		o.add(rb);
-
-		var l = new ConnectionLine();
-		l.to.set(-500, 0);
-		o.add(l);
-
-		var v = new Viewport();
-
-		var r = new Renderer(canvas);
-
-		function loop()
-		{
-			i.rotation += 0.01;
-			re.rotation -= 0.005;
-
-			r.update(o, v)
-			r.render(o, v)
-			requestAnimationFrame(loop);
-		}
-
-		loop();
-	</script>
-</body>
-</html>

+ 38 - 4
source/Object2D.js

@@ -49,6 +49,13 @@ function Object2D()
 	 */
 	 */
 	this.matrix = new Matrix();
 	this.matrix = new Matrix();
 
 
+	/**
+	 * Flag indicating if the pointer is inside of the element.
+	 *
+	 * Used to control object event.
+	 */
+	this.pointerInside = false;
+
 	/**
 	/**
 	 * Global transformation matrix multiplied by the parent matrix.
 	 * Global transformation matrix multiplied by the parent matrix.
 	 *
 	 *
@@ -112,8 +119,6 @@ Object2D.prototype.remove = function(object)
 	}
 	}
 };
 };
 
 
-Object2D.prototype.onOver = function(){};
-
 /**
 /**
  * Check if a point is inside of the object.
  * Check if a point is inside of the object.
  */
  */
@@ -148,6 +153,35 @@ Object2D.prototype.updateMatrix = function(context)
  * Has to be implemented by underlying classes.
  * Has to be implemented by underlying classes.
  *
  *
  * @param context Canvas 2d drawing context.
  * @param context Canvas 2d drawing context.
- * @param canvas The canvas DOM element where its being drawn.
  */
  */
-Object2D.prototype.draw = function(context){};
+Object2D.prototype.draw = function(context){};
+
+/**
+ * Callback method called when the pointer enters the object.
+ */
+Object2D.prototype.onPointerEnter = null;
+
+/**
+ * Callback method called when the was inside of the object and leaves the object.
+ */
+Object2D.prototype.onPointerLeave = null;
+
+/**
+ * Callback method while the pointer is over (inside) of the object.
+ */
+Object2D.prototype.onPointerOver = null;
+
+/**
+ * Callback method called while the pointer button is pressed.
+ */
+Object2D.prototype.onPointerPressed = null;
+
+/**
+ * Callback method called when the pointer button is pressed down (single time).
+ */
+Object2D.prototype.onPointerDown = null;
+
+/**
+ * Callback method called when the pointer button is released (single time).
+ */
+Object2D.prototype.onPointerUp = null;

+ 59 - 5
source/Renderer.js

@@ -18,7 +18,9 @@ function Renderer(canvas)
 	 * Canvas 2D rendering context used to draw content.
 	 * Canvas 2D rendering context used to draw content.
 	 */
 	 */
 	this.context = canvas.getContext("2d");
 	this.context = canvas.getContext("2d");
-
+	this.context.imageSmoothingEnabled = true;
+	this.context.globalCompositeOperation = "source-over";
+	
 	/**
 	/**
 	 * Mouse input handler object.
 	 * Mouse input handler object.
 	 */
 	 */
@@ -41,19 +43,71 @@ Renderer.prototype.update = function(object, viewport)
 
 
 	// Project mouse coordinates
 	// Project mouse coordinates
 	var point = mouse.position.clone();
 	var point = mouse.position.clone();
-	point = viewport.inverseMatrix.transformPoint(point);
+	var viewportPoint = viewport.inverseMatrix.transformPoint(point);
 
 
 	// Object transformation matrices
 	// Object transformation matrices
 	object.traverse(function(child)
 	object.traverse(function(child)
 	{
 	{
 		child.updateMatrix();
 		child.updateMatrix();
 		
 		
-		var childPoint = child.inverseGlobalMatrix.transformPoint(point);
-		
+		var childPoint = child.inverseGlobalMatrix.transformPoint(viewportPoint);
+
 		// Check if the mouse pointer is inside
 		// Check if the mouse pointer is inside
 		if(child.isInside(childPoint))
 		if(child.isInside(childPoint))
 		{
 		{
-			child.onOver();
+			// Pointer enter
+			if(!child.pointerInside)
+			{			
+				if(child.onPointerEnter !== null)
+				{
+					child.onPointerEnter(mouse, viewport);
+				}
+			}
+
+			// Pointer over
+			if(child.onPointerOver !== null)
+			{
+				child.onPointerOver(mouse, viewport);
+			}
+
+			// Pointer pressed
+			if(mouse.buttonPressed(Mouse.LEFT))
+			{
+				if(child.onPointerPressed !== null)
+				{
+					child.onPointerPressed(mouse, viewport);
+				}
+			}
+
+			// Just pressed
+			if(mouse.buttonJustPressed(Mouse.LEFT))
+			{	
+				if(child.onPointerDown !== null)
+				{
+					child.onPointerDown(mouse, viewport);
+				}
+			}
+
+			// Just released
+			if(mouse.buttonJustReleased(Mouse.LEFT))
+			{	
+				if(child.onPointerUp !== null)
+				{
+					child.onPointerUp(mouse, viewport);
+				}
+			}
+
+			child.pointerInside = true;
+		}
+		else if(child.pointerInside)
+		{
+			// Pointer leave
+			if(child.onPointerLeave !== null)
+			{
+				child.onPointerLeave(mouse, viewport);
+			}
+
+			child.pointerInside = false;
 		}
 		}
 	});
 	});
 };
 };

+ 22 - 2
source/Viewport.js

@@ -41,14 +41,34 @@ function Viewport()
 	 * If true the matrix is updated before rendering the object.
 	 * If true the matrix is updated before rendering the object.
 	 */
 	 */
 	this.matrixNeedsUpdate = true;
 	this.matrixNeedsUpdate = true;
+
+	/**
+	 * Flag to indicate if the viewport should move when scalling.
+	 *
+	 * For some application its easier to focus the target if the viewport moves to the pointer location while scalling.
+	 */
+	this.moveOnScale = true;
 }
 }
 
 
 /**
 /**
  * Update the viewport controls using the mouse object.
  * Update the viewport controls using the mouse object.
  */
  */
 Viewport.prototype.updateControls = function(mouse)
 Viewport.prototype.updateControls = function(mouse)
-{
-	this.scale -= mouse.wheel * 1e-3 * this.scale;
+{	
+	if(mouse.wheel !== 0)
+	{
+		this.scale -= mouse.wheel * 1e-3 * this.scale;
+
+		if(this.moveOnScale)
+		{	
+			var speed = mouse.wheel / this.scale;
+			var halfWidth = mouse.canvas.width / 2;
+			var halfWeight = mouse.canvas.height / 2;
+
+			this.position.x += ((mouse.position.x - halfWidth) / halfWidth) * speed;
+			this.position.y += ((mouse.position.y - halfWeight) / halfWeight) * speed;
+		}
+	}
 
 
 	if(mouse.buttonPressed(Mouse.RIGHT))
 	if(mouse.buttonPressed(Mouse.RIGHT))
 	{
 	{

+ 5 - 0
source/math/Box2.js

@@ -1,5 +1,10 @@
 "use strict";
 "use strict";
 
 
+/**
+ * Box is described by a minimum and maximum points.
+ *
+ * Can be used for collision detection with points and other boxes.
+ */
 function Box2(min, max)
 function Box2(min, max)
 {
 {
 	this.min = (min !== undefined) ? min : new Vector2();
 	this.min = (min !== undefined) ? min : new Vector2();

+ 37 - 14
source/math/Matrix.js

@@ -13,8 +13,7 @@ function Matrix(values)
 	}
 	}
 	else
 	else
 	{
 	{
-		this.m = null;
-		this.reset();
+		this.identity();
 	}
 	}
 }
 }
 
 
@@ -26,10 +25,18 @@ Matrix.prototype.copy = function(mat)
 	this.m = mat.m.slice(0);
 	this.m = mat.m.slice(0);
 };
 };
 
 
+/**
+ * Create a new matrix object with a copy of the content of this one.
+ */
+Matrix.prototype.clone = function()
+{
+	return new Matrix(this.m.slice(0))
+};
+
 /**
 /**
  * Reset this matrix to indentity.
  * Reset this matrix to indentity.
  */
  */
-Matrix.prototype.reset = function()
+Matrix.prototype.identity = function()
 {
 {
 	this.m = [1, 0, 0, 1, 0, 0];
 	this.m = [1, 0, 0, 1, 0, 0];
 };
 };
@@ -123,6 +130,22 @@ Matrix.prototype.scale = function(sx, sy)
 	this.m[3] *= sy;
 	this.m[3] *= sy;
 };
 };
 
 
+/**
+ * Get the scale from the transformation matrix.
+ */
+Matrix.prototype.getScale = function()
+{
+	return new Vector2(this.m[0], this.m[3]);
+};
+
+/**
+ * Get the position from the transformation matrix.
+ */
+Matrix.prototype.getPosition = function()
+{
+	return new Vector2(this.m[5], this.m[6]);
+};
+
 /**
 /**
  * Apply skew to this matrix.
  * Apply skew to this matrix.
  */
  */
@@ -149,6 +172,17 @@ Matrix.prototype.getInverse = function()
 	return new Matrix([this.m[3] * d, -this.m[1] * d, -this.m[2] * d, this.m[0] * d, d * (this.m[2] * this.m[5] - this.m[3] * this.m[4]), d * (this.m[1] * this.m[4] - this.m[0] * this.m[5])]);
 	return new Matrix([this.m[3] * d, -this.m[1] * d, -this.m[2] * d, this.m[0] * d, d * (this.m[2] * this.m[5] - this.m[3] * this.m[4]), d * (this.m[1] * this.m[4] - this.m[0] * this.m[5])]);
 };
 };
 
 
+/**
+ * Transform a point using this matrix.
+ */
+Matrix.prototype.transformPoint = function(p)
+{
+	var px = p.x * this.m[0] + p.y * this.m[2] + this.m[4];
+	var py = p.x * this.m[1] + p.y * this.m[3] + this.m[5];
+
+	return new Vector2(px, py);
+};
+
 /**
 /**
  * Set a canvas context to use this transformation.
  * Set a canvas context to use this transformation.
  */
  */
@@ -164,14 +198,3 @@ Matrix.prototype.tranformContext = function(context)
 {
 {
 	context.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);
 	context.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);
 };
 };
-
-/**
- * Transform a point using this matrix.
- */
-Matrix.prototype.transformPoint = function(p)
-{
-	var px = p.x * this.m[0] + p.y * this.m[2] + this.m[4];
-	var py = p.x * this.m[1] + p.y * this.m[3] + this.m[5];
-
-	return new Vector2(px, py);
-};

+ 46 - 4
source/objects/Box.js

@@ -1,6 +1,6 @@
 "use strict";
 "use strict";
 
 
-function Box(src)
+function Box()
 {
 {
 	Object2D.call(this);
 	Object2D.call(this);
 
 
@@ -13,15 +13,53 @@ function Box(src)
 	 * Color of the box border line.
 	 * Color of the box border line.
 	 */
 	 */
 	this.borderColor = "#000000";
 	this.borderColor = "#000000";
+
+	/**
+	 * Background color of the box.
+	 */
+	this.backgroundColor = "#FFFFFF";
+
+	this.dragging = false;
 }
 }
 
 
 Box.prototype = Object.create(Object2D.prototype);
 Box.prototype = Object.create(Object2D.prototype);
 
 
-Box.prototype.onOver = function(point)
+Box.prototype.onPointerDown = function(mouse, viewport)
 {
 {
-	this.borderColor = "#FF0000";
+	this.dragging = true;
 };
 };
 
 
+Box.prototype.onPointerUp = function(mouse, viewport)
+{
+	this.dragging = false;
+};
+
+Box.prototype.onPointerOver = function(mouse, viewport)
+{
+	if(this.dragging)
+	{
+		var matrix = viewport.inverseMatrix.clone();
+		matrix.multiply(this.inverseGlobalMatrix);
+
+		var scale = matrix.getScale();
+
+		this.position.x += mouse.delta.x * scale.x;
+		this.position.y += mouse.delta.y * scale.y;
+	}
+};
+
+
+Box.prototype.onPointerEnter = function(mouse, viewport)
+{
+	this.backgroundColor = "#CCCCCC";
+};
+
+Box.prototype.onPointerLeave = function(mouse, viewport)
+{
+	this.backgroundColor = "#FFFFFF";
+};
+
+
 Box.prototype.isInside = function(point)
 Box.prototype.isInside = function(point)
 {
 {
 	return this.box.containsPoint(point);
 	return this.box.containsPoint(point);
@@ -32,7 +70,11 @@ Box.prototype.draw = function(context)
 	var width = this.box.max.x - this.box.min.x;
 	var width = this.box.max.x - this.box.min.x;
 	var height = this.box.max.y - this.box.min.y;
 	var height = this.box.max.y - this.box.min.y;
 
 
-	context.lineWidth = 2;
+	context.fillStyle = this.backgroundColor;
+	context.fillRect(this.box.min.x, this.box.min.y, width, height);
+
+	context.setLineDash([]);
+	context.lineWidth = 1;
 	context.strokeStyle = this.borderColor;
 	context.strokeStyle = this.borderColor;
 	context.strokeRect(this.box.min.x, this.box.min.y, width, height);
 	context.strokeRect(this.box.min.x, this.box.min.y, width, height);
 };
 };

+ 3 - 2
source/objects/ConnectionLine.js

@@ -1,6 +1,6 @@
 "use strict";
 "use strict";
 
 
-function ConnectionLine(src)
+function ConnectionLine()
 {
 {
 	Object2D.call(this);
 	Object2D.call(this);
 
 
@@ -26,7 +26,8 @@ ConnectionLine.prototype.draw = function(context)
 {
 {
 	context.lineWidth = 2;
 	context.lineWidth = 2;
 	context.strokeStyle = this.color;
 	context.strokeStyle = this.color;
-
+	context.setLineDash([10, 10]);
+	
 	context.beginPath();
 	context.beginPath();
 	context.moveTo(this.from.x, this.from.y);
 	context.moveTo(this.from.x, this.from.y);
 	context.lineTo(this.to.x, this.to.y);
 	context.lineTo(this.to.x, this.to.y);

+ 21 - 2
source/objects/Text.js

@@ -1,13 +1,32 @@
 "use strict";
 "use strict";
 
 
-function Text(src)
+function Text()
 {
 {
 	Object2D.call(this);
 	Object2D.call(this);
+
+	/**
+	 * Text value.
+	 */
+	this.text = "";
+
+	/**
+	 * Font of the text.
+	 */
+	this.font = "30px Arial";
+
+	/**
+	 * Color (style) of the text.
+	 */
+	this.color = "#000000";
 }
 }
 
 
 Text.prototype = Object.create(Object2D.prototype);
 Text.prototype = Object.create(Object2D.prototype);
 
 
 Text.prototype.draw = function(context)
 Text.prototype.draw = function(context)
 {
 {
-	//TODO
+	context.font = this.font;
+	context.textAlign = "center";
+	context.fillStyle = this.color;
+
+	context.fillText(this.text, 0, 0);
 };
 };