1 /* 2 * Copyright 2010 Scriptoid s.r.l 3 */ 4 5 6 /** 7 *It's a connector between 2 figureConnectionPoints. 8 * 9 *@constructor 10 *@this {Connector} 11 *@param {Point} startPoint - the start of the line, where a ConnectionPoint will be added 12 *@param {Point} endPoint - the end of the line, where a ConnectionPoint will be added 13 *@param {String} type - the type of the Connector. It can be 'straight' or 'jagged' 14 *@param {Number} id - the unique (at least among other Connectors) id this connnector will have 15 *@author Zack Newsham <zack_newsham@yahoo.co.uk> 16 *@author Alex Gheorghiu <alex@scriptoid.com> 17 */ 18 function Connector(startPoint,endPoint,type, id){ 19 /**Connector's id*/ 20 this.id = id 21 22 /**An {Array} of {Point}s. They will be used to draw the connector*/ 23 this.turningPoints = [startPoint,endPoint]; 24 25 /**Type of connector. Ex. TYPE_STRAIGHT*/ 26 this.type = type; 27 28 /**The {Style} this connector will have*/ 29 this.style = new Style(); 30 this.style.strokeStyle = "#000000"; 31 32 /**The text that will appear in the middle of the connector*/ 33 this.middleText = new Text("", (startPoint.x + endPoint.x)/2+10, (startPoint.y + endPoint.y) / 2 - 13, 'Arial',10); 34 this.middleText.style.strokeStyle = "#000000"; 35 this.middleText.bgStyle = "#ffffff"; 36 37 /**An {Array} of {BuilderProperties} to store exposed properties of the connector*/ 38 this.properties = []; 39 this.properties.push(new BuilderProperty("Start Style", "startStyle", BuilderProperty.TYPE_CONNECTOR_END)); 40 this.properties.push(new BuilderProperty("End Style", "endStyle", BuilderProperty.TYPE_CONNECTOR_END)); 41 this.properties.push(new BuilderProperty('Line Width','style.lineWidth', BuilderProperty.TYPE_LINE_WIDTH)); 42 this.properties.push(new BuilderProperty('Color','style.strokeStyle', BuilderProperty.TYPE_COLOR)); 43 this.properties.push(new BuilderProperty('Text','middleText.str', BuilderProperty.TYPE_TEXT)); 44 45 /**Start style for connector. Ex: Connector.STYLE_NORMAL*/ 46 this.startStyle = Connector.STYLE_NORMAL; 47 48 /**End style for connector. Ex: Connector.STYLE_NORMAL*/ 49 this.endStyle = Connector.STYLE_NORMAL; 50 51 /**The {ConnectionPoint}'s id that is currently being dragged*/ 52 this.activeConnectionPointId = -1; 53 54 /**If true visual debug will be available*/ 55 this.visualDebug = false; 56 57 /**Serialization type*/ 58 this.oType = 'Connector'; //object type used for JSON deserialization 59 } 60 61 /**Straight connector type*/ 62 Connector.TYPE_STRAIGHT = 'straight'; 63 64 /**Jagged connector type*/ 65 Connector.TYPE_JAGGED = 'jagged'; 66 67 /**Normal end connector style*/ 68 Connector.STYLE_NORMAL = "Normal"; 69 70 /**Arrow like end connector style*/ 71 Connector.STYLE_ARROW = "Arrow" 72 73 /**Empty triangle end connector style*/ 74 Connector.STYLE_EMPTY_TRIANGLE = "Empty" 75 76 /**Filled triangle end connector style*/ 77 Connector.STYLE_FILLED_TRIANGLE = "Filled" 78 79 /**End connector arrow size*/ 80 Connector.ARROW_SIZE = 15; 81 82 /**End connector arrow angle*/ 83 Connector.ARROW_ANGLE = 30; 84 85 86 87 /**Creates a {Connector} out of JSON parsed object 88 *@param {JSONObject} o - the JSON parsed object 89 *@return {Connector} a newly constructed Connector 90 *@author Alex Gheorghiu <alex@scriptoid.com> 91 **/ 92 Connector.load = function(o){ 93 var newConnector = new Connector(new Point(0,0), new Point(0,0), Connector.TYPE_STRAIGHT, 0); //fake constructor 94 95 newConnector.id = o.id; 96 newConnector.turningPoints = Point.loadArray(o.turningPoints); 97 newConnector.type = o.type; 98 newConnector.style = Style.load(o.style); 99 100 newConnector.middleText = Text.load(o.middleText); 101 102 newConnector.properties = BuilderProperty.loadArray(o.properties); 103 104 newConnector.endStyle = o.endStyle; 105 newConnector.startStyle = o.startStyle; 106 107 newConnector.activeConnectionPointId = o.activeConnectionPointId; 108 109 return newConnector; 110 } 111 112 /**Creates a an {Array} of {Connector} out of JSON parsed array 113 *@param {JSONObject} v - the JSON parsed {Array} 114 *@return {Array} of newly loaded {Connector}s 115 *@author Alex Gheorghiu <alex@scriptoid.com> 116 **/ 117 Connector.loadArray = function(v){ 118 var newConnectors = []; 119 120 for(var i=0; i<v.length; i++){ 121 newConnectors.push(Connector.load(v[i])); 122 } 123 124 return newConnectors; 125 } 126 127 Connector.prototype = { 128 129 /** 130 *Compares to another Connector 131 * 132 *@param {Connector} anotherConnector - the other connector 133 **/ 134 equals:function(anotherConnector){ 135 if(!anotherConnector instanceof Connector){ 136 return false; 137 } 138 139 //test turning points 140 for(var i=0; i<this.turningPoints.length; i++){ 141 if( !this.turningPoints[i].equals(anotherConnector.turningPoints[i]) ){ 142 return false; 143 } 144 } 145 146 //test properties 147 for(var i=0; i<this.properties.length; i++){ 148 if(!this.properties[i].equals(anotherConnector.properties[i])){ 149 return false; 150 } 151 } 152 153 if(this.id != anotherConnector.id 154 || this.type != anotherConnector.type 155 || !this.middleText.equals(anotherConnector.middleText) 156 || this.startStyle != anotherConnector.startStyle 157 || this.endStyle != anotherConnector.endStyle 158 || this.activeConnectionPointId != anotherConnector.activeConnectionPointId ){ 159 return false; 160 } 161 162 return true; 163 }, 164 165 /** 166 *Creates an arrow like figure, pointed down \/, at a certain position 167 * @param {Number} x - the X coordinates of the point 168 * @param {Number} y - the X coordinates of the point 169 * @return {Path} the arrow as a {Path} object 170 * @author Zack 171 **/ 172 getArrow:function(x,y){ 173 var startPoint = new Point(x,y); 174 var line = new Line(startPoint.clone(),Util.getEndPoint(startPoint,Connector.ARROW_SIZE, Math.PI/180*Connector.ARROW_ANGLE)); 175 var line1 = new Line(startPoint.clone(),Util.getEndPoint(startPoint,Connector.ARROW_SIZE, Math.PI/180*-Connector.ARROW_ANGLE)); 176 177 var path = new Path(); 178 179 path.style = this.style; 180 line.style = this.style; 181 line1.style = this.style; 182 183 path.addPrimitive(line); 184 path.addPrimitive(line1); 185 186 return path; 187 }, 188 189 /**Creates a triangle like figure, pointed down \/, at a certain position 190 * @param {Number} x - the X coordinates of the point 191 * @param {Number} y - the X coordinates of the point 192 * @param {Boolean} fill - if true fill the triangle 193 * @return {Path} the arrow as a {Path} object 194 * @author Zack, Alex 195 * */ 196 getTriangle:function(x,y,fill){ 197 198 var startPoint = new Point(x,y); 199 var point2 = Util.getEndPoint(startPoint,Connector.ARROW_SIZE, Math.PI/180*Connector.ARROW_ANGLE); 200 var point3 = Util.getEndPoint(startPoint, Connector.ARROW_SIZE, - Math.PI/180*Connector.ARROW_ANGLE); 201 202 var tri = new Polygon(); 203 tri.addPoint(startPoint); 204 tri.addPoint(point2); 205 tri.addPoint(point3); 206 207 tri.style = this.style.clone(); 208 if(fill){ 209 tri.style.fillStyle = this.style.strokeStyle; 210 } 211 else{ 212 tri.style.fillStyle = '#FFFFFF'; 213 } 214 215 return tri; 216 }, 217 218 219 /**Paints the connector 220 *@param {Context} context - the 2D context of the canvas 221 *@author Alex, Zack 222 **/ 223 paint:function(context){ 224 this.style.setupContext(context); 225 226 context.beginPath(); 227 228 //paint connector's line 229 var newStartX = 0; 230 var newStartY = 0; 231 context.moveTo(this.turningPoints[0].x, this.turningPoints[0].y); 232 for(var i=1; i< this.turningPoints.length; i++){ 233 if(this.startStyle == Connector.STYLE_EMPTY_TRIANGLE && i == 1){ //special case 234 //get the angle of the start line 235 var angle = Util.getAngle(this.turningPoints[0],this.turningPoints[1]); 236 //by alex: var newPoint = Util.getEndPoint(this.turningPoints[0], Connector.ARROW_SIZE * Math.sin(Math.PI/180 * Connector.ARROW_ANGLE * 2), angle); 237 var newPoint = Util.getEndPoint(this.turningPoints[0], Connector.ARROW_SIZE * Math.cos(Math.PI/180 * Connector.ARROW_ANGLE), angle); 238 //move to new start 239 context.moveTo(newPoint.x, newPoint.y); 240 } 241 if(this.endStyle == Connector.STYLE_EMPTY_TRIANGLE && i == this.turningPoints.length -1){ //special case 242 //get the angle of the final line 243 var angle = Util.getAngle(this.turningPoints[i-1],this.turningPoints[i]); 244 //by alex: var newPoint = Util.getEndPoint(this.turningPoints[i], -Connector.ARROW_SIZE*Math.sin(Math.PI/180*Connector.ARROW_ANGLE*2), angle) 245 var newPoint = Util.getEndPoint(this.turningPoints[i], -Connector.ARROW_SIZE * Math.cos(Math.PI/180 * Connector.ARROW_ANGLE), angle) 246 //line to new end 247 context.lineTo(newPoint.x, newPoint.y); 248 } 249 else{ 250 context.lineTo(this.turningPoints[i].x, this.turningPoints[i].y); 251 } 252 } 253 context.stroke(); 254 255 //paid debug points 256 if(this.visualDebug){ 257 context.beginPath(); 258 for(var i=0; i< this.turningPoints.length; i++){ 259 context.moveTo(this.turningPoints[i].x, this.turningPoints[i].y); 260 context.arc(this.turningPoints[i].x, this.turningPoints[i].y, 3, 0, Math.PI*2, false); 261 262 //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); 263 } 264 context.stroke(); 265 } 266 267 268 //paint start style 269 var path = null; 270 if(this.startStyle == Connector.STYLE_ARROW){ 271 path = this.getArrow(this.turningPoints[0].x, this.turningPoints[0].y); 272 } 273 if(this.startStyle == Connector.STYLE_EMPTY_TRIANGLE){ 274 path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, false); 275 } 276 if(this.startStyle == Connector.STYLE_FILLED_TRIANGLE){ 277 path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, true); 278 } 279 280 281 //move start path(arrow, triangle, etc) into position 282 if(path){ 283 var transX = this.turningPoints[0].x; 284 var transY = this.turningPoints[0].y; 285 286 var lineAngle = Util.getAngle(this.turningPoints[0], this.turningPoints[1], 0); 287 path.transform(Matrix.translationMatrix(-transX, -transY)); 288 path.transform(Matrix.rotationMatrix(lineAngle)); 289 path.transform(Matrix.translationMatrix(transX,transY)); 290 291 context.save(); 292 293 //context.lineJoin = "miter"; 294 context.lineJoin = "round"; 295 context.lineCap = "round"; 296 path.paint(context); 297 298 context.restore(); 299 } 300 301 path = null; 302 303 //paint end style 304 var path = null; 305 if(this.endStyle == Connector.STYLE_ARROW){ 306 path = this.getArrow(this.turningPoints[this.turningPoints.length-1].x, this.turningPoints[this.turningPoints.length-1].y); 307 } 308 if(this.endStyle == Connector.STYLE_EMPTY_TRIANGLE){ 309 path = this.getTriangle(this.turningPoints[this.turningPoints.length-1].x, this.turningPoints[this.turningPoints.length-1].y, false); 310 } 311 if(this.endStyle == Connector.STYLE_FILLED_TRIANGLE){ 312 path = this.getTriangle(this.turningPoints[this.turningPoints.length-1].x, this.turningPoints[this.turningPoints.length-1].y, true); 313 } 314 315 //move end path (arrow, triangle, etc) into position 316 if(path){ 317 var transX = this.turningPoints[this.turningPoints.length-1].x; 318 var transY = this.turningPoints[this.turningPoints.length-1].y; 319 var lineAngle = Util.getAngle(this.turningPoints[this.turningPoints.length-1], this.turningPoints[this.turningPoints.length-2], 0); 320 321 path.transform(Matrix.translationMatrix(-transX, -transY)); 322 path.transform(Matrix.rotationMatrix(lineAngle)); 323 path.transform(Matrix.translationMatrix(transX, transY)); 324 325 context.save(); 326 327 context.lineJoin = "round"; 328 context.lineCap = "round"; 329 330 path.paint(context); 331 332 context.restore(); 333 } 334 335 336 if(this.middleText.str != ''){ 337 338 //TODO: not so smart to paint the background of the text 339 var oldFill = context.fillStyle; 340 341 context.beginPath(); 342 var textBounds = this.middleText.getBounds(); 343 context.moveTo(textBounds[0],textBounds[1]); 344 context.lineTo(textBounds[0],textBounds[3]); 345 context.lineTo(textBounds[2],textBounds[3]); 346 context.lineTo(textBounds[2],textBounds[1]); 347 context.fillStyle = "white"; 348 context.closePath(); 349 context.fill(); 350 351 context.fillStyle = oldFill; 352 this.middleText.paint(context); 353 } 354 355 }, 356 357 358 359 360 /** 361 *Apply a transformation to this Connector 362 *@param {Matrix} matrix - a matrix of numbers 363 **/ 364 transform:function(matrix){ 365 366 //are we moving the whole Connector, or just one point? 367 if(this.activeConnectionPointId != -1){ 368 var point = CONNETOR_MANAGER.connectionPointGet(this.activeConnectionPointId); 369 point.transform(matrix); 370 } 371 else{ 372 for(var i=0; i<this.turningPoints.length; i++){ 373 this.turningPoints[i].transform(matrix); 374 } 375 //this.startText.transform(matrix); 376 //this.endText.transform(matrix); 377 } 378 379 }, 380 381 /** 382 *Creates as jagged(zig-zag) line between 2 ConnectionPoints 383 *@author Zack Newsham <zack_newsham@yahoo.co.uk> 384 *@deprecated 385 **/ 386 jagged:function(){ 387 this.jaggedReloaded(); 388 return; 389 390 391 //reference to the start and end 392 var endPoint=this.turningPoints.pop(); 393 var startPoint=this.turningPoints[0]; 394 395 //the figure at the start 396 var startConnectionPoint = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0]; 397 var glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(startConnectionPoint.id)[0];//there will only be one for this 398 399 var startConnectionFigureId = CONNECTOR_MANAGER.connectionPointGet(glue.id1 == startConnectionPoint.id ? glue.id2 : glue.id1).parentId; 400 var startConnectionFigure = stack.figureGetById(startConnectionFigureId); 401 402 var startCenterPoint 403 if(startConnectionFigure){ 404 startCenterPoint = startConnectionFigure.rotationCoords[0]; 405 } 406 else{ 407 startCenterPoint = startPoint; 408 } 409 410 //the figure at the end 411 var endCon = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1]; 412 glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(endCon.id)[0];//there will only be one for this 413 var endConnectionFigure=CONNECTOR_MANAGER.connectionPointGet(glue.id1==endCon.id ? glue.id2 : glue.id1).parentId; 414 endConnectionFigure=stack.figureGetById(endConnectionFigure); 415 var endCenterPoint 416 if(endConnectionFigure){ 417 endCenterPoint = endConnectionFigure.rotationCoords[0]; 418 } 419 else { 420 endCenterPoint = endPoint; 421 } 422 423 //regardless of whih figure was clicked first, the left figure is start. 424 var swapped = false; 425 if(endCenterPoint.x<startCenterPoint.x){ 426 var t = endCenterPoint; 427 endCenterPoint = startCenterPoint; 428 startCenterPoint = t; 429 430 t = endConnectionFigure; 431 endConnectionFigure = startConnectionFigure; 432 startConnectionFigure = t; 433 434 t = endPoint; 435 endPoint = startPoint; 436 startPoint = t; 437 swapped = true; 438 } 439 440 441 //we use this later 442 var endPoints = [endPoint]; 443 444 //clear the array of all intermediate turningPoints, we use this when we have a connector that is moved from one connectionPoint to another 445 this.turningPoints=[startPoint]; 446 447 //start+end+4 turning points 448 var nextPoint; 449 var startAngle=Util.getAngle(startCenterPoint,startPoint,Math.PI/2); 450 var endAngle=Util.getAngle(endCenterPoint,endPoint,Math.PI/2); 451 452 //move away from figure in angle(90) direction 453 454 //END FIGURE ESCAPE 455 if(endAngle==0){ 456 nextPoint=new Point(endPoint.x,endConnectionFigure.getBounds()[1]-20); 457 } 458 else if(endAngle==Math.PI/2){ 459 nextPoint=new Point(endConnectionFigure.getBounds()[2]+20,endPoint.y); 460 } 461 else if(endAngle==Math.PI){ 462 nextPoint=new Point(endPoint.x,endConnectionFigure.getBounds()[3]+20); 463 } 464 else{ 465 nextPoint=new Point(endConnectionFigure.getBounds()[0]-20,endPoint.y); 466 } 467 endPoints.push(nextPoint); 468 endPoint = nextPoint; 469 470 var previousPoint = startPoint; 471 472 //START FIGURE ESCAPE 473 //clear bounds 474 //clear bounds by 20px in direction of angle 475 if(startAngle==0){ 476 nextPoint=new Point(startPoint.x,startConnectionFigure.getBounds()[1]-20); 477 } 478 else if(startAngle==Math.PI/2){ 479 nextPoint=new Point(startConnectionFigure.getBounds()[2]+20,startPoint.y); 480 } 481 else if(startAngle==Math.PI){ 482 nextPoint=new Point(startPoint.x,startConnectionFigure.getBounds()[3]+20); 483 } 484 else{ 485 nextPoint=new Point(startConnectionFigure.getBounds()[0]-20,startPoint.y); 486 } 487 this.turningPoints.push(nextPoint); 488 489 startPoint = nextPoint; 490 491 var currentPoint = startPoint; 492 nextPoint = null; 493 var angles = [0, Math.PI/2, Math.PI, Math.PI/2*3, Math.PI*2]; 494 var startCounter = 0; //keeps track of new turning points added 495 var intEnd = Util.lineIntersectsRectangle(startPoint, endPoint, endConnectionFigure.getBounds()); 496 var intStart = Util.lineIntersectsRectangle(startPoint, endPoint, startConnectionFigure.getBounds()); 497 while(intEnd || intStart){//while we have an intersection, keep trying 498 499 //get the angle of the last turn made, we know we need to do something 90degrees off this 500 startAngle = Util.getAngle(startPoint,this.turningPoints[this.turningPoints.length-2],Math.PI/2); 501 endAngle = Util.getAngle(endPoint,endPoints[endPoints.length-2],Math.PI/2); 502 switch (startCounter){ 503 case 0: 504 if(startAngle==0 || startAngle==Math.PI){ //we were going N/S, now we want to go E/W 505 if(startPoint.x < endPoint.x){ 506 startPoint = new Point(startConnectionFigure.getBounds()[2]+20, startPoint.y); 507 } 508 else{ 509 startPoint = new Point(startConnectionFigure.getBounds()[0]-20, startPoint.y); 510 } 511 } 512 else{//going E/W now want N/S 513 if(startPoint.y<endPoint.y || endPoint.y>startConnectionFigure.getBounds()[1]){ 514 startPoint = new Point(startPoint.x,startConnectionFigure.getBounds()[3]+20); 515 } 516 else{ 517 startPoint = new Point(startPoint.x,startConnectionFigure.getBounds()[1]-20); 518 } 519 } 520 this.turningPoints.push(startPoint); 521 break; 522 case 1://we have already done something to the startPoint, changing the end point should resolve the issue 523 endPoints.push(endPoint); 524 if(endAngle==0 || endAngle==Math.PI){ //we were going N/S, now we want to go E/W 525 if(startPoint.x > endPoint.x){ 526 endPoint = new Point(endConnectionFigure.getBounds()[2]+20,endPoint.y); 527 } 528 else{ 529 endPoint = new Point(endConnectionFigure.getBounds()[0]-20,endPoint.y); 530 } 531 } 532 else{//going E/W now want N/S 533 if(startPoint.y > endPoint.y){ 534 endPoint = new Point(endPoint.x,endConnectionFigure.getBounds()[3]+20); 535 } 536 else{ 537 endPoint = new Point(endPoint.x,endConnectionFigure.getBounds()[1]-20); 538 } 539 } 540 break; 541 } 542 543 startCounter++; 544 intEnd=Util.lineIntersectsRectangle(startPoint, endPoint, endConnectionFigure.getBounds()); 545 intStart=Util.lineIntersectsRectangle(startPoint, endPoint, startConnectionFigure.getBounds()); 546 if(startCounter==3){//we have done all we can, if we still can't make a good jagged, make a bad one 547 break; 548 } 549 } 550 551 //there are no intersections of the straight line between start and end 552 //now lets see if making a jagged line will create one 553 //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 554 if(!Util.lineIntersectsRectangle(new Point(startPoint.x,endPoint.y), new Point(endPoint.x,endPoint.y), endConnectionFigure.getBounds()) 555 && !Util.lineIntersectsRectangle(new Point(startPoint.x,endPoint.y), new Point(endPoint.x,endPoint.y), startConnectionFigure.getBounds()) 556 && !Util.lineIntersectsRectangle(new Point(startPoint.x,startPoint.y), new Point(startPoint.x,endPoint.y), endConnectionFigure.getBounds()) 557 && !Util.lineIntersectsRectangle(new Point(startPoint.x,startPoint.y), new Point(startPoint.x,endPoint.y), startConnectionFigure.getBounds())) 558 { 559 this.turningPoints.push(new Point(startPoint.x,endPoint.y)); 560 } 561 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())){ 562 this.turningPoints.push(new Point(endPoint.x,startPoint.y)); 563 } 564 /*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 565 var yMove=(startPoint.y>endPoint.y?endConnectionFigure.getBounds()[3]+20:endConnectionFigure.getBounds()[3]-20); 566 this.turningPoints.push(new Point(startPoint.x,yMove)); 567 this.turningPoints.push(new Point(endPoint.x,yMove)); 568 }*/ 569 570 //add the endPoints we have changed to the line 571 this.turningPoints.push(new Point(endPoint.x,endPoint.y)); 572 for(var i=0; i<endPoints.length; i++){ 573 this.turningPoints.push(endPoints.pop()); 574 i--; //lower the counter or we will only get half the points 575 } 576 577 //if our line was supposed to go backwards, lets reverse it 578 if(swapped){ 579 this.turningPoints = this.turningPoints.reverse(); 580 } 581 }, 582 583 584 /**A rework of jagged method 585 *Just creates all turning points for Connector that has a StartPoint and an EndPoint 586 *@author Alex Gheorghiu <alex@scriptoid.com> 587 **/ 588 jaggedReloaded:function(){ 589 590 //reference to the start and end 591 var startPoint = this.turningPoints[0]; 592 var startExitPoint = null; //next turning point after the startPoint (if start figure present) 593 var endExitPoint = null; //the last turning point before endPoint (if end figure present) 594 var endPoint = this.turningPoints[this.turningPoints.length-1]; 595 596 597 598 //START FIGURE 599 var startConnectionPointOnConnector = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0]; //fist ConnectionPoint on the Connector 600 var glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(startConnectionPointOnConnector.id)[0];//the (only) Glue tied to ConnectionPoint 601 602 if(glue != null){ //only if there is a Figure glued 603 //get ConnectionPoint on Figure 604 var startFigureConnectionPoint = CONNECTOR_MANAGER.connectionPointGet(glue.id1 == startConnectionPointOnConnector.id ? glue.id2 : glue.id1); 605 var startFigure = stack.figureGetById(startFigureConnectionPoint.parentId); 606 607 var startAngle = Util.getAngle(startFigure.rotationCoords[0], startPoint, Math.PI/2); 608 switch(startAngle){ 609 case 0: //north exit 610 startExitPoint = new Point(startPoint.x, startFigure.getBounds()[1]-20); 611 break; 612 case Math.PI/2: //east exit 613 startExitPoint = new Point(startFigure.getBounds()[2]+20, startPoint.y); 614 break; 615 case Math.PI: //south exit 616 startExitPoint = new Point(startPoint.x, startFigure.getBounds()[3]+20); 617 break; 618 case 3 * Math.PI/2: //west exit 619 startExitPoint = new Point(startFigure.getBounds()[0]-20, startPoint.y); 620 break; 621 } 622 } 623 624 625 //END FIGURE 626 var endConnectionPointOnConnector = CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1]; //last ConnectionPoint on Connector 627 glue = CONNECTOR_MANAGER.glueGetByConnectionPointId(endConnectionPointOnConnector.id)[0];//there will only be one for this 628 629 if(glue != null){ //only if there is a Figure glued 630 //get ConnectionPoint on Figure 631 var endFigureConnectionPoint = CONNECTOR_MANAGER.connectionPointGet(glue.id1 == endConnectionPointOnConnector.id ? glue.id2 : glue.id1); 632 var endFigure = stack.figureGetById(endFigureConnectionPoint.parentId); 633 634 var endAngle = Util.getAngle(endFigure.rotationCoords[0], endPoint, Math.PI/2); 635 switch(startAngle){ 636 case 0: //north exit 637 endExitPoint = new Point(endPoint.x, endFigure.getBounds()[1]-20); 638 break; 639 case Math.PI/2: //east exit 640 endExitPoint = new Point(endFigure.getBounds()[2]+20, endPoint.y); 641 break; 642 case Math.PI: //south exit 643 endExitPoint = new Point(endPoint.x, endFigure.getBounds()[3]+20); 644 break; 645 case 3 * Math.PI/2: //west exit 646 endExitPoint = new Point(endFigure.getBounds()[0]-20, endPoint.y); 647 break; 648 } 649 } 650 651 alert('jaggedReloaded:Connector has ' + this.turningPoints.length + " points"); 652 this.turningPoints.splice(1,0, startExitPoint, endExitPoint); 653 alert('jaggedReloaded:Connector has ' + this.turningPoints.length + " points"); 654 }, 655 656 /**This function simply tries to create all possible intermediate points that can be placed 657 *between 2 points to create a jagged connector 658 *@param {Point} p1 - a point 659 *@param {Point} p2 - the other point*/ 660 connect2Points:function(p1, p2){ 661 var solutions = []; 662 663 //1. is p1 == p2? 664 if(p1.equals(p2)){ 665 666 } 667 668 //2. is p1 on a vertical or horizontal line with p2? S0 669 //3. can we have a single intermediate point? S1 670 //4. can we have 2 intermediate points? S2 671 return solutions; 672 }, 673 674 /** 675 *Remove redundant points (we have just ajusted one of the handles of this figure, so) 676 **/ 677 redraw:function(){ 678 if(this.type=='jagged'){ 679 var changed=true; 680 while(changed==true){ 681 changed=false; 682 for(var i=1; i<this.turningPoints.length-2; i++){ 683 if(this.turningPoints[i].x == this.turningPoints[i-1].x && this.turningPoints[i-1].x == this.turningPoints[i+1].x){ 684 this.turningPoints.splice(i,1); 685 changed=true; 686 } 687 if(this.turningPoints[i].y == this.turningPoints[i-1].y && this.turningPoints[i-1].y == this.turningPoints[i+1].y){ 688 this.turningPoints.splice(i,1); 689 changed=true; 690 } 691 } 692 } 693 694 } 695 }, 696 697 /** 698 * Transform a ConnectionPoint by a matrix. Usually called only by ConnectionManager.connectionPointTransform(), 699 * when a figure is being moved, so it's more or less start point or end point of a connector. 700 * Important to remember is that by moving and edge turning point all ther might be cases when more than one 701 * points need to change 702 * Once a figure is changed its ConnectionPoints got tranformed...so the glued Connector must 703 * change...it's like a cascade change 704 * @param {Matrix} matrix - the transformation to be used 705 * @param {Point} point - the point to start from (could be end or start). It is the point that 706 * triggered the adjustement 707 */ 708 adjust:function(matrix, point){ 709 710 //Log.info('Adjusting...'); 711 if(this.type == Connector.TYPE_STRAIGHT){ 712 //Log.info("straight "); 713 714 var tempConPoint = CONNECTOR_MANAGER.connectionPointGetByParentAndCoordinates(this.id, point.x, point.y); 715 716 //find index of the turning point 717 var index = -1; 718 if(this.turningPoints[0].equals(point)){ 719 index = 0; 720 } 721 else if(this.turningPoints[1].equals(point)){ 722 index = 1; 723 } 724 else{ 725 Log.error("Connector:adjust() - This should not happend" + this.toString() + ' point is ' + point); 726 } 727 728 729 //Log.info('\tinitial' + tempConPoint.toString()); 730 tempConPoint.transform(matrix); 731 //Log.info('\tafter' + tempConPoint.toString()); 732 733 734 this.turningPoints[index].x = tempConPoint.point.x; 735 this.turningPoints[index].y = tempConPoint.point.y; 736 737 /*TODO: it seems that the code bellow is not working fine...clone is wrong? 738 this.turningPoints[index] = new Point(tempConPoint.point.x,tempConPoint.point.y); 739 */ 740 741 } 742 743 if(this.type == Connector.TYPE_JAGGED){ 744 //Log.info("jagged "); 745 var oldX = point.x; 746 var oldY = point.y; 747 748 var tempConPoint = CONNECTOR_MANAGER.connectionPointGetByParentAndCoordinates(this.id, point.x, point.y); 749 tempConPoint.transform(matrix); 750 751 //are we starting from beginning or end, so we will detect the interval and direction 752 var start,end,direction; 753 if(point.equals(this.turningPoints[0])){//if the point is the starting Point 754 //Log.info("It is the starting point"); 755 756 //adjust first turning point 757 this.turningPoints[0].x = tempConPoint.point.x; 758 this.turningPoints[0].y = tempConPoint.point.y; 759 760 start = 1; 761 end = this.turningPoints.length; 762 direction = 1; 763 } 764 else if(point.equals(this.turningPoints[this.turningPoints.length -1])){ //if the point is the ending Point 765 //Log.info("It is the ending point"); 766 767 //adjust last turning point 768 this.turningPoints[this.turningPoints.length -1].x = tempConPoint.point.x; 769 this.turningPoints[this.turningPoints.length -1].y = tempConPoint.point.y; 770 771 start = this.turningPoints.length - 2; 772 end = -1; 773 direction = -1; 774 } 775 else{ 776 Log.error("Connector:adjust() - this should never happen for point " + point + ' and connector ' + this.toString()); 777 } 778 779 //TODO: the only affected turning point should be ONLY the next one (if start point) or previous one (if end point) 780 for(var i=start; i!=end; i+=direction){ 781 //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 782 //dont do this if they are our start/end point 783 //we don't want to use them if they are on he exact spot 784 if(this.turningPoints[i].y != oldY 785 && this.turningPoints[i].x == oldX //same x 786 && this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0].point 787 && this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1].point ) 788 { 789 oldX = this.turningPoints[i].x; 790 oldY = this.turningPoints[i].y; 791 this.turningPoints[i].x = this.turningPoints[i-direction].x; 792 } 793 else if(this.turningPoints[i].x != oldX 794 && this.turningPoints[i].y == oldY 795 && this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[0].point 796 && this.turningPoints[i] != CONNECTOR_MANAGER.connectionPointGetAllByParent(this.id)[1].point ) 797 { 798 oldX = this.turningPoints[i].x; 799 oldY = this.turningPoints[i].y; 800 this.turningPoints[i].y = this.turningPoints[i-direction].y; 801 } 802 } 803 } 804 }, 805 806 807 /** 808 * This is really a near type function, we don't want to find out 809 * if we are anywhere within the "bounds" of the Connector 810 * @param {Number} x - coordinate 811 * @param {Number} y - coordinate 812 */ 813 contains:function(x,y){ 814 for(var i=0; i<this.turningPoints.length-1; i++){ 815 var l = new Line(this.turningPoints[i],this.turningPoints[i+1]); 816 if (l.near(x,y,3)){ 817 return true; 818 } 819 } 820 return this.turningPoints[this.turningPoints.length-1].near(x,y,3) || this.turningPoints[0].near(x,y,3); 821 }, 822 823 /**Tests if a point defined by (x,y) is within a radius 824 *@param {Number} x - x coordinates of the point 825 *@param {Number} y - y coordinates of the point 826 *@param {Number} radius - the radius to seach within 827 **/ 828 near:function(x,y,radius){ 829 for(var i=0; i<this.turningPoints.length-1; i++){ 830 var l=new Line(this.turningPoints[i],this.turningPoints[i+1]); 831 if (l.near(x,y,radius)){ 832 return true; 833 } 834 } 835 return this.turningPoints[this.turningPoints.length-1].near(x,y,3) || this.turningPoints[0].near(x,y,3); 836 }, 837 838 /**Returns the middle of a connector 839 *Usefull for setting up the middle text 840 *@return {Array} of 2 {Number}s - the x and y of the point 841 *@author Alex Gheorghiu <alex@scriptoid.com> 842 **/ 843 middle:function(){ 844 if(this.type == Connector.TYPE_STRAIGHT){ 845 var middleX = (this.turningPoints[0].x + this.turningPoints[1].x)/2; 846 var middleY = (this.turningPoints[0].y + this.turningPoints[1].y) /2; 847 return [middleX, middleY]; 848 } 849 else if(this.type == Connector.TYPE_JAGGED){ 850 /** Algorithm: 851 * Find the lenght of the connector. Then go on each segment until we will reach half of the 852 * connector's lenght. 853 **/ 854 855 //find total distance 856 var distance = 0; 857 for(var i=0; i<this.turningPoints.length-1; i++){ 858 distance += Util.getLength(this.turningPoints[i], this.turningPoints[i+1]); 859 } 860 861 //find between what turning points the half distance is 862 var index = -1; 863 var ellapsedDistance = 0; 864 for(var i=0; i<this.turningPoints.length-1; i++){ 865 index = i; 866 var segment = Util.getLength(this.turningPoints[i], this.turningPoints[i+1]); 867 if(ellapsedDistance + segment < distance /2){ 868 ellapsedDistance += segment; 869 } 870 else{ 871 break; 872 } 873 } 874 875 //we have the middle distance somewhere between i(ndex) and i(ndex)+1 876 if(index != -1){ 877 var missingDistance = distance / 2 - ellapsedDistance; 878 if( Util.round(this.turningPoints[index].x, 3) == Util.round(this.turningPoints[index + 1].x, 3) ){ //vertical segment (same x) 879 return [this.turningPoints[index].x, Math.min(this.turningPoints[index].y, this.turningPoints[index + 1].y) + missingDistance]; 880 } else if( Util.round(this.turningPoints[index].y, 3) == Util.round(this.turningPoints[index + 1].y, 3) ) { //horizontal segment (same y) 881 return [Math.min(this.turningPoints[index].x, this.turningPoints[index + 1].x) + missingDistance, this.turningPoints[index].y]; 882 } else{ 883 Log.error("Connector:middle() - this should never happen " + this.turningPoints[index] + " " + this.turningPoints[index + 1] 884 + " nr of points " + this.turningPoints.length 885 ); 886 } 887 888 } 889 } 890 891 return null; 892 }, 893 894 895 /**Updates the middle text of the connector 896 *@author Alex Gheorghiu <alex@scriptoid.com> 897 **/ 898 updateMiddleText: function(){ 899 // Log.info("updateMiddleText called"); 900 var middlePoint = this.middle(); 901 902 if(middlePoint != null){ 903 this.middleText.transform(Matrix.translationMatrix(middlePoint[0] - this.middleText.vector[0].x, middlePoint[1] - this.middleText.vector[0].y)); 904 } 905 }, 906 907 /**Founds the bounds of the connector 908 *@return {Array} - the [minX, minY, maxX, maxY] 909 **/ 910 getBounds:function(){ 911 var minX=minY=maxX=maxY=null; 912 for(var i=0; i<this.turningPoints.length; i++){ 913 if(this.turningPoints[i].x<minX || minX==null) 914 minX = this.turningPoints[i].x; 915 if(this.turningPoints[i].x>maxX || maxX==null) 916 maxX = this.turningPoints[i].x; 917 if(this.turningPoints[i].y<minY || minY==null) 918 minY = this.turningPoints[i].y; 919 if(this.turningPoints[i].y>maxY || maxY==null) 920 maxY = this.turningPoints[i].y; 921 } 922 return [minX, minY, maxX, maxY]; 923 }, 924 925 926 /**String representation*/ 927 toString:function(){ 928 return "Connector id = " + this.id + ' ' + this.type + '[' +this.turningPoints+ ']' + ' active cp = ' + this.activeConnectionPointId+")"; 929 }, 930 931 932 /**SVG representation of the connector 933 *@return {String} - the SVG part 934 **/ 935 toSVG:function(){ 936 937 //1. paint line 938 var r = '<polyline points="'; 939 for(var i =0; i <this.turningPoints.length; i++){ 940 r += this.turningPoints[i].x + ',' + this.turningPoints[i].y + ' '; 941 } 942 r += '"'; 943 r += this.style.toSVG(); 944 // r += ' style="fill: #none; stroke:#ADADAD;" '; 945 r += '/>'; 946 947 //2. paint the start/end 948 //paint start style 949 var path = null; 950 if(this.startStyle == Connector.STYLE_ARROW){ 951 path = this.getArrow(this.turningPoints[0].x, this.turningPoints[0].y); 952 } 953 if(this.startStyle == Connector.STYLE_EMPTY_TRIANGLE){ 954 path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, false); 955 } 956 if(this.startStyle == Connector.STYLE_FILLED_TRIANGLE){ 957 path = this.getTriangle(this.turningPoints[0].x, this.turningPoints[0].y, true); 958 } 959 960 if(path){ 961 var transX = this.turningPoints[0].x; 962 var transY = this.turningPoints[0].y; 963 964 var lineAngle = Util.getAngle(this.turningPoints[0], this.turningPoints[1], 0); 965 path.transform(Matrix.translationMatrix(-transX, -transY)); 966 path.transform(Matrix.rotationMatrix(lineAngle)); 967 path.transform(Matrix.translationMatrix(transX,transY)); 968 969 r += path.toSVG(); 970 } 971 972 973 //paint end style 974 if(this.endStyle == Connector.STYLE_ARROW){ 975 path = this.getArrow(this.turningPoints[this.turningPoints.length-1].x, this.turningPoints[this.turningPoints.length-1].y); 976 } 977 if(this.endStyle == Connector.STYLE_EMPTY_TRIANGLE){ 978 path = this.getTriangle(this.turningPoints[this.turningPoints.length-1].x, this.turningPoints[this.turningPoints.length-1].y, false); 979 } 980 if(this.endStyle == Connector.STYLE_FILLED_TRIANGLE){ 981 path = this.getTriangle(this.turningPoints[this.turningPoints.length-1].x, this.turningPoints[this.turningPoints.length-1].y, true); 982 } 983 //move end path (arrow, triangle, etc) into position 984 if(path){ 985 var transX = this.turningPoints[this.turningPoints.length-1].x; 986 var transY = this.turningPoints[this.turningPoints.length-1].y; 987 var lineAngle = Util.getAngle(this.turningPoints[this.turningPoints.length-1], this.turningPoints[this.turningPoints.length-2], 0); 988 989 path.transform(Matrix.translationMatrix(-transX, -transY)); 990 path.transform(Matrix.rotationMatrix(lineAngle)); 991 path.transform(Matrix.translationMatrix(transX, transY)); 992 993 r += path.toSVG(); 994 } 995 996 997 998 //3. pain text (if any) 999 if(this.middleText.str.length != 1){ 1000 //paint white background 1001 var txtBounds = this.middleText.getBounds(); //this is actually an array of numbers [minX, minY, maxX, maxY] 1002 1003 var poly = new Polygon(); 1004 1005 poly.addPoint(new Point(txtBounds[0], txtBounds[1])); 1006 poly.addPoint(new Point(txtBounds[2], txtBounds[1])); 1007 poly.addPoint(new Point(txtBounds[2], txtBounds[3])); 1008 poly.addPoint(new Point(txtBounds[0], txtBounds[3])); 1009 poly.style.fillStyle = "#FFFFFF"; 1010 1011 r += poly.toSVG(); 1012 1013 1014 //paint actuall text 1015 r += this.middleText.toSVG(); 1016 } 1017 1018 return r; 1019 } 1020 } 1021 1022 /** 1023 *A connection point that is attached to a figure and can accept connectors 1024 * 1025 *@constructor 1026 *@this {ConnectionPoint} 1027 *@param {Number} parentId - the parent to which this ConnectionPoint is attached. It can be either a {Figure} or a {Connector} 1028 *@param {Point} point - coordinate of this connection point, better than using x and y, because when we move "snap to" this 1029 * connectionPoint the line will follow 1030 *@param {Number} id - unique id to the parent figure 1031 *@param {String} type - the type of the parent. It can be either 'figure' or 'connector' 1032 * 1033 *@author Zack Newsham <zack_newsham@yahoo.co.uk> 1034 *@author Alex Gheorghiu <alex@scriptoid.com> 1035 */ 1036 function ConnectionPoint(parentId,point,id, type){ 1037 /**Connection point id*/ 1038 this.id = id; 1039 1040 /**The {Point} that is behind this ConnectionPoint*/ 1041 this.point = point.clone(); //we will create a clone so that no side effect will appear 1042 1043 /**Parent id (id of the Figure or Connector)*/ 1044 this.parentId = parentId; 1045 1046 /**Type of ConnectionPoint. Ex: ConnectionPoint.TYPE_FIGURE*/ 1047 this.type = type; 1048 1049 /**Current connection point color*/ 1050 this.color = ConnectionPoint.NORMAL_COLOR; 1051 1052 /**Radius of the connection point*/ 1053 this.radius = 3; 1054 1055 /**Serialization type*/ 1056 this.oType = 'ConnectionPoint'; //object type used for JSON deserialization 1057 1058 } 1059 1060 /**Color used by default to draw the connection point*/ 1061 ConnectionPoint.NORMAL_COLOR = "#FFFF33"; //yellow. 1062 1063 /*Color used to signal that the 2 connection points are about to glue*/ 1064 ConnectionPoint.OVER_COLOR = "#FF9900"; //orange 1065 1066 /*Color used to draw connected (glued) connection points*/ 1067 ConnectionPoint.CONNECTED_COLOR = "#ff0000"; //red 1068 1069 /**Connection point default radius*/ 1070 ConnectionPoint.RADIUS = 4; 1071 1072 /**Connection point (liked to)/ type figure*/ 1073 ConnectionPoint.TYPE_FIGURE = 'figure'; 1074 1075 /**Connection point (liked to)/ type connector*/ 1076 ConnectionPoint.TYPE_CONNECTOR = 'connector'; 1077 1078 1079 /**Creates a {ConnectionPoint} out of JSON parsed object 1080 *@param {JSONObject} o - the JSON parsed object 1081 *@return {ConnectionPoint} a newly constructed ConnectionPoint 1082 *@author Alex Gheorghiu <alex@scriptoid.com> 1083 **/ 1084 ConnectionPoint.load = function(o){ 1085 var newConnectionPoint = new ConnectionPoint(0, new Point(0,0), ConnectionPoint.TYPE_FIGURE); //fake constructor 1086 1087 newConnectionPoint.id = o.id; 1088 newConnectionPoint.point = Point.load(o.point); 1089 newConnectionPoint.parentId = o.parentId; 1090 newConnectionPoint.type = o.type; 1091 1092 newConnectionPoint.color = o.color; 1093 newConnectionPoint.radius = o.radius; 1094 1095 return newConnectionPoint; 1096 } 1097 1098 /**Creates a an {Array} of {ConnectionPoint} out of JSON parsed array 1099 *@param {JSONObject} v - the JSON parsed {Array} 1100 *@return {Array} of newly loaded {ConnectionPoint}s 1101 *@author Alex Gheorghiu <alex@scriptoid.com> 1102 **/ 1103 ConnectionPoint.loadArray = function(v){ 1104 var newConnectionPoints = []; 1105 1106 for(var i=0; i<v.length; i++){ 1107 newConnectionPoints.push(ConnectionPoint.load(v[i])); 1108 } 1109 1110 return newConnectionPoints; 1111 } 1112 1113 ConnectionPoint.prototype = { 1114 1115 /**Compares to another ConnectionPoint 1116 *@param {ConnectionPoint} anotherConnectionPoint - the other connection point 1117 *@return {Boolean} - true if equals, false otherwise 1118 **/ 1119 equals:function(anotherConnectionPoint){ 1120 1121 return this.id == anotherConnectionPoint.id 1122 && this.point.equals(anotherConnectionPoint.point) 1123 && this.parentId == anotherConnectionPoint.parentId 1124 && this.type == anotherConnectionPoint.type 1125 && this.color == anotherConnectionPoint.color 1126 && this.radius == anotherConnectionPoint.radius; 1127 }, 1128 1129 /** 1130 *Paints the ConnectionPoint into a Context 1131 *@param {Context} context - the 2D context 1132 **/ 1133 paint:function(context){ 1134 context.save(); 1135 context.fillStyle = this.color; 1136 context.strokeStyle = '#000000'; 1137 context.beginPath(); 1138 context.arc(this.point.x, this.point.y, ConnectionPoint.RADIUS, 0, (Math.PI/180)*360, false); 1139 context.fill(); 1140 context.stroke(); 1141 context.restore(); 1142 }, 1143 1144 1145 /** 1146 *Transform the ConnectionPoint through a Matrix 1147 *@param {Matrix} matrix - the transformation matrix 1148 **/ 1149 transform:function(matrix){ 1150 this.point.transform(matrix); 1151 }, 1152 1153 1154 /**Highlight the connection point*/ 1155 highlight:function(){ 1156 this.color = ConnectionPoint.OVER_COLOR; 1157 }, 1158 1159 /**Un-highlight the connection point*/ 1160 unhighlight:function(){ 1161 this.color = ConnectionPoint.NORMAL_COLOR; 1162 }, 1163 1164 1165 /**Tests to see if a point (x, y) is within a range of current ConnectionPoint 1166 *@param {Numeric} x - the x coordinate of tested point 1167 *@param {Numeric} y - the x coordinate of tested point 1168 *@return {Boolean} - true if inside, false otherwise 1169 *@author Alex Gheorghiu <alex@scriptoid.com> 1170 **/ 1171 contains:function(x, y){ 1172 return this.near(x, y, ConnectionPoint.RADIUS); 1173 }, 1174 1175 /**Tests to see if a point (x, y) is within a specified range of current ConnectionPoint 1176 *@param {Numeric} x - the x coordinate of tested point 1177 *@param {Numeric} y - the x coordinate of tested point 1178 *@param {Numeric} radius - the radius around this point 1179 *@return {Boolean} - true if inside, false otherwise 1180 *@author Alex Gheorghiu <alex@scriptoid.com> 1181 **/ 1182 near:function(x, y, radius){ 1183 return new Point(this.point.x,this.point.y).near(x,y,radius); 1184 }, 1185 1186 1187 /**A String representation of the point*/ 1188 toString:function(){ 1189 return "ConnectionPoint id = " + this.id + ' point = ['+ this.point + '] ,type = ' + this.type + ", parentId = " + this.parentId + ")"; 1190 } 1191 } 1192 1193 1194 1195 /**A Glue just glues together 2 ConnectionPoints. 1196 *Glued ConnectionPoints usually belongs to a Connector and a Figure. 1197 * 1198 *@constructor 1199 *@this {Glue} 1200 *@param {Number} cp1 - the id of the first {ConnectionPoint} (usually from a {Figure}) 1201 *@param {Number} cp2 - the id of the second {ConnectionPoint} (usualy from a {Connector}) 1202 **/ 1203 function Glue(cp1,cp2){ 1204 /**First shape's id (usually from a {Figure})*/ 1205 this.id1 = cp1; 1206 1207 /**Second shape's id (usualy from a {Connector})*/ 1208 this.id2 = cp2; 1209 1210 /*By default all the Glues are created with the first number as Figure's id and second number as 1211 *Connector's id. In the future glues can be used to glue other types as well*/ 1212 1213 /**First id type (usually 'figure')*/ 1214 this.type1 = 'figure'; 1215 1216 /**First id type (usually 'connector')*/ 1217 this.type2 = 'connector'; 1218 1219 /**object type used for JSON deserialization*/ 1220 this.oType = 'Glue'; 1221 } 1222 1223 /**Creates a {Glue} out of JSON parsed object 1224 *@param {JSONObject} o - the JSON parsed object 1225 *@return {Glue} a newly constructed Glue 1226 *@author Alex Gheorghiu <alex@scriptoid.com> 1227 **/ 1228 Glue.load = function(o){ 1229 var newGlue = new Glue(23, 40); //fake constructor 1230 1231 newGlue.id1 = o.id1; 1232 newGlue.id2 = o.id2; 1233 newGlue.type1 = o.type1; 1234 newGlue.type2 = o.type2; 1235 1236 return newGlue; 1237 } 1238 1239 1240 /**Creates a an {Array} of {Glue} out of JSON parsed array 1241 *@param {JSONObject} v - the JSON parsed {Array} 1242 *@return {Array} of newly loaded {Glue}s 1243 *@author Alex Gheorghiu <alex@scriptoid.com> 1244 **/ 1245 Glue.loadArray = function(v){ 1246 var newGlues = []; 1247 1248 for(var i=0; i<v.length; i++){ 1249 newGlues.push(Glue.load(v[i])); 1250 } 1251 1252 return newGlues; 1253 } 1254 1255 Glue.prototype = { 1256 /**Compares to another Glue 1257 *@param {Glue} anotherGlue - - the other glue 1258 *@return {Boolean} - true if equals, false otherwise 1259 **/ 1260 equals:function(anotherGlue){ 1261 if(!anotherGlue instanceof Glue){ 1262 return false; 1263 } 1264 1265 return this.id1 == anotherGlue.id1 1266 && this.id2 == anotherGlue.id2 1267 && this.type1 == anotherGlue.type1 1268 && this.type2 == anotherGlue.type2; 1269 }, 1270 1271 /**String representation of the Glue 1272 *@return {String} - the representation 1273 **/ 1274 toString:function(){ 1275 return 'Glue : (' + this.id1 + ', ' + this.id2 + ')'; 1276 } 1277 }