You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1714 lines
67 KiB
Plaintext
1714 lines
67 KiB
Plaintext
11 months ago
|
var connector_defaultConnectorTextSize = 12;
|
||
|
var connector_defaultConnectorTextStr = "";
|
||
|
var connector_defaultConnectorTextFont = "Arial";
|
||
|
var connector_defaultConnectorTextStrokeStyle = "#000000";
|
||
|
var connector_defaultConnectorTextFillStyle = "#000000";
|
||
|
var connector_defaultConnectorTextBgStyle = "#ffffff";
|
||
|
|
||
|
/**
|
||
|
*It's a connector between 2 figureConnectionPoints.
|
||
|
*
|
||
|
*@constructor
|
||
|
*@this {Connector}
|
||
|
*@param {Point} startPoint - the start of the line, where a ConnectionPoint will be added
|
||
|
*@param {Point} endPoint - the end of the line, where a ConnectionPoint will be added
|
||
|
*@param {String} type - the type of the Connector. It can be 'straight' or 'jagged'
|
||
|
*@param {Number} id - the unique (at least among other Connectors) id this connector will have
|
||
|
*@author Zack Newsham <zack_newsham@yahoo.co.uk>
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
*/
|
||
|
function Connector(startPoint, endPoint, type, id) {
|
||
|
/**Connector's id*/
|
||
|
this.id = id;
|
||
|
|
||
|
/**An {Array} of {Point}s. They will be used to draw the connector*/
|
||
|
this.turningPoints = [startPoint, endPoint];
|
||
|
|
||
|
/**Type of connector. Ex. TYPE_STRAIGHT*/
|
||
|
this.type = type;
|
||
|
|
||
|
/**An {Array} of {Object}s. Stores set of user manual changes to connector's shape.
|
||
|
* Structure of instance:
|
||
|
* - align: 'v' for vertical and 'h' for horizontal
|
||
|
* - delta: user defined offset from default position
|
||
|
* - index: index of turning point which is changed
|
||
|
* Note: the changes are not store in the order of the turning points, but
|
||
|
* the correspondence is made by 'index' field
|
||
|
* */
|
||
|
this.userChanges = [];
|
||
|
|
||
|
/**Solution of connector's shape calculated with ConnectionManager.connector2Points.
|
||
|
* It can be one of: 's0', 's1_1', 's2_2', etc. */
|
||
|
this.solution = '';
|
||
|
|
||
|
/**The {Style} this connector will have*/
|
||
|
this.style = new Style();
|
||
|
this.style.strokeStyle = "#b0b0b4";
|
||
|
this.style.lineWidth = 2; // fixes connector's display in Chrome for now
|
||
|
this.style.lineStyle = Style.LINE_STYLE_CONTINOUS;
|
||
|
|
||
|
/**The text that will appear in the middle of the connector*/
|
||
|
this.middleText = new Text(connector_defaultConnectorTextStr, (startPoint.x + endPoint.x) / 2 + 10, (startPoint.y + endPoint.y) / 2 - 13, connector_defaultConnectorTextFont, connector_defaultConnectorTextSize);
|
||
|
this.middleText.style.strokeStyle = connector_defaultConnectorTextStrokeStyle;
|
||
|
this.middleText.style.fillStyle = connector_defaultConnectorTextFillStyle;
|
||
|
this.middleText.bgStyle = connector_defaultConnectorTextBgStyle;
|
||
|
|
||
|
/**An {Array} of {BuilderProperties} to store exposed properties of the connector*/
|
||
|
this.properties = [];
|
||
|
|
||
|
this.properties.push(new BuilderProperty('线属性设置', 'group', BuilderProperty.TYPE_GROUP_LABEL));
|
||
|
this.properties.push(new BuilderProperty(BuilderProperty.SEPARATOR));
|
||
|
//this.properties.push(new BuilderProperty("Start Style", "startStyle", BuilderProperty.TYPE_CONNECTOR_END));
|
||
|
//this.properties.push(new BuilderProperty("End Style", "endStyle", BuilderProperty.TYPE_CONNECTOR_END));
|
||
|
this.properties.push(new BuilderProperty('粗细', 'style.lineWidth', BuilderProperty.TYPE_LINE_WIDTH));
|
||
|
//this.properties.push(new BuilderProperty('Line Style','style.lineStyle', BuilderProperty.TYPE_LINE_STYLE));
|
||
|
this.properties.push(new BuilderProperty('颜色', 'style.strokeStyle', BuilderProperty.TYPE_COLOR));
|
||
|
//this.properties.push(new BuilderProperty('Text','middleText.str', BuilderProperty.TYPE_TEXT));
|
||
|
//this.properties.push(new BuilderProperty('Text Size', 'middleText.size', BuilderProperty.TYPE_TEXT_FONT_SIZE));
|
||
|
//this.properties.push(new BuilderProperty('Font', 'middleText.font', BuilderProperty.TYPE_TEXT_FONT_FAMILY));
|
||
|
//this.properties.push(new BuilderProperty('Alignment', 'middleText.align', BuilderProperty.TYPE_TEXT_FONT_ALIGNMENT));
|
||
|
//this.properties.push(new BuilderProperty('Text Underlined', 'middleText.underlined', BuilderProperty.TYPE_TEXT_UNDERLINED));
|
||
|
//this.properties.push(new BuilderProperty('Text Color', 'middleText.style.fillStyle', BuilderProperty.TYPE_COLOR));
|
||
|
|
||
|
/**Start style for connector. Ex: Connector.STYLE_NORMAL*/
|
||
|
this.startStyle = Connector.STYLE_NORMAL;
|
||
|
|
||
|
/**End style for connector. Ex: Connector.STYLE_FILLED_TRIANGLE*/
|
||
|
this.endStyle = Connector.STYLE_NORMAL;
|
||
|
|
||
|
/**The {ConnectionPoint}'s id that is currently being dragged*/
|
||
|
this.activeConnectionPointId = -1;
|
||
|
|
||
|
/**Serialization type*/
|
||
|
this.oType = 'Connector'; //object type used for JSON deserialization
|
||
|
/**Object CCForm_Shape used for ccflow */
|
||
|
this.CCForm_Shape = "Connector";
|
||
|
/**Object CCForm_MyPK used for ccflow */
|
||
|
this.CCForm_MyPK = Util.NewGUID();
|
||
|
}
|
||
|
|
||
|
/**Straight connector type*/
|
||
|
Connector.TYPE_STRAIGHT = 'straight';
|
||
|
|
||
|
/**Jagged connector type*/
|
||
|
Connector.TYPE_JAGGED = 'jagged';
|
||
|
|
||
|
/**Round connector type. Orthogonal angles are smoothed.
|
||
|
*TODO: Not implemented*/
|
||
|
Connector.TYPE_ROUND = 'round';
|
||
|
|
||
|
/**Round connector type. The connector is drawn as a curve*/
|
||
|
Connector.TYPE_ORGANIC = 'organic';
|
||
|
|
||
|
|
||
|
|
||
|
/**Normal end connector style*/
|
||
|
Connector.STYLE_NORMAL = "Normal";
|
||
|
|
||
|
/**Arrow like end connector style*/
|
||
|
Connector.STYLE_ARROW = "Arrow";
|
||
|
|
||
|
/**Empty triangle end connector style*/
|
||
|
Connector.STYLE_EMPTY_TRIANGLE = "Empty";
|
||
|
|
||
|
/**Filled triangle end connector style*/
|
||
|
Connector.STYLE_FILLED_TRIANGLE = "Filled";
|
||
|
|
||
|
/**End connector arrow size*/
|
||
|
Connector.ARROW_SIZE = 12;
|
||
|
|
||
|
/**End connector arrow angle*/
|
||
|
Connector.ARROW_ANGLE = 15;
|
||
|
|
||
|
|
||
|
/**User change horizontal align*/
|
||
|
Connector.USER_CHANGE_HORIZONTAL_ALIGN = 'h';
|
||
|
|
||
|
/**User change vertical align*/
|
||
|
Connector.USER_CHANGE_VERTICAL_ALIGN = 'v';
|
||
|
|
||
|
|
||
|
/**Creates a {Connector} out of JSON parsed object
|
||
|
*@param {JSONObject} o - the JSON parsed object
|
||
|
*@return {Connector} a newly constructed Connector
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
Connector.load = function (o) {
|
||
|
var newConnector = new Connector(new Point(0, 0), new Point(0, 0), Connector.TYPE_STRAIGHT, 0); //fake constructor
|
||
|
|
||
|
newConnector.id = o.id;
|
||
|
newConnector.turningPoints = Point.loadArray(o.turningPoints);
|
||
|
newConnector.type = o.type;
|
||
|
newConnector.userChanges = o.userChanges;
|
||
|
newConnector.solution = o.solution;
|
||
|
newConnector.style = Style.load(o.style);
|
||
|
|
||
|
newConnector.middleText = Text.load(o.middleText);
|
||
|
|
||
|
newConnector.properties = BuilderProperty.loadArray(o.properties);
|
||
|
|
||
|
newConnector.endStyle = o.endStyle;
|
||
|
newConnector.startStyle = o.startStyle;
|
||
|
|
||
|
newConnector.activeConnectionPointId = o.activeConnectionPointId;
|
||
|
|
||
|
newConnector.CCForm_Shape = o.CCForm_Shape;
|
||
|
newConnector.CCForm_MyPK = o.CCForm_MyPK;
|
||
|
|
||
|
return newConnector;
|
||
|
}
|
||
|
|
||
|
/**Creates a an {Array} of {Connector} out of JSON parsed array
|
||
|
*@param {JSONObject} v - the JSON parsed {Array}
|
||
|
*@return {Array} of newly loaded {Connector}s
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
Connector.loadArray = function (v) {
|
||
|
var newConnectors = [];
|
||
|
|
||
|
for (var i = 0; i < v.length; i++) {
|
||
|
newConnectors.push(Connector.load(v[i]));
|
||
|
}
|
||
|
|
||
|
return newConnectors;
|
||
|
}
|
||
|
|
||
|
Connector.prototype = {
|
||
|
|
||
|
constructor: Connector,
|
||
|
|
||
|
|
||
|
/**
|
||
|
*Compares to another Connector
|
||
|
*
|
||
|
*@param {Connector} anotherConnector - the other connector
|
||
|
**/
|
||
|
equals: function (anotherConnector) {
|
||
|
if (!anotherConnector instanceof Connector) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//test turning points
|
||
|
for (var i = 0; i < this.turningPoints.length; i++) {
|
||
|
if (!this.turningPoints[i].equals(anotherConnector.turningPoints[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//test properties
|
||
|
for (var i = 0; i < this.properties.length; i++) {
|
||
|
if (!this.properties[i].equals(anotherConnector.properties[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//test user changes
|
||
|
for (var i = 0; i < this.userChanges.length; i++) {
|
||
|
if (this.userChanges[i].align != anotherConnector.userChanges[i].align
|
||
|
|| this.userChanges[i].index != anotherConnector.userChanges[i].index
|
||
|
|| this.userChanges[i].delta != anotherConnector.userChanges[i].delta) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.id != anotherConnector.id
|
||
|
|| this.type != anotherConnector.type
|
||
|
|| this.solution != anotherConnector.solution
|
||
|
|| !this.middleText.equals(anotherConnector.middleText)
|
||
|
|| this.startStyle != anotherConnector.startStyle
|
||
|
|| this.endStyle != anotherConnector.endStyle
|
||
|
|| this.activeConnectionPointId != anotherConnector.activeConnectionPointId) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
*Creates an arrow like figure, pointed down \/, at a certain position
|
||
|
* @param {Number} x - the X coordinates of the point
|
||
|
* @param {Number} y - the X coordinates of the point
|
||
|
* @return {Path} the arrow as a {Path} object
|
||
|
* @author Zack
|
||
|
**/
|
||
|
getArrow: function (x, y) {
|
||
|
var startPoint = new Point(x, y);
|
||
|
var line = new Line(startPoint.clone(), Util.getEndPoint(startPoint, Connector.ARROW_SIZE, Math.PI / 180 * Connector.ARROW_ANGLE));
|
||
|
var line1 = new Line(startPoint.clone(), Util.getEndPoint(startPoint, Connector.ARROW_SIZE, Math.PI / 180 * -Connector.ARROW_ANGLE));
|
||
|
|
||
|
var path = new Path();
|
||
|
|
||
|
path.style = this.style;
|
||
|
line.style = this.style;
|
||
|
line1.style = this.style;
|
||
|
|
||
|
path.addPrimitive(line);
|
||
|
path.addPrimitive(line1);
|
||
|
|
||
|
return path;
|
||
|
},
|
||
|
|
||
|
/**Creates a triangle like figure, pointed down \/, at a certain position
|
||
|
* @param {Number} x - the X coordinates of the point
|
||
|
* @param {Number} y - the X coordinates of the point
|
||
|
* @param {Boolean} fill - if true fill the triangle
|
||
|
* @return {Path} the arrow as a {Path} object
|
||
|
* @author Zack, Alex
|
||
|
* */
|
||
|
getTriangle: function (x, y, fill) {
|
||
|
|
||
|
var startPoint = new Point(x, y);
|
||
|
var point2 = Util.getEndPoint(startPoint, Connector.ARROW_SIZE, Math.PI / 180 * Connector.ARROW_ANGLE);
|
||
|
var point3 = Util.getEndPoint(startPoint, Connector.ARROW_SIZE, -Math.PI / 180 * Connector.ARROW_ANGLE);
|
||
|
|
||
|
var tri = new Polygon();
|
||
|
tri.addPoint(startPoint);
|
||
|
tri.addPoint(point2);
|
||
|
tri.addPoint(point3);
|
||
|
|
||
|
tri.style = this.style.clone();
|
||
|
if (fill) {
|
||
|
tri.style.fillStyle = this.style.strokeStyle;
|
||
|
}
|
||
|
else {
|
||
|
tri.style.fillStyle = '#FFFFFF';
|
||
|
}
|
||
|
|
||
|
return tri;
|
||
|
},
|
||
|
|
||
|
|
||
|
|
||
|
/**Paints the connector
|
||
|
*@param {CanvasRenderingContext2D} context - the 2D context of the canvas
|
||
|
*@author Alex, Zack, Artyom
|
||
|
**/
|
||
|
paint: function (context) {
|
||
|
//Do the start and end point match?
|
||
|
if (this.areStartEndPointsMatch()) {
|
||
|
// then not paint Connector at all
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
context.save();
|
||
|
|
||
|
this.style.setupContext(context);
|
||
|
|
||
|
switch (this.type) {
|
||
|
case Connector.TYPE_ORGANIC:
|
||
|
this.paintOrganic(context);
|
||
|
break;
|
||
|
|
||
|
case Connector.TYPE_STRAIGHT:
|
||
|
case Connector.TYPE_JAGGED:
|
||
|
context.beginPath();
|
||
|
|
||
|
//paint connector's line
|
||
|
context.moveTo(this.turningPoints[0].x, this.turningPoints[0].y);
|
||
|
|
||
|
for (var i = 1; i < this.turningPoints.length; i++) {
|
||
|
//start style
|
||
|
if (this.startStyle == Connector.STYLE_EMPTY_TRIANGLE && i == 1) { //special case
|
||
|
//get the angle of the start line
|
||
|
var angle = Util.getAngle(this.turningPoints[0], this.turningPoints[1]);
|
||
|
//by alex: var newPoint = Util.getEndPoint(this.turningPoints[0], Connector.ARROW_SIZE * Math.sin(Math.PI/180 * Connector.ARROW_ANGLE * 2), angle);
|
||
|
var newPoint = Util.getEndPoint(this.turningPoints[0], Connector.ARROW_SIZE * Math.cos(Math.PI / 180 * Connector.ARROW_ANGLE), angle);
|
||
|
//move to new start
|
||
|
context.moveTo(newPoint.x, newPoint.y);
|
||
|
}
|
||
|
|
||
|
//end style
|
||
|
if (this.endStyle == Connector.STYLE_EMPTY_TRIANGLE && i == this.turningPoints.length - 1) { //special case
|
||
|
//get the angle of the final line
|
||
|
var angle = Util.getAngle(this.turningPoints[i - 1], this.turningPoints[i]);
|
||
|
//by alex: var newPoint = Util.getEndPoint(this.turningPoints[i], -Connector.ARROW_SIZE*Math.sin(Math.PI/180*Connector.ARROW_ANGLE*2), angle)
|
||
|
var newPoint = Util.getEndPoint(this.turningPoints[i], -Connector.ARROW_SIZE * Math.cos(Math.PI / 180 * Connector.ARROW_ANGLE), angle)
|
||
|
//line to new end
|
||
|
context.lineTo(newPoint.x, newPoint.y);
|
||
|
}
|
||
|
else {
|
||
|
context.lineTo(this.turningPoints[i].x, this.turningPoints[i].y);
|
||
|
}
|
||
|
}
|
||
|
context.stroke();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
this.paintVisualDebug(context);
|
||
|
|
||
|
this.paintStart(context);
|
||
|
this.paintEnd(context);
|
||
|
|
||
|
this.paintText(context);
|
||
|
|
||
|
|
||
|
context.restore();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @param {CanvasRenderingContext2D} context the context to draw
|
||
|
* */
|
||
|
paintOrganic: function (context) {
|
||
|
//poly.style.strokeStyle = '#000000';
|
||
|
//poly.style.lineWidth = 1;
|
||
|
//poly.paint(context);
|
||
|
|
||
|
//paint NURBS
|
||
|
// var rPoints = Util.collinearReduction(this.turningPoints);
|
||
|
var rPoints = this.turningPoints;
|
||
|
Log.info("Connector:paint() - Number of reduced points: " + rPoints.length + " " + rPoints);
|
||
|
|
||
|
//1 - Draw NURB based only on turning points
|
||
|
var n = new NURBS(rPoints);
|
||
|
n.style.strokeStyle = 'rgba(0,100,0,0.5)'; //green
|
||
|
|
||
|
//paint glow
|
||
|
if (DIAGRAMO.debug) {
|
||
|
//Log.info("Nr of cubic curves " + this.fragments.length);
|
||
|
for (var f = 0; f < n.fragments.length; f++) {
|
||
|
var fragment = n.fragments[f].clone();
|
||
|
fragment.style.lineWidth = 6;
|
||
|
fragment.style.strokeStyle = "rgb(" + f * 100 % 255 + "," + f * 50 % 255 + "," + f * 20 % 255 + ")";
|
||
|
fragment.paint(context);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
n.paint(context);
|
||
|
//end 1
|
||
|
},
|
||
|
|
||
|
paintStart: function (context) {
|
||
|
//paint start style
|
||
|
var path = null;
|
||
|
if (this.startStyle == Connector.STYLE_ARROW) {
|
||
|
path = this.getArrow(this.turningPoints[0].x, this.turningPoints[0].y);
|
||
|
}
|
||
|
if (this.startStyle == Connector.STYLE_EMPTY_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, false);
|
||
|
}
|
||
|
if (this.startStyle == Connector.STYLE_FILLED_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, true);
|
||
|
}
|
||
|
|
||
|
|
||
|
//move start path(arrow, triangle, etc) into position
|
||
|
if (path) {
|
||
|
var transX = this.turningPoints[0].x;
|
||
|
var transY = this.turningPoints[0].y;
|
||
|
|
||
|
var lineAngle = Util.getAngle(this.turningPoints[0], this.turningPoints[1], 0);
|
||
|
path.transform(Matrix.translationMatrix(-transX, -transY));
|
||
|
path.transform(Matrix.rotationMatrix(lineAngle));
|
||
|
path.transform(Matrix.translationMatrix(transX, transY));
|
||
|
|
||
|
context.save();
|
||
|
|
||
|
//context.lineJoin = "miter";
|
||
|
context.lineJoin = "round";
|
||
|
context.lineCap = "round";
|
||
|
path.paint(context);
|
||
|
|
||
|
context.restore();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
paintEnd: function (context) {
|
||
|
//paint end style
|
||
|
var path = null;
|
||
|
if (this.endStyle == Connector.STYLE_ARROW) {
|
||
|
path = this.getArrow(this.turningPoints[this.turningPoints.length - 1].x, this.turningPoints[this.turningPoints.length - 1].y);
|
||
|
}
|
||
|
if (this.endStyle == Connector.STYLE_EMPTY_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[this.turningPoints.length - 1].x, this.turningPoints[this.turningPoints.length - 1].y, false);
|
||
|
}
|
||
|
if (this.endStyle == Connector.STYLE_FILLED_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[this.turningPoints.length - 1].x, this.turningPoints[this.turningPoints.length - 1].y, true);
|
||
|
}
|
||
|
|
||
|
//move end path (arrow, triangle, etc) into position
|
||
|
if (path) {
|
||
|
var transX = this.turningPoints[this.turningPoints.length - 1].x;
|
||
|
var transY = this.turningPoints[this.turningPoints.length - 1].y;
|
||
|
var lineAngle = Util.getAngle(this.turningPoints[this.turningPoints.length - 1], this.turningPoints[this.turningPoints.length - 2], 0);
|
||
|
|
||
|
path.transform(Matrix.translationMatrix(-transX, -transY));
|
||
|
path.transform(Matrix.rotationMatrix(lineAngle));
|
||
|
path.transform(Matrix.translationMatrix(transX, transY));
|
||
|
|
||
|
context.save();
|
||
|
|
||
|
context.lineJoin = "round";
|
||
|
context.lineCap = "round";
|
||
|
|
||
|
path.paint(context);
|
||
|
|
||
|
context.restore();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
|
||
|
paintVisualDebug: function (context) {
|
||
|
//paint debug points
|
||
|
if (DIAGRAMO.debug) {
|
||
|
context.beginPath();
|
||
|
for (var i = 0; i < this.turningPoints.length; i++) {
|
||
|
context.moveTo(this.turningPoints[i].x, this.turningPoints[i].y);
|
||
|
context.arc(this.turningPoints[i].x, this.turningPoints[i].y, 3, 0, Math.PI * 2, false);
|
||
|
|
||
|
//context.strokeText('' + Util.round(this.turningPoints[i].x,2) + ',' + Util.round(this.turningPoints[i].y,2), this.turningPoints[i].x + 5, this.turningPoints[i].y - 5);
|
||
|
}
|
||
|
context.stroke();
|
||
|
|
||
|
//paint coordinates
|
||
|
context.save();
|
||
|
for (var i = 0; i < this.turningPoints.length; i++) {
|
||
|
context.fillText('(' + Util.round(this.turningPoints[i].x, 3) + ', ' + Util.round(this.turningPoints[i].y, 3) + ')', this.turningPoints[i].x + 5, this.turningPoints[i].y - 5);
|
||
|
}
|
||
|
context.restore();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Paints the text of the connector
|
||
|
*@param {Context} context - the 2D context of the canvas
|
||
|
*@private
|
||
|
*@author Alex
|
||
|
**/
|
||
|
paintText: function (context) {
|
||
|
if (this.middleText.str != '') {
|
||
|
|
||
|
//TODO: not so smart to paint the background of the text
|
||
|
var oldFill = context.fillStyle;
|
||
|
|
||
|
context.beginPath();
|
||
|
var textBounds = this.middleText.getBounds();
|
||
|
context.moveTo(textBounds[0], textBounds[1]);
|
||
|
context.lineTo(textBounds[0], textBounds[3]);
|
||
|
context.lineTo(textBounds[2], textBounds[3]);
|
||
|
context.lineTo(textBounds[2], textBounds[1]);
|
||
|
context.fillStyle = "white";
|
||
|
context.closePath();
|
||
|
context.fill();
|
||
|
|
||
|
context.fillStyle = oldFill;
|
||
|
this.middleText.paint(context);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/*
|
||
|
*apply/clone another Connector style onto this connector
|
||
|
*@param{Connector} anotherConnector - another Connector
|
||
|
*@author dgq
|
||
|
*@deprecated
|
||
|
*/
|
||
|
applyAnotherConnectorStyle: function (anotherConnector) {
|
||
|
this.style = anotherConnector.style;
|
||
|
this.style.strokeStyle = anotherConnector.style.strokeStyle;
|
||
|
this.style.lineWidth = anotherConnector.style.lineWidth;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
*Apply a transformation to this Connector
|
||
|
*@param {Matrix} matrix - a matrix of numbers
|
||
|
**/
|
||
|
transform: function (matrix) {
|
||
|
this.activeConnectionPointId = -1;
|
||
|
if (SHIFT_PRESSED) {
|
||
|
var cps = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id);
|
||
|
var rStartPoint = cps[0];
|
||
|
var rEndPoint = cps[cps.length - 1];
|
||
|
var xSpan = rStartPoint.point.x - rEndPoint.point.x;
|
||
|
var ySpan = rStartPoint.point.y - rEndPoint.point.y;
|
||
|
//如果为横线,上下键只能是移动,左右键增长或缩短线长度
|
||
|
if (Math.abs(xSpan) > Math.abs(ySpan)) {
|
||
|
//计算左右点
|
||
|
var leftPoint = rStartPoint;
|
||
|
var rightPoint = rEndPoint;
|
||
|
if (rStartPoint.point.x > rEndPoint.point.x) {
|
||
|
rightPoint = rStartPoint;
|
||
|
leftPoint = rEndPoint;
|
||
|
}
|
||
|
//判断移动方向
|
||
|
if (Matrix.equals(matrix,Matrix.RIGHT) == true) {
|
||
|
this.activeConnectionPointId = rightPoint.id;
|
||
|
}
|
||
|
if (Matrix.equals(matrix,Matrix.LEFT) == true) {
|
||
|
this.activeConnectionPointId = leftPoint.id;
|
||
|
}
|
||
|
|
||
|
} else { //竖线
|
||
|
|
||
|
}
|
||
|
}
|
||
|
//are we moving the whole Connector, or just one point?
|
||
|
if (this.activeConnectionPointId != -1) {
|
||
|
var point = CONNECTOR_MANAGER.connectionPointGetById(this.activeConnectionPointId);
|
||
|
point.transform(matrix);
|
||
|
}
|
||
|
else {
|
||
|
for (var i = 0; i < this.turningPoints.length; i++) {
|
||
|
this.turningPoints[i].transform(matrix);
|
||
|
}
|
||
|
var cps = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id);
|
||
|
for (var j = 0; j < cps.length; j++) {
|
||
|
cps[j].transform(matrix);
|
||
|
}
|
||
|
//this.startText.transform(matrix);
|
||
|
//this.endText.transform(matrix);
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
*Creates as jagged(zig-zag) line between 2 ConnectionPoints
|
||
|
*@author Zack Newsham <zack_newsham@yahoo.co.uk>
|
||
|
*@deprecated
|
||
|
**/
|
||
|
jagged: function () {
|
||
|
this.jaggedReloaded();
|
||
|
return;
|
||
|
|
||
|
|
||
|
//reference to the start and end
|
||
|
var endPoint = this.turningPoints.pop();
|
||
|
var startPoint = this.turningPoints[0];
|
||
|
|
||
|
//the figure at the start
|
||
|
var startConnectionPoint = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0];
|
||
|
var glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(startConnectionPoint.id)[0]; //there will only be one for this
|
||
|
|
||
|
var startConnectionFigureId = CONNECTOR_MANAGER.connectionPointGet(glue.id1 == startConnectionPoint.id ? glue.id2 : glue.id1).parentId;
|
||
|
var startConnectionFigure = STACK.figureGetById(startConnectionFigureId);
|
||
|
|
||
|
var startCenterPoint;
|
||
|
if (startConnectionFigure) {
|
||
|
startCenterPoint = startConnectionFigure.rotationCoords[0];
|
||
|
}
|
||
|
else {
|
||
|
startCenterPoint = startPoint;
|
||
|
}
|
||
|
|
||
|
//the figure at the end
|
||
|
var endCon = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1];
|
||
|
glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(endCon.id)[0]; //there will only be one for this
|
||
|
var endConnectionFigure = CONNECTOR_MANAGER.connectionPointGet(glue.id1 == endCon.id ? glue.id2 : glue.id1).parentId;
|
||
|
endConnectionFigure = STACK.figureGetById(endConnectionFigure);
|
||
|
var endCenterPoint;
|
||
|
if (endConnectionFigure) {
|
||
|
endCenterPoint = endConnectionFigure.rotationCoords[0];
|
||
|
}
|
||
|
else {
|
||
|
endCenterPoint = endPoint;
|
||
|
}
|
||
|
|
||
|
//regardless of whih figure was clicked first, the left figure is start.
|
||
|
var swapped = false;
|
||
|
if (endCenterPoint.x < startCenterPoint.x) {
|
||
|
var t = endCenterPoint;
|
||
|
endCenterPoint = startCenterPoint;
|
||
|
startCenterPoint = t;
|
||
|
|
||
|
t = endConnectionFigure;
|
||
|
endConnectionFigure = startConnectionFigure;
|
||
|
startConnectionFigure = t;
|
||
|
|
||
|
t = endPoint;
|
||
|
endPoint = startPoint;
|
||
|
startPoint = t;
|
||
|
swapped = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
//we use this later
|
||
|
var endPoints = [endPoint];
|
||
|
|
||
|
//clear the array of all intermediate turningPoints, we use this when we have a connector that is moved from one connectionPoint to another
|
||
|
this.turningPoints = [startPoint];
|
||
|
|
||
|
//start+end+4 turning points
|
||
|
var nextPoint;
|
||
|
var startAngle = Util.getAngle(startCenterPoint, startPoint, Math.PI / 2);
|
||
|
var endAngle = Util.getAngle(endCenterPoint, endPoint, Math.PI / 2);
|
||
|
|
||
|
//move away from figure in angle(90) direction
|
||
|
|
||
|
//END FIGURE ESCAPE
|
||
|
if (endAngle == 0) {
|
||
|
nextPoint = new Point(endPoint.x, endConnectionFigure.getBounds()[1] - 20);
|
||
|
}
|
||
|
else if (endAngle == Math.PI / 2) {
|
||
|
nextPoint = new Point(endConnectionFigure.getBounds()[2] + 20, endPoint.y);
|
||
|
}
|
||
|
else if (endAngle == Math.PI) {
|
||
|
nextPoint = new Point(endPoint.x, endConnectionFigure.getBounds()[3] + 20);
|
||
|
}
|
||
|
else {
|
||
|
nextPoint = new Point(endConnectionFigure.getBounds()[0] - 20, endPoint.y);
|
||
|
}
|
||
|
endPoints.push(nextPoint);
|
||
|
endPoint = nextPoint;
|
||
|
|
||
|
var previousPoint = startPoint;
|
||
|
|
||
|
//START FIGURE ESCAPE
|
||
|
//clear bounds
|
||
|
//clear bounds by 20px in direction of angle
|
||
|
if (startAngle == 0) {
|
||
|
nextPoint = new Point(startPoint.x, startConnectionFigure.getBounds()[1] - 20);
|
||
|
}
|
||
|
else if (startAngle == Math.PI / 2) {
|
||
|
nextPoint = new Point(startConnectionFigure.getBounds()[2] + 20, startPoint.y);
|
||
|
}
|
||
|
else if (startAngle == Math.PI) {
|
||
|
nextPoint = new Point(startPoint.x, startConnectionFigure.getBounds()[3] + 20);
|
||
|
}
|
||
|
else {
|
||
|
nextPoint = new Point(startConnectionFigure.getBounds()[0] - 20, startPoint.y);
|
||
|
}
|
||
|
this.turningPoints.push(nextPoint);
|
||
|
|
||
|
startPoint = nextPoint;
|
||
|
|
||
|
var currentPoint = startPoint;
|
||
|
nextPoint = null;
|
||
|
var angles = [0, Math.PI / 2, Math.PI, Math.PI / 2 * 3, Math.PI * 2];
|
||
|
var startCounter = 0; //keeps track of new turning points added
|
||
|
var intEnd = Util.lineIntersectsRectangle(startPoint, endPoint, endConnectionFigure.getBounds());
|
||
|
var intStart = Util.lineIntersectsRectangle(startPoint, endPoint, startConnectionFigure.getBounds());
|
||
|
while (intEnd || intStart) {//while we have an intersection, keep trying
|
||
|
|
||
|
//get the angle of the last turn made, we know we need to do something 90degrees off this
|
||
|
startAngle = Util.getAngle(startPoint, this.turningPoints[this.turningPoints.length - 2], Math.PI / 2);
|
||
|
endAngle = Util.getAngle(endPoint, endPoints[endPoints.length - 2], Math.PI / 2);
|
||
|
switch (startCounter) {
|
||
|
case 0:
|
||
|
if (startAngle == 0 || startAngle == Math.PI) { //we were going N/S, now we want to go E/W
|
||
|
if (startPoint.x < endPoint.x) {
|
||
|
startPoint = new Point(startConnectionFigure.getBounds()[2] + 20, startPoint.y);
|
||
|
}
|
||
|
else {
|
||
|
startPoint = new Point(startConnectionFigure.getBounds()[0] - 20, startPoint.y);
|
||
|
}
|
||
|
}
|
||
|
else {//going E/W now want N/S
|
||
|
if (startPoint.y < endPoint.y || endPoint.y > startConnectionFigure.getBounds()[1]) {
|
||
|
startPoint = new Point(startPoint.x, startConnectionFigure.getBounds()[3] + 20);
|
||
|
}
|
||
|
else {
|
||
|
startPoint = new Point(startPoint.x, startConnectionFigure.getBounds()[1] - 20);
|
||
|
}
|
||
|
}
|
||
|
this.turningPoints.push(startPoint);
|
||
|
break;
|
||
|
case 1: //we have already done something to the startPoint, changing the end point should resolve the issue
|
||
|
endPoints.push(endPoint);
|
||
|
if (endAngle == 0 || endAngle == Math.PI) { //we were going N/S, now we want to go E/W
|
||
|
if (startPoint.x > endPoint.x) {
|
||
|
endPoint = new Point(endConnectionFigure.getBounds()[2] + 20, endPoint.y);
|
||
|
}
|
||
|
else {
|
||
|
endPoint = new Point(endConnectionFigure.getBounds()[0] - 20, endPoint.y);
|
||
|
}
|
||
|
}
|
||
|
else {//going E/W now want N/S
|
||
|
if (startPoint.y > endPoint.y) {
|
||
|
endPoint = new Point(endPoint.x, endConnectionFigure.getBounds()[3] + 20);
|
||
|
}
|
||
|
else {
|
||
|
endPoint = new Point(endPoint.x, endConnectionFigure.getBounds()[1] - 20);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
startCounter++;
|
||
|
intEnd = Util.lineIntersectsRectangle(startPoint, endPoint, endConnectionFigure.getBounds());
|
||
|
intStart = Util.lineIntersectsRectangle(startPoint, endPoint, startConnectionFigure.getBounds());
|
||
|
if (startCounter == 3) {//we have done all we can, if we still can't make a good jagged, make a bad one
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//there are no intersections of the straight line between start and end
|
||
|
//now lets see if making a jagged line will create one
|
||
|
//this should only occur when we need to make an opposite turn, that could lead to us running along the edge of one figures bounds
|
||
|
if (!Util.lineIntersectsRectangle(new Point(startPoint.x, endPoint.y), new Point(endPoint.x, endPoint.y), endConnectionFigure.getBounds())
|
||
|
&& !Util.lineIntersectsRectangle(new Point(startPoint.x, endPoint.y), new Point(endPoint.x, endPoint.y), startConnectionFigure.getBounds())
|
||
|
&& !Util.lineIntersectsRectangle(new Point(startPoint.x, startPoint.y), new Point(startPoint.x, endPoint.y), endConnectionFigure.getBounds())
|
||
|
&& !Util.lineIntersectsRectangle(new Point(startPoint.x, startPoint.y), new Point(startPoint.x, endPoint.y), startConnectionFigure.getBounds())) {
|
||
|
this.turningPoints.push(new Point(startPoint.x, endPoint.y));
|
||
|
}
|
||
|
else {//if(!Util.lineIntersectsRectangle(new Point(endPoint.x,startPoint.y), new Point(endPoint.x,endPoint.y), endConnectionFigure.getBounds()) && !Util.lineIntersectsRectangle(new Point(endPoint.x,startPoint.y), new Point(endPoint.x,endPoint.y), startConnectionFigure.getBounds())){
|
||
|
this.turningPoints.push(new Point(endPoint.x, startPoint.y));
|
||
|
}
|
||
|
/*else{//worst case scenario, we cant go up then across, cant go across then up, lets clear the end figure, and go up then across
|
||
|
var yMove=(startPoint.y>endPoint.y?endConnectionFigure.getBounds()[3]+20:endConnectionFigure.getBounds()[3]-20);
|
||
|
this.turningPoints.push(new Point(startPoint.x,yMove));
|
||
|
this.turningPoints.push(new Point(endPoint.x,yMove));
|
||
|
}*/
|
||
|
|
||
|
//add the endPoints we have changed to the line
|
||
|
this.turningPoints.push(new Point(endPoint.x, endPoint.y));
|
||
|
for (var i = 0; i < endPoints.length; i++) {
|
||
|
this.turningPoints.push(endPoints.pop());
|
||
|
i--; //lower the counter or we will only get half the points
|
||
|
}
|
||
|
|
||
|
//if our line was supposed to go backwards, lets reverse it
|
||
|
if (swapped) {
|
||
|
this.turningPoints = this.turningPoints.reverse();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
|
||
|
/**A rework of jagged method
|
||
|
*Just creates all turning points for Connector that has a StartPoint and an EndPoint
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
jaggedReloaded: function () {
|
||
|
|
||
|
//reference to the start and end
|
||
|
var startPoint = this.turningPoints[0];
|
||
|
var startExitPoint = null; //next turning point after the startPoint (if start figure present)
|
||
|
var endExitPoint = null; //the last turning point before endPoint (if end figure present)
|
||
|
var endPoint = this.turningPoints[this.turningPoints.length - 1];
|
||
|
|
||
|
|
||
|
|
||
|
//START FIGURE
|
||
|
var startConnectionPointOnConnector = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0]; //fist ConnectionPoint on the Connector
|
||
|
var glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(startConnectionPointOnConnector.id)[0]; //the (only) Glue tied to ConnectionPoint
|
||
|
|
||
|
if (glue != null) { //only if there is a Figure glued
|
||
|
//get ConnectionPoint on Figure
|
||
|
var startFigureConnectionPoint = CONNECTOR_MANAGER.connectionPointGet(glue.id1 == startConnectionPointOnConnector.id ? glue.id2 : glue.id1);
|
||
|
var startFigure = STACK.figureGetById(startFigureConnectionPoint.parentId);
|
||
|
|
||
|
var startAngle = Util.getAngle(startFigure.rotationCoords[0], startPoint, Math.PI / 2);
|
||
|
switch (startAngle) {
|
||
|
case 0: //north exit
|
||
|
startExitPoint = new Point(startPoint.x, startFigure.getBounds()[1] - 20);
|
||
|
break;
|
||
|
case Math.PI / 2: //east exit
|
||
|
startExitPoint = new Point(startFigure.getBounds()[2] + 20, startPoint.y);
|
||
|
break;
|
||
|
case Math.PI: //south exit
|
||
|
startExitPoint = new Point(startPoint.x, startFigure.getBounds()[3] + 20);
|
||
|
break;
|
||
|
case 3 * Math.PI / 2: //west exit
|
||
|
startExitPoint = new Point(startFigure.getBounds()[0] - 20, startPoint.y);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//END FIGURE
|
||
|
var endConnectionPointOnConnector = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1]; //last ConnectionPoint on Connector
|
||
|
glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(endConnectionPointOnConnector.id)[0]; //there will only be one for this
|
||
|
|
||
|
if (glue != null) { //only if there is a Figure glued
|
||
|
//get ConnectionPoint on Figure
|
||
|
var endFigureConnectionPoint = CONNECTOR_MANAGER.connectionPointGet(glue.id1 == endConnectionPointOnConnector.id ? glue.id2 : glue.id1);
|
||
|
var endFigure = STACK.figureGetById(endFigureConnectionPoint.parentId);
|
||
|
|
||
|
var endAngle = Util.getAngle(endFigure.rotationCoords[0], endPoint, Math.PI / 2);
|
||
|
switch (startAngle) {
|
||
|
case 0: //north exit
|
||
|
endExitPoint = new Point(endPoint.x, endFigure.getBounds()[1] - 20);
|
||
|
break;
|
||
|
case Math.PI / 2: //east exit
|
||
|
endExitPoint = new Point(endFigure.getBounds()[2] + 20, endPoint.y);
|
||
|
break;
|
||
|
case Math.PI: //south exit
|
||
|
endExitPoint = new Point(endPoint.x, endFigure.getBounds()[3] + 20);
|
||
|
break;
|
||
|
case 3 * Math.PI / 2: //west exit
|
||
|
endExitPoint = new Point(endFigure.getBounds()[0] - 20, endPoint.y);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
alert('jaggedReloaded:Connector has ' + this.turningPoints.length + " points");
|
||
|
this.turningPoints.splice(1, 0, startExitPoint, endExitPoint);
|
||
|
alert('jaggedReloaded:Connector has ' + this.turningPoints.length + " points");
|
||
|
},
|
||
|
|
||
|
/**This function simply tries to create all possible intermediate points that can be placed
|
||
|
*between 2 points to create a jagged connector
|
||
|
*@param {Point} p1 - a point
|
||
|
*@param {Point} p2 - the other point*/
|
||
|
connect2Points: function (p1, p2) {
|
||
|
var solutions = [];
|
||
|
|
||
|
//1. is p1 == p2?
|
||
|
if (p1.equals(p2)) {
|
||
|
|
||
|
}
|
||
|
|
||
|
//2. is p1 on a vertical or horizontal line with p2? S0
|
||
|
//3. can we have a single intermediate point? S1
|
||
|
//4. can we have 2 intermediate points? S2
|
||
|
return solutions;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
*Remove redundant points (we have just ajusted one of the handles of this figure, so)
|
||
|
**/
|
||
|
redraw: function () {
|
||
|
if (this.type == 'jagged') {
|
||
|
var changed = true;
|
||
|
while (changed == true) {
|
||
|
changed = false;
|
||
|
for (var i = 1; i < this.turningPoints.length - 2; i++) {
|
||
|
if (this.turningPoints[i].x == this.turningPoints[i - 1].x && this.turningPoints[i - 1].x == this.turningPoints[i + 1].x) {
|
||
|
this.turningPoints.splice(i, 1);
|
||
|
changed = true;
|
||
|
}
|
||
|
if (this.turningPoints[i].y == this.turningPoints[i - 1].y && this.turningPoints[i - 1].y == this.turningPoints[i + 1].y) {
|
||
|
this.turningPoints.splice(i, 1);
|
||
|
changed = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Transform a ConnectionPoint by a matrix. Usually called only by ConnectionManager.connectionPointTransform(),
|
||
|
* when a figure is being moved, so it's more or less start point or end point of a connector.
|
||
|
* Important to remember is that by moving and edge turning point all ther might be cases when more than one
|
||
|
* points need to change
|
||
|
* Once a figure is changed its ConnectionPoints got tranformed...so the glued Connector must
|
||
|
* change...it's like a cascade change
|
||
|
* @param {Matrix} matrix - the transformation to be used
|
||
|
* @param {Point} point - the point to start from (could be end or start). It is the point that
|
||
|
* triggered the adjustement
|
||
|
*/
|
||
|
adjust: function (matrix, point) {
|
||
|
|
||
|
//Log.info('Adjusting...');
|
||
|
if (this.type == Connector.TYPE_STRAIGHT) {
|
||
|
//Log.info("straight ");
|
||
|
|
||
|
var tempConPoint = CONNECTOR_MANAGER.connectionPointGetByParentAndCoordinates(this.id, point.x, point.y);
|
||
|
|
||
|
//find index of the turning point
|
||
|
var index = -1;
|
||
|
if (this.turningPoints[0].equals(point)) {
|
||
|
index = 0;
|
||
|
}
|
||
|
else if (this.turningPoints[1].equals(point)) {
|
||
|
index = 1;
|
||
|
}
|
||
|
else {
|
||
|
Log.error("Connector:adjust() - This should not happend" + this.toString() + ' point is ' + point);
|
||
|
}
|
||
|
|
||
|
|
||
|
//Log.info('\tinitial' + tempConPoint.toString());
|
||
|
tempConPoint.transform(matrix);
|
||
|
//Log.info('\tafter' + tempConPoint.toString());
|
||
|
|
||
|
|
||
|
this.turningPoints[index].x = tempConPoint.point.x;
|
||
|
this.turningPoints[index].y = tempConPoint.point.y;
|
||
|
|
||
|
/*TODO: it seems that the code bellow is not working fine...clone is wrong?
|
||
|
this.turningPoints[index] = new Point(tempConPoint.point.x,tempConPoint.point.y);
|
||
|
*/
|
||
|
|
||
|
}
|
||
|
|
||
|
if (this.type == Connector.TYPE_JAGGED) {
|
||
|
//Log.info("jagged ");
|
||
|
var oldX = point.x;
|
||
|
var oldY = point.y;
|
||
|
|
||
|
var tempConPoint = CONNECTOR_MANAGER.connectionPointGetByParentAndCoordinates(this.id, point.x, point.y);
|
||
|
tempConPoint.transform(matrix);
|
||
|
|
||
|
//are we starting from beginning or end, so we will detect the interval and direction
|
||
|
var start, end, direction;
|
||
|
if (point.equals(this.turningPoints[0])) {//if the point is the starting Point
|
||
|
//Log.info("It is the starting point");
|
||
|
|
||
|
//adjust first turning point
|
||
|
this.turningPoints[0].x = tempConPoint.point.x;
|
||
|
this.turningPoints[0].y = tempConPoint.point.y;
|
||
|
|
||
|
start = 1;
|
||
|
end = this.turningPoints.length;
|
||
|
direction = 1;
|
||
|
}
|
||
|
else if (point.equals(this.turningPoints[this.turningPoints.length - 1])) { //if the point is the ending Point
|
||
|
//Log.info("It is the ending point");
|
||
|
|
||
|
//adjust last turning point
|
||
|
this.turningPoints[this.turningPoints.length - 1].x = tempConPoint.point.x;
|
||
|
this.turningPoints[this.turningPoints.length - 1].y = tempConPoint.point.y;
|
||
|
|
||
|
start = this.turningPoints.length - 2;
|
||
|
end = -1;
|
||
|
direction = -1;
|
||
|
}
|
||
|
else {
|
||
|
Log.error("Connector:adjust() - this should never happen for point " + point + ' and connector ' + this.toString());
|
||
|
}
|
||
|
|
||
|
//TODO: the only affected turning point should be ONLY the next one (if start point) or previous one (if end point)
|
||
|
for (var i = start; i != end; i += direction) {
|
||
|
//If this turningPoints X==last turningPoints X (or Y), prior to transformation, then they used to be the same, so make them the same now
|
||
|
//dont do this if they are our start/end point
|
||
|
//we don't want to use them if they are on he exact spot
|
||
|
if (this.turningPoints[i].y != oldY
|
||
|
&& this.turningPoints[i].x == oldX //same x
|
||
|
&& this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0].point
|
||
|
&& this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1].point) {
|
||
|
oldX = this.turningPoints[i].x;
|
||
|
oldY = this.turningPoints[i].y;
|
||
|
this.turningPoints[i].x = this.turningPoints[i - direction].x;
|
||
|
}
|
||
|
else if (this.turningPoints[i].x != oldX
|
||
|
&& this.turningPoints[i].y == oldY
|
||
|
&& this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0].point
|
||
|
&& this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1].point) {
|
||
|
oldX = this.turningPoints[i].x;
|
||
|
oldY = this.turningPoints[i].y;
|
||
|
this.turningPoints[i].y = this.turningPoints[i - direction].y;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Applies solution from ConnectionManager.connector2Points() method.
|
||
|
*@param {Array} solutions - value returned from ConnectionManager.connector2Points()
|
||
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
||
|
*@author Alex
|
||
|
**/
|
||
|
applySolution: function (solutions) {
|
||
|
// solution category: 's0', 's1_1', 's2_2', etc.
|
||
|
var solutionCategory = solutions[0][1];
|
||
|
|
||
|
/*We should check if solution changed from previous.
|
||
|
* Solution determined by it's category (s1_2, s2_1) and number of turning points.*/
|
||
|
if (!this.solution //No solution?
|
||
|
|| this.solution != solutionCategory // Did category changed?
|
||
|
|| this.turningPoints.length != solutions[0][2].length) { // Did number of turning points changed?
|
||
|
this.solution = solutionCategory; // update solution
|
||
|
this.clearUserChanges(); // clear user changes
|
||
|
this.turningPoints = Point.cloneArray(solutions[0][2]); // update turning points
|
||
|
} else { //same solution (category and turning points no)
|
||
|
this.turningPoints = Point.cloneArray(solutions[0][2]); // get turning points from solution
|
||
|
this.applyUserChanges(); // apply user changes to turning points
|
||
|
}
|
||
|
|
||
|
this.updateMiddleText(); // update position of middle text
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Applies user changes to turning points.
|
||
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
||
|
**/
|
||
|
applyUserChanges: function () {
|
||
|
var changesLength = this.userChanges.length;
|
||
|
var currentChange;
|
||
|
var translationMatrix;
|
||
|
|
||
|
// go through and apply all changes
|
||
|
for (var i = 0; i < changesLength; i++) {
|
||
|
currentChange = this.userChanges[i];
|
||
|
|
||
|
// generate translation matrix
|
||
|
if (currentChange.align == Connector.USER_CHANGE_HORIZONTAL_ALIGN) { // Do we have horizontal change?
|
||
|
translationMatrix = Matrix.translationMatrix(currentChange.delta, 0); // apply horizontal delta
|
||
|
} else if (currentChange.align == Connector.USER_CHANGE_VERTICAL_ALIGN) { // Do we have vertical change?
|
||
|
translationMatrix = Matrix.translationMatrix(0, currentChange.delta); // apply vertical delta
|
||
|
}
|
||
|
// apply change
|
||
|
this.turningPoints[currentChange.index].transform(translationMatrix);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Adds user change.
|
||
|
*@param {Object} userChange - user change to add. It's form is
|
||
|
* {align : '', delta: '', index: ''} where
|
||
|
* align: Connector.USER_CHANGE_VERTICAL_ALIGN | Connector.USER_CHANGE_HORIZONTAL_ALIGN
|
||
|
* delta: Numeric
|
||
|
* index : the index of turning point
|
||
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
||
|
**/
|
||
|
addUserChange: function (userChange) {
|
||
|
var changesLength = this.userChanges.length;
|
||
|
var currentChange;
|
||
|
|
||
|
/*First seach if we need to merge current change with existing one,
|
||
|
* if no existing one present we will simply add it.*/
|
||
|
|
||
|
// Go through all changes (Merge option)
|
||
|
for (var i = 0; i < changesLength; i++) {
|
||
|
currentChange = this.userChanges[i];
|
||
|
|
||
|
// Do we have change with such align and index?
|
||
|
if (currentChange.align == userChange.align && currentChange.index == userChange.index) {
|
||
|
/* update delta of previous change
|
||
|
* we should accumulate delta value, not replace
|
||
|
* because current step here based on previous*/
|
||
|
currentChange.delta += userChange.delta;
|
||
|
return; // work is done - exit function
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// we have new change and add it to array (new change)
|
||
|
this.userChanges.push(userChange);
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Clears user changes.
|
||
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
||
|
**/
|
||
|
clearUserChanges: function () {
|
||
|
this.userChanges = [];
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Clones array of user changes.
|
||
|
*@return {Array} - array containing current user changes
|
||
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
||
|
**/
|
||
|
cloneUserChanges: function () {
|
||
|
var clonedArray = [];
|
||
|
var changesLength = this.userChanges.length;
|
||
|
|
||
|
// go through and clone all user changes
|
||
|
for (var i = 0; i < changesLength; i++) {
|
||
|
// create new instance of user changes
|
||
|
// set values equal to current user change
|
||
|
// push new instance in result array with cloned user changes
|
||
|
clonedArray.push({
|
||
|
align: this.userChanges[i].align,
|
||
|
index: this.userChanges[i].index,
|
||
|
delta: this.userChanges[i].delta
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return clonedArray;
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Check if start and end members of turningPoints match/are the same.
|
||
|
*@return {Boolean} - match or not
|
||
|
*@author Artyom Pokatilov <artyom.pokatilov@gmail.com>
|
||
|
**/
|
||
|
areStartEndPointsMatch: function () {
|
||
|
return this.turningPoints[0].equals(this.turningPoints[this.turningPoints.length - 1]);
|
||
|
},
|
||
|
|
||
|
|
||
|
/**
|
||
|
* See if a file is on a connector
|
||
|
* @param {Number} x - coordinate
|
||
|
* @param {Number} y - coordinate
|
||
|
* @author alex
|
||
|
*/
|
||
|
contains: function (x, y) {
|
||
|
var r = false;
|
||
|
switch (this.type) {
|
||
|
|
||
|
case Connector.TYPE_STRAIGHT:
|
||
|
//just fall :)
|
||
|
|
||
|
case Connector.TYPE_JAGGED:
|
||
|
for (var i = 0; i < this.turningPoints.length - 1; i++) {
|
||
|
var l = new Line(this.turningPoints[i], this.turningPoints[i + 1]);
|
||
|
if (l.contains(x, y)) {
|
||
|
r = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case Connector.TYPE_ORGANIC:
|
||
|
var n = new NURBS(this.turningPoints);
|
||
|
|
||
|
r = n.contains(x, y);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
},
|
||
|
|
||
|
/**Tests if a point defined by (x,y) is within a radius
|
||
|
*@param {Number} x - x coordinates of the point
|
||
|
*@param {Number} y - y coordinates of the point
|
||
|
*@param {Number} radius - the radius to seach within
|
||
|
*@author alex
|
||
|
**/
|
||
|
near: function (x, y, radius) {
|
||
|
var r = false;
|
||
|
switch (this.type) {
|
||
|
case Connector.TYPE_STRAIGHT:
|
||
|
//just fall :)
|
||
|
case Connector.TYPE_JAGGED:
|
||
|
case Connector.STYLE_NORMAL:
|
||
|
for (var i = 0; i < this.turningPoints.length - 1; i++) {
|
||
|
var l = new Line(this.turningPoints[i], this.turningPoints[i + 1]);
|
||
|
if (l.near(x, y, radius)) {
|
||
|
r = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case Connector.TYPE_ORGANIC:
|
||
|
var n = new NURBS(this.turningPoints);
|
||
|
r = n.near(x, y, radius);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
},
|
||
|
clone: function () {
|
||
|
var startPoint = this.turningPoints[0].clone();
|
||
|
var endPoint = this.turningPoints[1].clone();
|
||
|
|
||
|
var cId = CONNECTOR_MANAGER.connectorCreate(startPoint, endPoint, Connector.TYPE_STRAIGHT);
|
||
|
var conn = CONNECTOR_MANAGER.connectorGetById(cId)
|
||
|
//solutions
|
||
|
var candidate = CONNECTOR_MANAGER.getClosestPointsOfConnection(false, false, -1, startPoint, -1, endPoint);
|
||
|
var rStartBounds = null;
|
||
|
var rEndBounds = null;
|
||
|
DIAGRAMO.debugSolutions = CONNECTOR_MANAGER.connector2Points(Connector.TYPE_STRAIGHT, candidate[0], candidate[1], rStartBounds, rEndBounds);
|
||
|
|
||
|
conn.style = this.style;
|
||
|
conn.style.strokeStyle = this.style.strokeStyle;
|
||
|
conn.style.lineWidth = this.style.lineWidth;
|
||
|
return conn;
|
||
|
},
|
||
|
|
||
|
/**Returns the middle of a connector
|
||
|
*Usefull for setting up the middle text
|
||
|
*@return {Array} of 2 {Number}s - the x and y of the point
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
middle: function () {
|
||
|
if (this.type == Connector.TYPE_STRAIGHT) {
|
||
|
var middleX = (this.turningPoints[0].x + this.turningPoints[1].x) / 2;
|
||
|
var middleY = (this.turningPoints[0].y + this.turningPoints[1].y) / 2;
|
||
|
return [middleX, middleY];
|
||
|
}
|
||
|
else if (this.type == Connector.TYPE_JAGGED) {
|
||
|
/** Algorithm:
|
||
|
* Find the lenght of the connector. Then go on each segment until we will reach half of the
|
||
|
* connector's lenght.
|
||
|
**/
|
||
|
|
||
|
//find total distance
|
||
|
var distance = 0;
|
||
|
for (var i = 0; i < this.turningPoints.length - 1; i++) {
|
||
|
distance += Util.getLength(this.turningPoints[i], this.turningPoints[i + 1]);
|
||
|
}
|
||
|
|
||
|
//find between what turning points the half distance is
|
||
|
var index = -1;
|
||
|
var ellapsedDistance = 0;
|
||
|
for (var i = 0; i < this.turningPoints.length - 1; i++) {
|
||
|
index = i;
|
||
|
var segment = Util.getLength(this.turningPoints[i], this.turningPoints[i + 1]);
|
||
|
if (ellapsedDistance + segment < distance / 2) {
|
||
|
ellapsedDistance += segment;
|
||
|
}
|
||
|
else {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//we have the middle distance somewhere between i(ndex) and i(ndex)+1
|
||
|
if (index != -1) {
|
||
|
var missingDistance = distance / 2 - ellapsedDistance;
|
||
|
if (Util.round(this.turningPoints[index].x, 3) == Util.round(this.turningPoints[index + 1].x, 3)) { //vertical segment (same x)
|
||
|
return [this.turningPoints[index].x, Math.min(this.turningPoints[index].y, this.turningPoints[index + 1].y) + missingDistance];
|
||
|
} else if (Util.round(this.turningPoints[index].y, 3) == Util.round(this.turningPoints[index + 1].y, 3)) { //horizontal segment (same y)
|
||
|
return [Math.min(this.turningPoints[index].x, this.turningPoints[index + 1].x) + missingDistance, this.turningPoints[index].y];
|
||
|
} else {
|
||
|
Log.error("Connector:middle() - this should never happen " + this.turningPoints[index] + " " + this.turningPoints[index + 1]
|
||
|
+ " nr of points " + this.turningPoints.length
|
||
|
);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
} else if (this.type === Connector.TYPE_ORGANIC) {
|
||
|
//TODO: Either compute the middle using pure NURB algorithm (and use t=0.5) or
|
||
|
//base it on the curves already computed (but they might no be evenly distributes
|
||
|
//(or might not have the same length) to pick the middle of middle curve
|
||
|
//(if no. of curves is odd) or joining
|
||
|
//point (if number of curves is even)
|
||
|
var n = new NURBS(this.turningPoints);
|
||
|
|
||
|
var middle = n.getMiddle();
|
||
|
Log.info("Middle is " + middle);
|
||
|
|
||
|
return [middle.x, middle.y];
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Updates the middle text of the connector
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
updateMiddleText: function () {
|
||
|
// Log.info("updateMiddleText called");
|
||
|
var middlePoint = this.middle();
|
||
|
|
||
|
if (middlePoint != null) {
|
||
|
var m = Matrix.translationMatrix(middlePoint[0] - this.middleText.vector[0].x, middlePoint[1] - this.middleText.vector[0].y)
|
||
|
this.middleText.transform(m);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**Founds the bounds of the connector
|
||
|
*@return {Array} - the [minX, minY, maxX, maxY]
|
||
|
**/
|
||
|
getBounds: function () {
|
||
|
var minX = null;
|
||
|
var minY = null;
|
||
|
var maxX = null;
|
||
|
var maxY = null;
|
||
|
for (var i = 0; i < this.turningPoints.length; i++) {
|
||
|
if (this.turningPoints[i].x < minX || minX == null)
|
||
|
minX = this.turningPoints[i].x;
|
||
|
if (this.turningPoints[i].x > maxX || maxX == null)
|
||
|
maxX = this.turningPoints[i].x;
|
||
|
if (this.turningPoints[i].y < minY || minY == null)
|
||
|
minY = this.turningPoints[i].y;
|
||
|
if (this.turningPoints[i].y > maxY || maxY == null)
|
||
|
maxY = this.turningPoints[i].y;
|
||
|
}
|
||
|
return [minX, minY, maxX, maxY];
|
||
|
},
|
||
|
|
||
|
/**String representation*/
|
||
|
toString: function () {
|
||
|
return 'Connector : (id = ' + this.id
|
||
|
+ ', type = ' + this.type
|
||
|
+ ', turningPoints = [' + this.turningPoints + ']'
|
||
|
+ ', userChanges = [' + this.userChanges + ']'
|
||
|
+ ', solution = ' + this.solution
|
||
|
+ ', startStyle = ' + this.startStyle
|
||
|
+ ', endStyle = ' + this.endStyle
|
||
|
+ ', activeConnectionPointId = ' + this.activeConnectionPointId
|
||
|
+ ')';
|
||
|
},
|
||
|
|
||
|
|
||
|
/**SVG representation of the connector
|
||
|
*@return {String} - the SVG part
|
||
|
**/
|
||
|
toSVG: function () {
|
||
|
|
||
|
//1. paint line
|
||
|
var r = '<polyline points="';
|
||
|
for (var i = 0; i < this.turningPoints.length; i++) {
|
||
|
r += this.turningPoints[i].x + ',' + this.turningPoints[i].y + ' ';
|
||
|
}
|
||
|
r += '"';
|
||
|
r += this.style.toSVG();
|
||
|
// r += ' style="fill: #none; stroke:#ADADAD;" ';
|
||
|
r += '/>';
|
||
|
|
||
|
//2. paint the start/end
|
||
|
//paint start style
|
||
|
var path = null;
|
||
|
if (this.startStyle == Connector.STYLE_ARROW) {
|
||
|
path = this.getArrow(this.turningPoints[0].x, this.turningPoints[0].y);
|
||
|
}
|
||
|
if (this.startStyle == Connector.STYLE_EMPTY_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, false);
|
||
|
}
|
||
|
if (this.startStyle == Connector.STYLE_FILLED_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, true);
|
||
|
}
|
||
|
|
||
|
if (path) {
|
||
|
var transX = this.turningPoints[0].x;
|
||
|
var transY = this.turningPoints[0].y;
|
||
|
|
||
|
var lineAngle = Util.getAngle(this.turningPoints[0], this.turningPoints[1], 0);
|
||
|
path.transform(Matrix.translationMatrix(-transX, -transY));
|
||
|
path.transform(Matrix.rotationMatrix(lineAngle));
|
||
|
path.transform(Matrix.translationMatrix(transX, transY));
|
||
|
|
||
|
r += path.toSVG();
|
||
|
}
|
||
|
|
||
|
|
||
|
//paint end style
|
||
|
if (this.endStyle == Connector.STYLE_ARROW) {
|
||
|
path = this.getArrow(this.turningPoints[this.turningPoints.length - 1].x, this.turningPoints[this.turningPoints.length - 1].y);
|
||
|
}
|
||
|
if (this.endStyle == Connector.STYLE_EMPTY_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[this.turningPoints.length - 1].x, this.turningPoints[this.turningPoints.length - 1].y, false);
|
||
|
}
|
||
|
if (this.endStyle == Connector.STYLE_FILLED_TRIANGLE) {
|
||
|
path = this.getTriangle(this.turningPoints[this.turningPoints.length - 1].x, this.turningPoints[this.turningPoints.length - 1].y, true);
|
||
|
}
|
||
|
//move end path (arrow, triangle, etc) into position
|
||
|
if (path) {
|
||
|
var transX = this.turningPoints[this.turningPoints.length - 1].x;
|
||
|
var transY = this.turningPoints[this.turningPoints.length - 1].y;
|
||
|
var lineAngle = Util.getAngle(this.turningPoints[this.turningPoints.length - 1], this.turningPoints[this.turningPoints.length - 2], 0);
|
||
|
|
||
|
path.transform(Matrix.translationMatrix(-transX, -transY));
|
||
|
path.transform(Matrix.rotationMatrix(lineAngle));
|
||
|
path.transform(Matrix.translationMatrix(transX, transY));
|
||
|
|
||
|
r += path.toSVG();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//3. pain text (if any)
|
||
|
if (this.middleText.str.length != 1) {
|
||
|
//paint white background
|
||
|
var txtBounds = this.middleText.getBounds(); //this is actually an array of numbers [minX, minY, maxX, maxY]
|
||
|
|
||
|
var poly = new Polygon();
|
||
|
|
||
|
poly.addPoint(new Point(txtBounds[0], txtBounds[1]));
|
||
|
poly.addPoint(new Point(txtBounds[2], txtBounds[1]));
|
||
|
poly.addPoint(new Point(txtBounds[2], txtBounds[3]));
|
||
|
poly.addPoint(new Point(txtBounds[0], txtBounds[3]));
|
||
|
poly.style.fillStyle = "#FFFFFF";
|
||
|
|
||
|
r += poly.toSVG();
|
||
|
|
||
|
|
||
|
//paint actuall text
|
||
|
r += this.middleText.toSVG();
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*A connection point that is attached to a figure and can accept connectors
|
||
|
*
|
||
|
*@constructor
|
||
|
*@this {ConnectionPoint}
|
||
|
*@param {Number} parentId - the parent to which this ConnectionPoint is attached. It can be either a {Figure} or a {Connector}
|
||
|
*@param {Point} point - coordinate of this connection point, better than using x and y, because when we move "snap to" this
|
||
|
* connectionPoint the line will follow
|
||
|
*@param {Number} id - unique id to the parent figure
|
||
|
*@param {String} type - the type of the parent. It can be either 'figure' or 'connector'
|
||
|
*
|
||
|
*@author Zack Newsham <zack_newsham@yahoo.co.uk>
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
*/
|
||
|
function ConnectionPoint(parentId, point, id, type) {
|
||
|
/**Connection point id*/
|
||
|
this.id = id;
|
||
|
|
||
|
/**The {Point} that is behind this ConnectionPoint*/
|
||
|
this.point = point.clone(); //we will create a clone so that no side effect will appear
|
||
|
|
||
|
/**Parent id (id of the Figure or Connector)*/
|
||
|
this.parentId = parentId;
|
||
|
|
||
|
/**Type of ConnectionPoint. Ex: ConnectionPoint.TYPE_FIGURE*/
|
||
|
this.type = type;
|
||
|
|
||
|
/**Current connection point color*/
|
||
|
this.color = ConnectionPoint.NORMAL_COLOR;
|
||
|
|
||
|
/**Radius of the connection point*/
|
||
|
this.radius = 3;
|
||
|
|
||
|
/**Serialization type*/
|
||
|
this.oType = 'ConnectionPoint'; //object type used for JSON deserialization
|
||
|
|
||
|
}
|
||
|
|
||
|
/**Color used by default to draw the connection point*/
|
||
|
ConnectionPoint.NORMAL_COLOR = "#FFFF33"; //yellow.
|
||
|
|
||
|
/*Color used to signal that the 2 connection points are about to glue*/
|
||
|
ConnectionPoint.OVER_COLOR = "#FF9900"; //orange
|
||
|
|
||
|
/*Color used to draw connected (glued) connection points*/
|
||
|
ConnectionPoint.CONNECTED_COLOR = "#ff0000"; //red
|
||
|
|
||
|
/**Connection point default radius*/
|
||
|
ConnectionPoint.RADIUS = 4;
|
||
|
|
||
|
/**Connection point (liked to)/ type figure*/
|
||
|
ConnectionPoint.TYPE_FIGURE = 'figure';
|
||
|
|
||
|
/**Connection point (liked to)/ type connector*/
|
||
|
ConnectionPoint.TYPE_CONNECTOR = 'connector';
|
||
|
|
||
|
|
||
|
/**Creates a {ConnectionPoint} out of JSON parsed object
|
||
|
*@param {JSONObject} o - the JSON parsed object
|
||
|
*@return {ConnectionPoint} a newly constructed ConnectionPoint
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
ConnectionPoint.load = function (o) {
|
||
|
var newConnectionPoint = new ConnectionPoint(0, new Point(0, 0), ConnectionPoint.TYPE_FIGURE); //fake constructor
|
||
|
|
||
|
newConnectionPoint.id = o.id;
|
||
|
newConnectionPoint.point = Point.load(o.point);
|
||
|
newConnectionPoint.parentId = o.parentId;
|
||
|
newConnectionPoint.type = o.type;
|
||
|
|
||
|
newConnectionPoint.color = o.color;
|
||
|
newConnectionPoint.radius = o.radius;
|
||
|
|
||
|
return newConnectionPoint;
|
||
|
}
|
||
|
|
||
|
/**Creates a an {Array} of {ConnectionPoint} out of JSON parsed array
|
||
|
*@param {JSONObject} v - the JSON parsed {Array}
|
||
|
*@return {Array} of newly loaded {ConnectionPoint}s
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
ConnectionPoint.loadArray = function (v) {
|
||
|
var newConnectionPoints = [];
|
||
|
|
||
|
for (var i = 0; i < v.length; i++) {
|
||
|
newConnectionPoints.push(ConnectionPoint.load(v[i]));
|
||
|
}
|
||
|
|
||
|
return newConnectionPoints;
|
||
|
}
|
||
|
|
||
|
/**Clones an array of {ConnectionPoint}s
|
||
|
*@param {Array} v - the array of {ConnectionPoint}s
|
||
|
*@return an {Array} of {ConnectionPoint}s
|
||
|
**/
|
||
|
ConnectionPoint.cloneArray = function (v) {
|
||
|
var newConnectionPoints = [];
|
||
|
for (var i = 0; i < v.length; i++) {
|
||
|
newConnectionPoints.push(v[i].clone());
|
||
|
}
|
||
|
return newConnectionPoints;
|
||
|
}
|
||
|
|
||
|
|
||
|
ConnectionPoint.prototype = {
|
||
|
constructor: ConnectionPoint,
|
||
|
|
||
|
|
||
|
/**Clone current {ConnectionPoint}
|
||
|
**/
|
||
|
clone: function () {
|
||
|
//parentId,point,id, type
|
||
|
return new ConnectionPoint(this.parentId, this.point.clone(), this.id, this.type);
|
||
|
},
|
||
|
|
||
|
/**Compares to another ConnectionPoint
|
||
|
*@param {ConnectionPoint} anotherConnectionPoint - the other connection point
|
||
|
*@return {Boolean} - true if equals, false otherwise
|
||
|
**/
|
||
|
equals: function (anotherConnectionPoint) {
|
||
|
|
||
|
return this.id == anotherConnectionPoint.id
|
||
|
&& this.point.equals(anotherConnectionPoint.point)
|
||
|
&& this.parentId == anotherConnectionPoint.parentId
|
||
|
&& this.type == anotherConnectionPoint.type
|
||
|
&& this.color == anotherConnectionPoint.color
|
||
|
&& this.radius == anotherConnectionPoint.radius;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
*Paints the ConnectionPoint into a Context
|
||
|
*@param {Context} context - the 2D context
|
||
|
**/
|
||
|
paint: function (context) {
|
||
|
context.save();
|
||
|
context.fillStyle = this.color;
|
||
|
context.strokeStyle = '#000000';
|
||
|
context.lineWidth = defaultThinLineWidth;
|
||
|
context.beginPath();
|
||
|
context.arc(this.point.x, this.point.y, ConnectionPoint.RADIUS, 0, (Math.PI / 180) * 360, false);
|
||
|
context.stroke();
|
||
|
context.fill();
|
||
|
context.restore();
|
||
|
},
|
||
|
|
||
|
|
||
|
/**
|
||
|
*Transform the ConnectionPoint through a Matrix
|
||
|
*@param {Matrix} matrix - the transformation matrix
|
||
|
**/
|
||
|
transform: function (matrix) {
|
||
|
this.point.transform(matrix);
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Highlight the connection point*/
|
||
|
highlight: function () {
|
||
|
this.color = ConnectionPoint.OVER_COLOR;
|
||
|
},
|
||
|
|
||
|
/**Un-highlight the connection point*/
|
||
|
unhighlight: function () {
|
||
|
this.color = ConnectionPoint.NORMAL_COLOR;
|
||
|
},
|
||
|
|
||
|
|
||
|
/**Tests to see if a point (x, y) is within a range of current ConnectionPoint
|
||
|
*@param {Numeric} x - the x coordinate of tested point
|
||
|
*@param {Numeric} y - the x coordinate of tested point
|
||
|
*@return {Boolean} - true if inside, false otherwise
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
contains: function (x, y) {
|
||
|
return this.near(x, y, ConnectionPoint.RADIUS);
|
||
|
},
|
||
|
|
||
|
/**Tests to see if a point (x, y) is within a specified range of current ConnectionPoint
|
||
|
*@param {Numeric} x - the x coordinate of tested point
|
||
|
*@param {Numeric} y - the x coordinate of tested point
|
||
|
*@param {Numeric} radius - the radius around this point
|
||
|
*@return {Boolean} - true if inside, false otherwise
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
near: function (x, y, radius) {
|
||
|
return new Point(this.point.x, this.point.y).near(x, y, radius);
|
||
|
},
|
||
|
|
||
|
|
||
|
/**A String representation of the point*/
|
||
|
toString: function () {
|
||
|
return "ConnectionPoint id = " + this.id + ' point = [' + this.point + '] ,type = ' + this.type + ", parentId = " + this.parentId + ")";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**A Glue just glues together 2 ConnectionPoints.
|
||
|
*Glued ConnectionPoints usually belongs to a Connector and a Figure.
|
||
|
*
|
||
|
*@constructor
|
||
|
*@this {Glue}
|
||
|
*@param {Number} cp1Id - the id of the first {ConnectionPoint} (usually from a {Figure})
|
||
|
*@param {Number} cp2Id - the id of the second {ConnectionPoint} (usualy from a {Connector})
|
||
|
*@param {Boolean} automatic - type of connection connector to a figure:
|
||
|
* if true - {Connector} connects a {Figure} itself
|
||
|
* else - {Connector} connects specific {ConnectionPoint} of {Figure}
|
||
|
**/
|
||
|
function Glue(cp1Id, cp2Id, automatic) {
|
||
|
/**First shape's id (usually from a {Figure})*/
|
||
|
this.id1 = cp1Id;
|
||
|
|
||
|
/**Second shape's id (usualy from a {Connector})*/
|
||
|
this.id2 = cp2Id;
|
||
|
|
||
|
/*By default all the Glues are created with the first number as Figure's id and second number as
|
||
|
*Connector's id. In the future glues can be used to glue other types as well*/
|
||
|
|
||
|
/**First id type (usually 'figure')*/
|
||
|
this.type1 = 'figure';
|
||
|
|
||
|
/**First id type (usually 'connector')*/
|
||
|
this.type2 = 'connector';
|
||
|
|
||
|
/**object type used for JSON deserialization*/
|
||
|
this.oType = 'Glue';
|
||
|
|
||
|
/**Type of connector's behaviour:
|
||
|
* if it's true - connector connects the whole figure and touches it's optimum connection point
|
||
|
* if it's false - connector connects one fixed connection point of the figure
|
||
|
* */
|
||
|
this.automatic = automatic;
|
||
|
}
|
||
|
|
||
|
/**Creates a {Glue} out of JSON parsed object
|
||
|
*@param {JSONObject} o - the JSON parsed object
|
||
|
*@return {Glue} a newly constructed Glue
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
Glue.load = function (o) {
|
||
|
var newGlue = new Glue(-1, -1, false); //fake constructor
|
||
|
|
||
|
newGlue.id1 = o.id1;
|
||
|
newGlue.id2 = o.id2;
|
||
|
newGlue.type1 = o.type1;
|
||
|
newGlue.type2 = o.type2;
|
||
|
newGlue.automatic = o.automatic ? o.automatic : false;
|
||
|
|
||
|
return newGlue;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**Creates a an {Array} of {Glue} out of JSON parsed array
|
||
|
*@param {JSONObject} v - the JSON parsed {Array}
|
||
|
*@return {Array} of newly loaded {Glue}s
|
||
|
*@author Alex Gheorghiu <alex@scriptoid.com>
|
||
|
**/
|
||
|
Glue.loadArray = function (v) {
|
||
|
var newGlues = [];
|
||
|
|
||
|
for (var i = 0; i < v.length; i++) {
|
||
|
newGlues.push(Glue.load(v[i]));
|
||
|
}
|
||
|
|
||
|
return newGlues;
|
||
|
}
|
||
|
|
||
|
/**Clones an array of points
|
||
|
*@param {Array} v - the array of {Glue}s
|
||
|
*@return an {Array} of {Glue}s
|
||
|
**/
|
||
|
Glue.cloneArray = function (v) {
|
||
|
var newGlues = [];
|
||
|
for (var i = 0; i < v.length; i++) {
|
||
|
newGlues.push(v[i].clone());
|
||
|
}
|
||
|
return newGlues;
|
||
|
}
|
||
|
|
||
|
Glue.prototype = {
|
||
|
|
||
|
constructor: Glue,
|
||
|
|
||
|
|
||
|
/**Clone current {Glue}
|
||
|
**/
|
||
|
clone: function () {
|
||
|
return new Glue(this.id1, this.id2, this.automatic);
|
||
|
},
|
||
|
|
||
|
/**Compares to another Glue
|
||
|
*@param {Glue} anotherGlue - - the other glue
|
||
|
*@return {Boolean} - true if equals, false otherwise
|
||
|
**/
|
||
|
equals: function (anotherGlue) {
|
||
|
if (!anotherGlue instanceof Glue) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return this.id1 == anotherGlue.id1
|
||
|
&& this.id2 == anotherGlue.id2
|
||
|
&& this.automatic == anotherGlue.automatic
|
||
|
&& this.type1 == anotherGlue.type1
|
||
|
&& this.type2 == anotherGlue.type2;
|
||
|
},
|
||
|
|
||
|
/**String representation of the Glue
|
||
|
*@return {String} - the representation
|
||
|
**/
|
||
|
toString: function () {
|
||
|
return 'Glue : (id1 = ' + this.id1
|
||
|
+ ', id2 = ' + this.id2
|
||
|
+ ', type1 = ' + this.type1
|
||
|
+ ', type2 = ' + this.type2
|
||
|
+ ', automatic = ' + this.automatic
|
||
|
+ ')';
|
||
|
}
|
||
|
}
|