1 /** 2 * Copyright 2010 Scriptoid s.r.l 3 **/ 4 5 /** 6 *Handles are created on-the-fly for a figure. They are completelly managed by the HandleManager 7 *Each handle is responsable for an action. The {Handle} does not need to keep a reference to the parent shape 8 *as the HandleManager will do that. 9 *@constructor 10 *@this {Handle} 11 *@param {String} type - the type of handle 12 **/ 13 function Handle(type){ 14 /**Type of Handle*/ 15 this.type = type; 16 17 /*These are stupidly initialized to 0 but they should not be present at all... 18 *anyway they got set to the proper values in HandleManager::handleGetAll() function*/ 19 20 /**The center of the circle (x coordinates)*/ 21 this.x = 0; 22 23 /**The center of the circle (y coordinates)*/ 24 this.y = 0; 25 26 /**Used by Connector handles, to not display redundant handles (i.e. when they are on the same line)*/ 27 this.visible = true; 28 } 29 30 /**It's a (static) vector of handle types 31 * Note: R - stand for rotation 32 * Note: More handles might be added in the future : like handles to increase the number of edges for a hexagone 33 * Those handles will be specific for a figure 34 **/ 35 Handle.types = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'r' ]; //DO NOT CHANGE THE ORDER OF THESE VALUES 36 37 /**It's a (static) vector of connector types*/ 38 Handle.connectorTypes = ['ns', 'ew']; 39 40 /**Creates a {Handle} out of JSON parsed object 41 *@param {JSONObject} o - the JSON parsed object 42 *@return {Handle} a newly constructed Handle 43 *@author Alex Gheorghiu <alex@scriptoid.com> 44 **/ 45 Handle.load = function(o){ 46 var newHandle = new Handle(o.type); 47 newHandle.x = o.x; 48 newHandle.y = o.y; 49 newHandle.visible = o.visible; 50 return newHandle; 51 } 52 53 /**Creates an array of handles from an array of {JSONObject}s 54 *@param {Array} v - the array of JSONObjects 55 *@return an {Array} of {Handle}s 56 *@author Alex Gheorghiu <alex@scriptoid.com> 57 **/ 58 Handle.loadArray = function(v){ 59 var newHandles = []; 60 for(var i=0; i< v.length; i++){ 61 newHandles.push(Handle.load(v[i])); 62 } 63 return newHandles; 64 } 65 66 /**Default handle radius*/ 67 Handle.RADIUS = 3; 68 69 Handle.prototype = { 70 /**Compares to another Handle 71 *@param {Handle} group - - the other glue 72 *@return {Boolean} - true if equals, false otherwise 73 **/ 74 equals : function(anotherHandle){ 75 if(!anotherHandle instanceof Handle){ 76 return false; 77 } 78 79 return this.type == anotherHandle.type 80 && this.x == anotherHandle.x 81 && this.y == anotherHandle.y 82 && this.visible == anotherHandle.visible; 83 }, 84 85 86 /**Handle actions for Figure 87 * 88 *@param {Array } lastMove - an array that will hold [x,y] of last x & y coordinates 89 *@param {Number} newX - new X coordinate 90 *@param {Number} newY - new Y coordinate 91 **/ 92 actionFigure: function(lastMove, newX, newY){ 93 //see if we have a resize and prepare the figure by moving it back to Origin and "unrotate" it 94 if(this.type != 'r'){ //if not "rotate" (figure), "updown", "leftright" (connector) 95 //find the angle by which the figure was rotated (for any figure this is initally 0 so if != than 0 we have a rotation) 96 var angle = Util.getAngle(HandleManager.figure.rotationCoords[0], HandleManager.figure.rotationCoords[1]); 97 98 //save initial figure's center 99 var oldCenter = HandleManager.figure.rotationCoords[0].clone(); 100 101 //move the figure to origine and "unrotate" it 102 HandleManager.figure.transform(Matrix.translationMatrix(-oldCenter.x,-oldCenter.y)); 103 HandleManager.figure.transform(Matrix.rotationMatrix(-angle)); 104 HandleManager.figure.transform(Matrix.translationMatrix(oldCenter.x,oldCenter.y)); 105 106 //move the new [x,y] to the "un-rotated" and "un-translated" space 107 var p = new Point(newX,newY); 108 p.transform(Matrix.translationMatrix(-oldCenter.x,-oldCenter.y)); 109 p.transform(Matrix.rotationMatrix(-angle)); 110 p.transform(Matrix.translationMatrix(oldCenter.x,oldCenter.y)); 111 newX = p.x; 112 newY = p.y; 113 114 var handlerPoint=new Point(this.x,this.y) //Handler's center point (used to draw it's circle) 115 //rotate that as well. 116 handlerPoint.transform(Matrix.translationMatrix(-oldCenter.x,-oldCenter.y)); 117 handlerPoint.transform(Matrix.rotationMatrix(-angle)); 118 handlerPoint.transform(Matrix.translationMatrix(oldCenter.x,oldCenter.y)); 119 } 120 121 var figBounds=HandleManager.figure.getBounds(); 122 123 var transX = 0; //the amount of translation on Ox 124 var transY = 0; //the amount of translation on Oy 125 var scaleX = 1; //the scale percentage on Ox 126 var scaleY = 1; //the scale percentage on Oy 127 var arc = false; 128 129 switch(this.type){ 130 case 'n': 131 /*move the xOy coodinates at the bottom of the figure and then scale*/ 132 transY = figBounds[3]; 133 if(newY < figBounds[3]-5){ //North must not get too close to South 134 scaleY = (figBounds[3]-newY)/(figBounds[3]-handlerPoint.y); 135 } 136 break; 137 138 case 's': 139 /*move the xOy coodinates at the top of the figure (superfluous as we are there already) and then scale*/ 140 transY = figBounds[1]; 141 if(newY > figBounds[1]+5){ //South must not get too close to North 142 scaleY = (newY-figBounds[1])/(handlerPoint.y-figBounds[1]); 143 } 144 break; 145 146 case 'w': 147 /*move the xOy coordinates at the right of the figure and then scale*/ 148 transX = figBounds[2]; 149 if(newX < figBounds[2]-5){ //West(newX) must not get too close to East(figBounds[2]) 150 scaleX = (figBounds[2]-newX)/(figBounds[2]-handlerPoint.x); 151 } 152 break; 153 154 case 'e': 155 /*move the xOy coodinates at the left of the figure (superfluous as we are there already) and then scale*/ 156 transX = figBounds[0]; 157 if(newX > figBounds[0]+5){ 158 scaleX = (newX-figBounds[0])/(handlerPoint.x-figBounds[0]); 159 } 160 break; 161 162 case 'nw': 163 /*You can think as a combined North and West action*/ 164 transX = figBounds[2]; 165 transY = figBounds[3]; 166 if(newX<figBounds[2]-5 && newY<figBounds[3]-5){ 167 scaleY = (figBounds[3]-newY) /(figBounds[3]-handlerPoint.y); 168 scaleX = (figBounds[2]-newX) / (figBounds[2]-handlerPoint.x); 169 } 170 break; 171 172 case 'ne': 173 transX = figBounds[0] 174 transY = figBounds[3]; 175 if(newX>figBounds[0]+5 && newY<figBounds[3]-5){ 176 scaleX = (newX-figBounds[0])/(handlerPoint.x-figBounds[0]); 177 scaleY = (figBounds[3]-newY)/(figBounds[3]-handlerPoint.y); 178 } 179 break; 180 181 case 'sw': 182 transX = figBounds[2] 183 transY = figBounds[1]; 184 if(newX<figBounds[2]-5 && newY>figBounds[1]+5){ 185 scaleX = (figBounds[2]-newX)/((figBounds[2]-handlerPoint.x)); 186 scaleY = (newY-figBounds[1])/(handlerPoint.y-figBounds[1]); 187 } 188 break; 189 190 case 'se': 191 transX = figBounds[0]; 192 transY = figBounds[1]; 193 if(newX>figBounds[0]+5 && newY>figBounds[1]+5){ 194 scaleY= (newY-figBounds[1]) / (handlerPoint.y-figBounds[1]); 195 scaleX= (newX-figBounds[0]) / (handlerPoint.x-figBounds[0]); 196 } 197 break; 198 199 case 'r': 200 //rotationCoords[0] is always the center of the shape, we clone it as when we do -rotationCoords[0].x, it is set to 0. 201 var center = HandleManager.figure.rotationCoords[0].clone(); 202 var endAngle = Util.getAngle(HandleManager.figure.rotationCoords[0],new Point(newX,newY)); 203 var startAngle = Util.getAngle(HandleManager.figure.rotationCoords[0],HandleManager.figure.rotationCoords[1]);//new Point(lastMove[0],lastMove[1]) 204 var rotAngle = endAngle - startAngle; 205 206 207 HandleManager.figure.transform(Matrix.translationMatrix(-center.x,-center.y)) 208 HandleManager.figure.transform(Matrix.rotationMatrix(rotAngle)) 209 HandleManager.figure.transform(Matrix.translationMatrix(center.x,center.y)); 210 break; 211 } 212 213 /*By default the NW, NE, SW and SE are scalling keeping the ratio 214 *but you can use SHIFT to cause a free (no keep ratio) change 215 *So, if no SHIFT pressed we force a "keep ration" resize 216 **/ 217 if(!SHIFT_PRESSED && transX != 0 && transY != 0){//keep ratios, only affects ne/nw resize 218 219 //if we are scaling along the x axis (West or East resize), with an arc(behaves like corner) then scale relative to x movement 220 //TODO: what's the reason for this? 221 if(this.getCursor()=="w-resize" || this.getCursor()=="e-resize"){ 222 scaleY = scaleX; 223 } 224 else { //for everything else, scale based on y 225 scaleX = scaleY; 226 } 227 } 228 229 if(this.type!='r'){ 230 HandleManager.figure.transform(Matrix.translationMatrix(-transX, -transY)); 231 HandleManager.figure.transform(Matrix.scaleMatrix(scaleX, scaleY)) 232 HandleManager.figure.transform(Matrix.translationMatrix(transX, transY)); 233 234 235 //rotate the figure back to its original coordinates 236 HandleManager.figure.transform(Matrix.translationMatrix(-oldCenter.x,-oldCenter.y)); 237 HandleManager.figure.transform(Matrix.rotationMatrix(angle)); 238 HandleManager.figure.transform(Matrix.translationMatrix(oldCenter.x,oldCenter.y)); 239 } 240 }, 241 242 /** 243 *Handle actions for Connector 244 * 245 *@param {Array } lastMove - an array that will hold [x,y] of last x & y coordinates 246 *@param {Number} newX - new X coordinate 247 *@param {Number} newY - new Y coordinate 248 **/ 249 actionConnector: function(lastMove, newX, newY){ 250 switch(this.type){ 251 case 'v': 252 var index; 253 //find the two turning points this handle is in between 254 for(var i = 1; i < HandleManager.figure.turningPoints.length-1; i++){ 255 if(HandleManager.figure.turningPoints[i-1].y == HandleManager.figure.turningPoints[i].y 256 && HandleManager.figure.turningPoints[i].y == this.y 257 && Math.min(HandleManager.figure.turningPoints[i].x, HandleManager.figure.turningPoints[i-1].x) <= this.x 258 && Math.max(HandleManager.figure.turningPoints[i].x, HandleManager.figure.turningPoints[i-1].x) >= this.x) 259 { 260 index = i; 261 } 262 } 263 //Pick turning points neighbours and translate them on Oy 264 HandleManager.figure.turningPoints[index-1].transform( Matrix.translationMatrix(0, newY - lastMove[1]) ); 265 HandleManager.figure.turningPoints[index].transform( Matrix.translationMatrix(0, newY - lastMove[1]) ); 266 break; 267 268 case 'h': 269 var index; 270 //find the two turning points this handle is in between 271 for(var i = 1; i < HandleManager.figure.turningPoints.length-1; i++){ 272 if(HandleManager.figure.turningPoints[i-1].x == HandleManager.figure.turningPoints[i].x 273 && HandleManager.figure.turningPoints[i].x == this.x 274 && Math.min(HandleManager.figure.turningPoints[i].y, HandleManager.figure.turningPoints[i-1].y) <= this.y 275 && Math.max(HandleManager.figure.turningPoints[i].y, HandleManager.figure.turningPoints[i-1].y) >= this.y) 276 { 277 index = i; 278 } 279 } 280 //Pick turning points neighbours and translate them on Ox 281 HandleManager.figure.turningPoints[index-1].transform( Matrix.translationMatrix(newX-lastMove[0],0) ); 282 HandleManager.figure.turningPoints[index].transform( Matrix.translationMatrix(newX-lastMove[0],0) ); 283 break; 284 } 285 HandleManager.figure.updateMiddleText(); 286 }, 287 288 /**Handle an action. Simply dispatch to the correct handler 289 *@param {Array } lastMove - an array that will hold [x,y] of last x & y coordinates 290 *@param {Number} newX - new X coordinate 291 *@param {Number} newY - new Y coordinate 292 **/ 293 action: function(lastMove, newX, newY){ 294 if(lastMove == null || lastMove.length != 2){ 295 throw new Exception('Handle:action() Last move is wrong'); 296 } 297 if(HandleManager.figure instanceof Connector){ 298 this.actionConnector(lastMove, newX, newY); 299 } 300 else{ 301 this.actionFigure(lastMove, newX, newY); 302 } 303 }, 304 305 306 /**This is the method you have to call to paint a handler 307 * All handles will be circles...so we avoid to much of the computing for rectangle handles 308 * They will have a filling color (green) and a stoke (black) 309 * @param {Context} context - the 2D context 310 **/ 311 paint : function(context){ 312 313 context.beginPath(); 314 context.arc(this.x, this.y, Handle.RADIUS, 0, Math.PI*2, false); 315 context.fillStyle = "rgb(0,255,0)"; 316 context.closePath(); 317 context.fill(); 318 319 context.beginPath(); 320 context.arc(this.x, this.y, Handle.RADIUS, 0, Math.PI*2, false); 321 context.strokeStyle = "rgb(0,0,0)"; 322 context.closePath(); 323 context.stroke(); 324 325 326 if(this.type == 'r'){ 327 var line = new Line(new Point(this.x,this.y), new Point(HandleManager.handles[1].x,HandleManager.handles[1].y)) 328 line.style.dashLength = 3; 329 line.style.strokeStyle="grey"; 330 line.paint(context); 331 } 332 }, 333 334 335 /**See if the handle contains a point 336 *@param {Number} x - the x coordinate of the point 337 *@param {Number} y - the y coordinate of the point 338 **/ 339 contains:function(x,y){ 340 var p=new Point(this.x,this.y); 341 return p.near(x,y, Handle.RADIUS); 342 }, 343 344 345 /** 346 *Get a handle bounds 347 **/ 348 getBounds : function(){ 349 return [this.x - Handle.RADIUS, this.y - Handle.RADIUS, this.x + Handle.RADIUS,this.y + Handle.RADIUS]; 350 }, 351 352 353 /** 354 *Transform the Handle through a matrix 355 *@param {Matrix} matrix - the matrix that will perform the transformation 356 **/ 357 transform: function(matrix){ 358 var p=new Point(this.x,this.y) 359 p.transform(matrix); 360 this.x=p.x; 361 this.y=p.y; 362 }, 363 364 365 /**Get the specific cursor for this handle. Cursor is ONLY a visual clue for 366 * the user to know how to move his mouse. 367 * 368 *Behaviour: 369 * If North handle is in the North we have 'Up/Down arrow" cursor 370 * If North handle is in the West (so it has "Left/Right arrow") (or anything different that North) 371 * we have 'Left/Right arrow' cursor but the figure will expand as follows: 372 * - rotate back to initial position 373 * - expand North 374 * - rotate back to current position 375 * - repaint 376 * @see <a href="http://www.w3schools.com/css/pr_class_cursor.asp">http://www.w3schools.com/css/pr_class_cursor.asp</a> for cusor values 377 * @author Zack Newsham <zack_newsham@yahoo.co.uk> 378 * @author Alex Gheorghiu <alex@scriptoid.com> 379 **/ 380 381 getCursor:function(){ 382 if(HandleManager.figure instanceof Connector){ 383 if(this.visible == false){ 384 return ""; 385 } 386 if(this.type == 'v'){ 387 return 'ns-resize'; 388 } 389 else{ 390 return 'ew-resize'; 391 } 392 } //end if Connector 393 else{ 394 if(this.visible == false){ 395 return ""; 396 } 397 if(this.type == 'r'){ 398 return 'move'; 399 } 400 401 var figureBounds = HandleManager.figure.getBounds(); //get figure's bounds 402 var figureCenter = new Point(figureBounds[0] + ((figureBounds[2]-figureBounds[0])/2), 403 (figureBounds[1] + ((figureBounds[3] - figureBounds[1])/2)) ); //get figure's center 404 405 //find north 406 var closestToNorthIndex = -1; //keeps the index of closest handle to North 407 var minAngleToNorth = 2 * Math.PI; //keeps the smallest (angular) distante to North 408 var myIndex = -1; 409 410 for(var i=0; i<HandleManager.handles.length-1; i++){ 411 var handleCenter = new Point(HandleManager.handles[i].x, HandleManager.handles[i].y); 412 var angle = Util.getAngle(figureCenter,handleCenter); //get the angle between those 2 points 0=n 413 414 if(angle <= Math.PI){ //quadrant I or II 415 if(angle < minAngleToNorth){ 416 minAngleToNorth = angle; 417 closestToNorthIndex = i; 418 } 419 } 420 else{ //quadrant III or IV 421 if(2 * Math.PI - angle < minAngleToNorth){ 422 minAngleToNorth = 2 * Math.PI - angle 423 closestToNorthIndex = i; 424 } 425 } 426 } 427 428 //alert("closest to North is : " + closestToNorthIndex); 429 for(var k=0; k<8; k++){ //there will always be 8 resize handlers 430 //we do not use modulo 9 as we want to ignore the "rotate" handle 431 if(HandleManager.handles[(closestToNorthIndex + k) % 8] == this){ 432 return Handle.types[k]+"-resize"; 433 } 434 } 435 } //end if Figure 436 437 return ""; 438 } 439 } 440 441 442 /**HandleManager will act like a Singleton (even not defined as one) 443 * You will attach a Figure to it and he will be in charge with the figure manipulation 444 * @constructor 445 * @this {HandleManager} 446 **/ 447 function HandleManager(){ 448 } 449 450 /**The shape (figure or connector) that the HandleManager will manage*/ 451 HandleManager.figure = null; 452 453 /**An {Array} with current handles*/ 454 HandleManager.handles = []; 455 456 /**An {Array} with connector handles*/ 457 HandleManager.connectorHandles = []; 458 459 /**Selection rectangle (the rectangle upon the Handles will stay in case of a Figure/Group)*/ 460 HandleManager.selectRect = null; 461 462 /**Currently selected handle*/ 463 HandleManager.handleSelectedIndex = -1; 464 465 /**Get selected handle or null if no handler selected*/ 466 HandleManager.handleGetSelected = function(){ 467 if(HandleManager.handleSelectedIndex!=-1){ 468 return HandleManager.handles[HandleManager.handleSelectedIndex]; 469 } 470 return null; 471 } 472 473 /**Use this method to set a new shape (Figure or Connetor) to this manager. 474 * Every time a new figure is set, old handles will dissapear (got erased by new figure's handles) 475 **/ 476 HandleManager.figureSet = function(shape){ 477 HandleManager.figure = shape; 478 479 //1. clear old/previous handles 480 HandleManager.handles = []; 481 482 //2. setup/add handles for this figure 483 if(shape instanceof Connector) { 484 HandleManager.selectRect = null; 485 486 //we don't want to affect the start or end points 487 for(var i=1; i<shape.turningPoints.length-2; i++){ 488 var h; 489 var previousAngle = Util.getAngle(HandleManager.figure.turningPoints[i-1], HandleManager.figure.turningPoints[i], 0.00001); 490 var currentAngle = Util.getAngle(HandleManager.figure.turningPoints[i], HandleManager.figure.turningPoints[i+1], 0.00001); 491 var nextAngle = Util.getAngle(HandleManager.figure.turningPoints[i+1],HandleManager.figure.turningPoints[i+2], 0.00001); 492 493 if(previousAngle != currentAngle && currentAngle != nextAngle){ 494 if(shape.turningPoints[i].x == shape.turningPoints[i+1].x){ //same vertical 495 h = new Handle("h"); 496 h.x = HandleManager.figure.turningPoints[i].x; 497 h.y = (HandleManager.figure.turningPoints[i].y + HandleManager.figure.turningPoints[i+1].y) / 2; 498 499 } 500 else{ // same horizontal 501 h = new Handle("v"); 502 h.x = (HandleManager.figure.turningPoints[i].x + HandleManager.figure.turningPoints[i+1].x) / 2; 503 h.y = HandleManager.figure.turningPoints[i].y; 504 } 505 h.visible = true; 506 HandleManager.handles.push(h); 507 } 508 } 509 } 510 else if(shape instanceof Figure || shape instanceof Group){ 511 //find Figure's angle 512 var angle = Util.getAngle(HandleManager.figure.rotationCoords[0], HandleManager.figure.rotationCoords[1]); 513 514 //rotate it back to "normal" space (from current space) 515 HandleManager.figure.transform(Matrix.rotationMatrix(-angle), false); 516 HandleManager.selectRect = new Polygon(); 517 518 //construct bounds of the Figure in "normal" space 519 var bounds = HandleManager.figure.getBounds(); 520 HandleManager.selectRect.points = []; 521 HandleManager.selectRect.addPoint(new Point(bounds[0] - 10, bounds[1] - 10)); //top left 522 HandleManager.selectRect.addPoint(new Point(bounds[2]+ 10, bounds[1] - 10)); //top right 523 HandleManager.selectRect.addPoint(new Point(bounds[2] + 10, bounds[3] + 10)); //bottom right 524 HandleManager.selectRect.addPoint(new Point(bounds[0] - 10, bounds[3] + 10)); //bottom left 525 526 bounds = HandleManager.selectRect.getBounds(); 527 528 //update current handles 529 var handle = new Handle("nw"); //NW 530 handle.x = bounds[0]; 531 handle.y = bounds[1]; 532 HandleManager.handles.push(handle); 533 534 handle = new Handle("n"); //N 535 handle.x = bounds[0]+(bounds[2]-bounds[0])/2; 536 handle.y = bounds[1]; 537 HandleManager.handles.push(handle); 538 539 handle = new Handle("ne"); //NE 540 handle.x = bounds[2]; 541 handle.y = bounds[1]; 542 HandleManager.handles.push(handle); 543 544 handle = new Handle("e"); //E 545 handle.x = bounds[2]; 546 handle.y = bounds[1]+(bounds[3]-bounds[1])/2; 547 HandleManager.handles.push(handle); 548 549 handle = new Handle("se"); //SE 550 handle.x = bounds[2]; 551 handle.y = bounds[3]; 552 HandleManager.handles.push(handle); 553 554 handle = new Handle("s"); //S 555 handle.x = bounds[0]+(bounds[2]-bounds[0])/2; 556 handle.y = bounds[3]; 557 HandleManager.handles.push(handle); 558 559 handle = new Handle("sw"); //SW 560 handle.x = bounds[0]; 561 handle.y = bounds[3]; 562 HandleManager.handles.push(handle); 563 564 handle = new Handle("w"); //W 565 handle.x = bounds[0]; 566 handle.y = bounds[1]+(bounds[3]-bounds[1])/2; 567 HandleManager.handles.push(handle); 568 569 570 handle = new Handle("r"); //Rotation 571 handle.x = bounds[0]+(bounds[2]-bounds[0])/2; 572 handle.y = bounds[1]-20; 573 HandleManager.handles.push(handle); 574 575 576 HandleManager.selectRect.transform(Matrix.rotationMatrix(angle)); 577 578 //rotate figure from "normal" space to current space 579 HandleManager.figure.transform(Matrix.rotationMatrix(angle),false); 580 if(shape instanceof Figure){ 581 if(shape.primitives[0] instanceof Text && shape.primitives.length == 1){ 582 for(var i = 0; i < HandleManager.handles.length-1; i++){ 583 HandleManager.handles[i].visible = false; 584 } 585 } 586 } 587 //now transform the handles from "normal" space too 588 for(var i=0; i<HandleManager.handles.length; i++){ 589 HandleManager.handles[i].transform(Matrix.rotationMatrix(angle)); 590 } 591 } 592 } 593 594 /**Returns all handles for a shape (figure or connector). 595 *It does not mean that the HandleManager keeps records of all Handles for a 596 *Figure but more likely they are computed on-the-fly 597 *@return an {Array} of {Handle} that you can further use to manage the figure 598 **/ 599 HandleManager.handleGetAll = function(){ 600 return HandleManager.handles; 601 } 602 603 /**Returns the handle from a certain coordinates 604 *@param {Number} x - the value on Ox 605 *@param {Number} y - the value on Oy 606 ***/ 607 HandleManager.handleGet=function(x,y){ 608 for(var i=0; i<HandleManager.handles.length; i++){ 609 if(HandleManager.handles[i].contains(x,y)){ 610 return HandleManager.handles[i]; 611 } 612 } 613 return null; 614 } 615 616 /** 617 *Select the handle from a certain coodinates 618 *@param {Number} x - the value on Ox 619 *@param {Number} y - the value on Oy 620 **/ 621 HandleManager.handleSelectXY = function(x,y){ 622 HandleManager.handleSelectedIndex=-1; 623 for (var i=0; i<HandleManager.handles.length; i++){ 624 if(HandleManager.handles[i].contains(x,y)){ 625 HandleManager.handleSelectedIndex = i; 626 } 627 } 628 } 629 630 /** 631 *Clear HandleManager 632 **/ 633 HandleManager.clear = function(){ 634 HandleManager.handleSelectedIndex = -1; 635 HandleManager.figure = null; 636 HandleManager.handles = []; 637 } 638 639 /**Paint the Handles, actually the HandleManager will delegate each paint to 640 *the proper Handle to paint 641 *@param {Context} context - the 2D context 642 **/ 643 HandleManager.paint = function(context){ 644 var handles = HandleManager.handleGetAll(); //calling this sets the coordinates 645 646 //paint first the selection rectanle 647 context.save(); 648 649 //paint selection rectagle (if present - only for Figure and Group) 650 if(HandleManager.selectRect != null){ 651 //alert("Handle manager paint!"); 652 HandleManager.selectRect.style.strokeStyle="grey"; 653 HandleManager.selectRect.paint(context); 654 } 655 656 //now paint handles 657 for(var i=0; i<handles.length; i++){ 658 if(handles[i].visible == true){ 659 handles[i].paint(context); 660 } 661 } 662 context.restore() 663 } 664