|
|
@@ -5,7 +5,8 @@ function Graph(element)
|
|
|
this.canvas.focus();
|
|
|
this.context = this.canvas.getContext("2d");
|
|
|
this.theme = { background: "#fff", connection: "#000", selection: "#000", connector: "#31456b", connectorBorder: "#fff", connectorHoverBorder: "#000", connectorHover: "#0c0" };
|
|
|
- this.mousePosition = new Point(0, 0);
|
|
|
+ this.pointerPosition = new Point(0, 0);
|
|
|
+ this.shiftKey = false;
|
|
|
this.undoService = new UndoService();
|
|
|
this.elements = [];
|
|
|
this.activeTemplate = null;
|
|
|
@@ -19,12 +20,18 @@ function Graph(element)
|
|
|
this.mouseUpHandler = this.mouseUp.delegate(this);
|
|
|
this.mouseMoveHandler = this.mouseMove.delegate(this);
|
|
|
this.doubleClickHandler = this.doubleClick.delegate(this);
|
|
|
+ this.touchStartHandler = this.touchStart.delegate(this);
|
|
|
+ this.touchEndHandler = this.touchEnd.delegate(this);
|
|
|
+ this.touchMoveHandler = this.touchMove.delegate(this);
|
|
|
this.keyDownHandler = this.keyDown.delegate(this);
|
|
|
- this.keyUpHandler = this.keyUp.delegate(this);
|
|
|
+ this.keyUpHandler = this.keyUp.delegate(this);
|
|
|
|
|
|
this.canvas.addEventListener("mousedown", this.mouseDownHandler, false);
|
|
|
this.canvas.addEventListener("mouseup", this.mouseUpHandler, false);
|
|
|
this.canvas.addEventListener("mousemove", this.mouseMoveHandler, false);
|
|
|
+ this.canvas.addEventListener("touchstart", this.touchStartHandler, false);
|
|
|
+ this.canvas.addEventListener("touchend", this.touchEndHandler, false);
|
|
|
+ this.canvas.addEventListener("touchmove", this.touchMoveHandler, false);
|
|
|
this.canvas.addEventListener("dblclick", this.doubleClickHandler, false);
|
|
|
this.canvas.addEventListener("keydown", this.keyDownHandler, false);
|
|
|
this.canvas.addEventListener("keyup", this.keyUpHandler, false);
|
|
|
@@ -38,6 +45,9 @@ Graph.prototype.dispose = function()
|
|
|
this.canvas.removeEventListener("mouseup", this.mouseUpHandler);
|
|
|
this.canvas.removeEventListener("mousemove", this.mouseMoveHandler);
|
|
|
this.canvas.removeEventListener("dblclick", this.doubleClickHandler);
|
|
|
+ this.canvas.removeEventListener("touchstart", this.touchStartHandler);
|
|
|
+ this.canvas.removeEventListener("touchend", this.touchEndHandler);
|
|
|
+ this.canvas.removeEventListener("touchmove", this.touchMoveHandler);
|
|
|
this.canvas.removeEventListener("keydown", this.keyDownHandler);
|
|
|
this.canvas.removeEventListener("keyup", this.keyUpHandler);
|
|
|
this.canvas = null;
|
|
|
@@ -50,7 +60,6 @@ Graph.prototype.mouseDown = function(e)
|
|
|
e.preventDefault();
|
|
|
this.canvas.focus();
|
|
|
this.updateMousePosition(e);
|
|
|
- var point = this.mousePosition;
|
|
|
|
|
|
if (e.button === 0) // left-click
|
|
|
{
|
|
|
@@ -60,172 +69,230 @@ Graph.prototype.mouseDown = function(e)
|
|
|
this.createElement(this.activeTemplate);
|
|
|
}
|
|
|
|
|
|
- if (this.newElement !== null)
|
|
|
+ this.pointerDown();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Graph.prototype.mouseUp = function(e)
|
|
|
+{
|
|
|
+ e.preventDefault();
|
|
|
+ this.updateMousePosition(e);
|
|
|
+ if (e.button === 0) // left-click
|
|
|
+ {
|
|
|
+ this.pointerUp();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Graph.prototype.mouseMove = function(e)
|
|
|
+{
|
|
|
+ e.preventDefault();
|
|
|
+ this.updateMousePosition(e);
|
|
|
+ this.pointerMove();
|
|
|
+};
|
|
|
+
|
|
|
+Graph.prototype.doubleClick = function(e)
|
|
|
+{
|
|
|
+ e.preventDefault();
|
|
|
+ this.updateMousePosition(e);
|
|
|
+
|
|
|
+ if (e.button === 0) // left-click
|
|
|
+ {
|
|
|
+ var point = this.pointerPosition;
|
|
|
+
|
|
|
+ this.updateActiveObject(point);
|
|
|
+ if ((this.activeObject !== null) && (this.activeObject instanceof Element) && (this.activeObject.template !== null) && ("edit" in this.activeObject.template))
|
|
|
{
|
|
|
- this.undoService.begin();
|
|
|
- this.newElement.invalidate();
|
|
|
- this.newElement.rectangle = new Rectangle(point.x, point.y, this.newElement.rectangle.width, this.newElement.rectangle.height);
|
|
|
- this.newElement.invalidate();
|
|
|
- this.undoService.add(new InsertElementUndoUnit(this.newElement, this));
|
|
|
- this.undoService.commit();
|
|
|
- this.newElement = null;
|
|
|
+ this.activeObject.template.edit(this.activeObject, point);
|
|
|
+ this.update();
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Graph.prototype.touchStart = function(e)
|
|
|
+{
|
|
|
+ if (e.touches.length == 1)
|
|
|
+ {
|
|
|
+ e.preventDefault();
|
|
|
+ this.updateTouchPosition(e);
|
|
|
+ this.pointerDown();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Graph.prototype.touchEnd = function(e)
|
|
|
+{
|
|
|
+ e.preventDefault();
|
|
|
+ this.pointerUp();
|
|
|
+};
|
|
|
+
|
|
|
+Graph.prototype.touchMove = function(e)
|
|
|
+{
|
|
|
+ if (e.touches.length == 1)
|
|
|
+ {
|
|
|
+ e.preventDefault();
|
|
|
+ this.updateTouchPosition(e);
|
|
|
+ this.pointerMove();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+Graph.prototype.pointerDown = function()
|
|
|
+{
|
|
|
+ var point = this.pointerPosition;
|
|
|
+
|
|
|
+ if (this.newElement !== null)
|
|
|
+ {
|
|
|
+ this.undoService.begin();
|
|
|
+ this.newElement.invalidate();
|
|
|
+ this.newElement.rectangle = new Rectangle(point.x, point.y, this.newElement.rectangle.width, this.newElement.rectangle.height);
|
|
|
+ this.newElement.invalidate();
|
|
|
+ this.undoService.add(new InsertElementUndoUnit(this.newElement, this));
|
|
|
+ this.undoService.commit();
|
|
|
+ this.newElement = null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ this.selection = null;
|
|
|
+ this.updateActiveObject(point);
|
|
|
+ if (this.activeObject === null)
|
|
|
+ {
|
|
|
+ // start selection
|
|
|
+ this.selection = new Selection(point);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- this.selection = null;
|
|
|
- this.updateActiveObject(point);
|
|
|
- if (this.activeObject === null)
|
|
|
+ // start connection
|
|
|
+ if ((this.activeObject instanceof Connector) && (!this.shiftKey))
|
|
|
{
|
|
|
- // start selection
|
|
|
- this.selection = new Selection(point);
|
|
|
+ if (this.activeObject.isValid(null))
|
|
|
+ {
|
|
|
+ this.newConnection = new Connection(this.activeObject, null);
|
|
|
+ this.newConnection.toPoint = point;
|
|
|
+ this.activeObject.invalidate();
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- // start connection
|
|
|
- if (this.activeObject instanceof Connector)
|
|
|
+ // select object
|
|
|
+ if (!this.activeObject.selected)
|
|
|
{
|
|
|
- if (this.activeObject.isValid(null))
|
|
|
+ this.undoService.begin();
|
|
|
+ var selectionUndoUnit = new SelectionUndoUnit();
|
|
|
+ if (!this.shiftKey)
|
|
|
{
|
|
|
- this.newConnection = new Connection(this.activeObject, null);
|
|
|
- this.newConnection.toPoint = point;
|
|
|
- this.activeObject.invalidate();
|
|
|
+ this.deselectAll(selectionUndoUnit);
|
|
|
}
|
|
|
+ selectionUndoUnit.select(this.activeObject);
|
|
|
+ this.undoService.add(selectionUndoUnit);
|
|
|
+ this.undoService.commit();
|
|
|
}
|
|
|
- else
|
|
|
+ else if (this.shiftKey)
|
|
|
{
|
|
|
- // select object
|
|
|
- if (!this.activeObject.selected)
|
|
|
- {
|
|
|
- this.undoService.begin();
|
|
|
- var selectionUndoUnit = new SelectionUndoUnit();
|
|
|
- if (!e.shiftKey)
|
|
|
- {
|
|
|
- this.deselectAll(selectionUndoUnit);
|
|
|
- }
|
|
|
- selectionUndoUnit.select(this.activeObject);
|
|
|
- this.undoService.add(selectionUndoUnit);
|
|
|
- this.undoService.commit();
|
|
|
- }
|
|
|
+ this.undoService.begin();
|
|
|
+ var deselectUndoUnit = new SelectionUndoUnit();
|
|
|
+ deselectUndoUnit.deselect(this.activeObject);
|
|
|
+ this.undoService.add(deselectUndoUnit);
|
|
|
+ this.undoService.commit();
|
|
|
+ }
|
|
|
|
|
|
- // start tracking
|
|
|
- var hit = new Point(0, 0);
|
|
|
- if (this.activeObject instanceof Element)
|
|
|
- {
|
|
|
- hit = this.activeObject.tracker.hitTest(point);
|
|
|
- }
|
|
|
- for (var i = 0; i < this.elements.length; i++)
|
|
|
+ // start tracking
|
|
|
+ var hit = new Point(0, 0);
|
|
|
+ if (this.activeObject instanceof Element)
|
|
|
+ {
|
|
|
+ hit = this.activeObject.tracker.hitTest(point);
|
|
|
+ }
|
|
|
+ for (var i = 0; i < this.elements.length; i++)
|
|
|
+ {
|
|
|
+ var element = this.elements[i];
|
|
|
+ if (element.tracker !== null)
|
|
|
{
|
|
|
- var element = this.elements[i];
|
|
|
- if (element.tracker !== null)
|
|
|
- {
|
|
|
- element.tracker.start(point, hit);
|
|
|
- }
|
|
|
+ element.tracker.start(point, hit);
|
|
|
}
|
|
|
-
|
|
|
- this.track = true;
|
|
|
}
|
|
|
+
|
|
|
+ this.track = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- else if (e.button == 2) // right-click
|
|
|
- {
|
|
|
- if ((this.activeObject !== null) && (!this.activeObject.selected))
|
|
|
- {
|
|
|
- this.undoService.begin();
|
|
|
- var deselectUndoUnit = new SelectionUndoUnit();
|
|
|
- this.deselectAll(deselectUndoUnit);
|
|
|
- this.undoService.add(deselectUndoUnit);
|
|
|
- this.undoService.commit();
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
this.update();
|
|
|
this.updateMouseCursor();
|
|
|
};
|
|
|
|
|
|
-Graph.prototype.mouseUp = function(e)
|
|
|
+Graph.prototype.pointerUp = function()
|
|
|
{
|
|
|
- e.preventDefault();
|
|
|
- this.updateMousePosition(e);
|
|
|
- var point = this.mousePosition;
|
|
|
-
|
|
|
- if (e.button === 0) // left-click
|
|
|
+ var point = this.pointerPosition;
|
|
|
+
|
|
|
+ if (this.newConnection !== null)
|
|
|
{
|
|
|
- if (this.newConnection !== null)
|
|
|
+ this.updateActiveObject(point);
|
|
|
+ this.newConnection.invalidate();
|
|
|
+ if ((this.activeObject !== null) && (this.activeObject instanceof Connector))
|
|
|
{
|
|
|
- this.updateActiveObject(point);
|
|
|
- this.newConnection.invalidate();
|
|
|
- if ((this.activeObject !== null) && (this.activeObject instanceof Connector))
|
|
|
+ if ((this.activeObject != this.newConnection.from) && (this.activeObject.isValid(this.newConnection.from)))
|
|
|
{
|
|
|
- if ((this.activeObject != this.newConnection.from) && (this.activeObject.isValid(this.newConnection.from)))
|
|
|
- {
|
|
|
- this.undoService.begin();
|
|
|
- this.undoService.add(new InsertConnectionUndoUnit(this.newConnection, this.newConnection.from, this.activeObject));
|
|
|
- this.undoService.commit();
|
|
|
- }
|
|
|
+ this.undoService.begin();
|
|
|
+ this.undoService.add(new InsertConnectionUndoUnit(this.newConnection, this.newConnection.from, this.activeObject));
|
|
|
+ this.undoService.commit();
|
|
|
}
|
|
|
-
|
|
|
- this.newConnection = null;
|
|
|
}
|
|
|
|
|
|
- if (this.selection !== null)
|
|
|
- {
|
|
|
- this.undoService.begin();
|
|
|
- var selectionUndoUnit = new SelectionUndoUnit();
|
|
|
+ this.newConnection = null;
|
|
|
+ }
|
|
|
|
|
|
- var rectangle = this.selection.getRectangle();
|
|
|
- if ((this.activeObject === null) || (!this.activeObject.selected))
|
|
|
- {
|
|
|
- if (!e.shiftKey)
|
|
|
- {
|
|
|
- this.deselectAll(selectionUndoUnit);
|
|
|
- }
|
|
|
- }
|
|
|
+ if (this.selection !== null)
|
|
|
+ {
|
|
|
+ this.undoService.begin();
|
|
|
+ var selectionUndoUnit = new SelectionUndoUnit();
|
|
|
|
|
|
- if ((rectangle.width !== 0) || (rectangle.weight !== 0))
|
|
|
+ var rectangle = this.selection.getRectangle();
|
|
|
+ if ((this.activeObject === null) || (!this.activeObject.selected))
|
|
|
+ {
|
|
|
+ if (!this.shiftKey)
|
|
|
{
|
|
|
- this.selectAll(selectionUndoUnit, rectangle);
|
|
|
+ this.deselectAll(selectionUndoUnit);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- this.undoService.add(selectionUndoUnit);
|
|
|
- this.undoService.commit();
|
|
|
- this.selection = null;
|
|
|
+ if ((rectangle.width !== 0) || (rectangle.weight !== 0))
|
|
|
+ {
|
|
|
+ this.selectAll(selectionUndoUnit, rectangle);
|
|
|
}
|
|
|
|
|
|
- if (this.track)
|
|
|
+ this.undoService.add(selectionUndoUnit);
|
|
|
+ this.undoService.commit();
|
|
|
+ this.selection = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.track)
|
|
|
+ {
|
|
|
+ this.undoService.begin();
|
|
|
+ for (var i = 0; i < this.elements.length; i++)
|
|
|
{
|
|
|
- this.undoService.begin();
|
|
|
- for (var i = 0; i < this.elements.length; i++)
|
|
|
+ var element = this.elements[i];
|
|
|
+ if (element.tracker !== null)
|
|
|
{
|
|
|
- var element = this.elements[i];
|
|
|
- if (element.tracker !== null)
|
|
|
+ element.tracker.track = false;
|
|
|
+ element.invalidate();
|
|
|
+ var r1 = element.getRectangle();
|
|
|
+ var r2 = element.tracker.rectangle;
|
|
|
+ if ((r1.x != r2.x) || (r1.y != r2.y) || (r1.width != r2.width) || (r1.height != r2.height))
|
|
|
{
|
|
|
- element.tracker.track = false;
|
|
|
- element.invalidate();
|
|
|
- var r1 = element.getRectangle();
|
|
|
- var r2 = element.tracker.rectangle;
|
|
|
- if ((r1.x != r2.x) || (r1.y != r2.y) || (r1.width != r2.width) || (r1.height != r2.height))
|
|
|
- {
|
|
|
- this.undoService.add(new TransformUndoUnit(element, r1, r2));
|
|
|
- }
|
|
|
+ this.undoService.add(new TransformUndoUnit(element, r1, r2));
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- this.undoService.commit();
|
|
|
- this.track = false;
|
|
|
- this.updateActiveObject(point);
|
|
|
}
|
|
|
+
|
|
|
+ this.undoService.commit();
|
|
|
+ this.track = false;
|
|
|
+ this.updateActiveObject(point);
|
|
|
}
|
|
|
|
|
|
this.update();
|
|
|
this.updateMouseCursor();
|
|
|
};
|
|
|
|
|
|
-Graph.prototype.mouseMove = function(e)
|
|
|
+Graph.prototype.pointerMove = function()
|
|
|
{
|
|
|
- e.preventDefault();
|
|
|
- this.updateMousePosition(e);
|
|
|
- var point = this.mousePosition;
|
|
|
+ var point = this.pointerPosition;
|
|
|
|
|
|
if (this.newElement !== null)
|
|
|
{
|
|
|
@@ -268,22 +335,6 @@ Graph.prototype.mouseMove = function(e)
|
|
|
this.updateMouseCursor();
|
|
|
};
|
|
|
|
|
|
-Graph.prototype.doubleClick = function(e)
|
|
|
-{
|
|
|
- e.preventDefault();
|
|
|
- this.updateMousePosition(e);
|
|
|
- var point = this.mousePosition;
|
|
|
-
|
|
|
- if (e.button === 0) // left-click
|
|
|
- {
|
|
|
- this.updateActiveObject(point);
|
|
|
- if ((this.activeObject !== null) && (this.activeObject instanceof Element) && (this.activeObject.template !== null) && ("edit" in this.activeObject.template))
|
|
|
- {
|
|
|
- this.activeObject.template.edit(this.activeObject, point);
|
|
|
- this.update();
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
|
|
|
Graph.prototype.keyDown = function(e)
|
|
|
{
|
|
|
@@ -297,7 +348,7 @@ Graph.prototype.keyDown = function(e)
|
|
|
this.undoService.add(selectionUndoUnit);
|
|
|
this.undoService.commit();
|
|
|
this.update();
|
|
|
- this.updateActiveObject(this.mousePosition);
|
|
|
+ this.updateActiveObject(this.pointerPosition);
|
|
|
this.updateMouseCursor();
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
@@ -306,7 +357,7 @@ Graph.prototype.keyDown = function(e)
|
|
|
{
|
|
|
this.undoService.undo();
|
|
|
this.update();
|
|
|
- this.updateActiveObject(this.mousePosition);
|
|
|
+ this.updateActiveObject(this.pointerPosition);
|
|
|
this.updateMouseCursor();
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
@@ -315,7 +366,7 @@ Graph.prototype.keyDown = function(e)
|
|
|
{
|
|
|
this.undoService.redo();
|
|
|
this.update();
|
|
|
- this.updateActiveObject(this.mousePosition);
|
|
|
+ this.updateActiveObject(this.pointerPosition);
|
|
|
this.updateMouseCursor();
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
@@ -325,7 +376,7 @@ Graph.prototype.keyDown = function(e)
|
|
|
{
|
|
|
this.deleteSelection();
|
|
|
this.update();
|
|
|
- this.updateActiveObject(this.mousePosition);
|
|
|
+ this.updateActiveObject(this.pointerPosition);
|
|
|
this.updateMouseCursor();
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
@@ -346,7 +397,7 @@ Graph.prototype.keyDown = function(e)
|
|
|
}
|
|
|
|
|
|
this.update();
|
|
|
- this.updateActiveObject(this.mousePosition);
|
|
|
+ this.updateActiveObject(this.pointerPosition);
|
|
|
this.updateMouseCursor();
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
@@ -509,26 +560,40 @@ Graph.prototype.updateMouseCursor = function()
|
|
|
{
|
|
|
if (this.newConnection !== null)
|
|
|
{
|
|
|
- this.canvas.style.cursor = ((this.activeObject !== null) && (this.activeObject instanceof Connector)) ? this.activeObject.getCursor(this.mousePosition) : Cursors.cross;
|
|
|
+ this.canvas.style.cursor = ((this.activeObject !== null) && (this.activeObject instanceof Connector)) ? this.activeObject.getCursor(this.pointerPosition) : Cursors.cross;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- this.canvas.style.cursor = (this.activeObject !== null) ? this.activeObject.getCursor(this.mousePosition) : Cursors.arrow;
|
|
|
+ this.canvas.style.cursor = (this.activeObject !== null) ? this.activeObject.getCursor(this.pointerPosition) : Cursors.arrow;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Graph.prototype.updateMousePosition = function(e)
|
|
|
{
|
|
|
- this.mousePosition = new Point(e.pageX, e.pageY);
|
|
|
+ this.shiftKey = e.shiftKey;
|
|
|
+ this.pointerPosition = new Point(e.pageX, e.pageY);
|
|
|
var node = this.canvas;
|
|
|
while (node !== null)
|
|
|
{
|
|
|
- this.mousePosition.x -= node.offsetLeft;
|
|
|
- this.mousePosition.y -= node.offsetTop;
|
|
|
+ this.pointerPosition.x -= node.offsetLeft;
|
|
|
+ this.pointerPosition.y -= node.offsetTop;
|
|
|
node = node.offsetParent;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+Graph.prototype.updateTouchPosition = function(e)
|
|
|
+{
|
|
|
+ this.shiftKey = false;
|
|
|
+ this.pointerPosition = new Point(e.touches[0].pageX, e.touches[0].pageY);
|
|
|
+ var node = this.canvas;
|
|
|
+ while (node !== null)
|
|
|
+ {
|
|
|
+ this.pointerPosition.x -= node.offsetLeft;
|
|
|
+ this.pointerPosition.y -= node.offsetTop;
|
|
|
+ node = node.offsetParent;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
Graph.prototype.addElement = function(template, point, content)
|
|
|
{
|
|
|
this.activeTemplate = template;
|
|
|
@@ -542,7 +607,7 @@ Graph.prototype.addElement = function(template, point, content)
|
|
|
Graph.prototype.createElement = function(template)
|
|
|
{
|
|
|
this.activeTemplate = template;
|
|
|
- this.newElement = new Element(template, this.mousePosition);
|
|
|
+ this.newElement = new Element(template, this.pointerPosition);
|
|
|
this.update();
|
|
|
this.canvas.focus();
|
|
|
};
|