Tuesday, April 22, 2014

How to add more than one connection between two raphael rectangles by modifying graffle.js

Brief history of this code:

Hi, friends i am learning Raphael js and creating an application in it. i needed to create a mechanism which would allow more than one connections between two Raphael rectangles and i was having alot of i mean tons of issues and thoughts on how to do it and it kept me busy a lot. i was so tired that i had to make stackoverflow account and ask help about it, but the help i got added one more thought to me. At last i am able to create a mechanism which will not only allow more than one connection but also renders it on moving the rectangle. yes i know it still has issues but this is the basic code to help any other who need this and can use it and don't have struggle as much as i did.

Lets get started:

create and HTML document and use the following code:


 <!doctype html>  
 <html>  
 <body>  
      <div id="canvas"></div>  
      <script type="text/javascript" src="js/Raphael.js"></script>  
      <script type="text/javascript" src="js/app.js"></script>  
 </body>  
 </html>  

in the app.js use the following code:

 function lineDistance( point1, point2 )  
 {  
  var xs = 0;  
  var ys = 0;  
  xs = point2.x - point1.x;  
  xs = xs * xs;  
  ys = point2.y - point1.y;  
  ys = ys * ys;  
  return Math.sqrt( xs + ys );  
 }  
 Raphael.fn.connection = function (objFrom, objTo, line, bg) {  
   if (objFrom.line && objFrom.from && objFrom.to) {  
     line = objFrom;  
     objFrom = line.from;  
     objTo = line.to;  
   }  
   var bb1 = objFrom.getBBox(),  
     bb2 = objTo.getBBox();  
     var obj1freeNodes = objFrom.data('freeNodes');  
     var obj2freeNodes = objTo.data('freeNodes');  
     var p = [];  
     obj1freeNodes.forEach(function (el) {  
     p.push(el);  
    })  
     obj2freeNodes.forEach(function (el) {  
     p.push(el);  
    })  
     var distance = [], d = {};  
     for (var i = 0; i <obj1freeNodes.length; i++) {  
     for (var j = obj1freeNodes.length; j <p.length; j++) {  
        var point1 = {x:p[i].x, y: p[i].y};  
        var point2 = {x:p[j].x, y: p[j].y};  
       if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {  
         distance.push(lineDistance(point1, point2));  
        d[distance[distance.length - 1]] = [i, j];  
       }  
     }  
   }  
     if (distance.length == 0) {  
      var res = [0, obj1freeNodes.length];  
    } else {  
      res = d[Math.min.apply(Math, distance)];  
    }  
    var x1 = p[res[0]].x,  
      y1 = p[res[0]].y,  
      x4 = p[res[1]].x,  
      y4 = p[res[1]].y;  
    //remove to connecting point  
    for(var i=0;i<obj1freeNodes.length; i++){  
    if(i== res[0]){  
      obj1freeNodes.splice(i,1);   
     }  
    }  
    for(var i=0;i<obj2freeNodes.length; i++){  
    if(i == (res[1]-obj1freeNodes.length-1)){  
      obj2freeNodes.splice(i,1);   
     }  
    }  
   objFrom.data('freeNodes', obj1freeNodes);  
   objTo.data('freeNodes', obj2freeNodes);  
   p = [];  
     var path = ["M", x1.toFixed(3), y1.toFixed(3), "L", /*x2, y2, x3, y3,*/ x4.toFixed(3), y4.toFixed(3)].join(",");  
   if (line && line.line) {  
     line.bg && line.bg.attr({path: path});  
     line.line.attr({path: path});  
   } else {  
     var color = typeof line == "string" ? line : "#000";  
           var conLine = this.path(path).attr({  
          stroke: color,  
          fill: "none",  
          "arrow-end": "block-wide-long",  
          "stroke-width": 3,  
          });  
           pathObj = {  
        bg: bg && bg.split && this.path(path).attr({  
          stroke: bg.split("|")[0],  
          fill: "none",  
          "stroke-width": bg.split("|")[1] || 3  
        }),  
        line: conLine,  
        from: objFrom,  
        to: objTo,  
      };  
      return pathObj;  
   }  
 };  
 Raphael.el.getNodes = function()  
   {  
    //calculate the element nodes and return them  
    var obj = this.getBBox();  
    var objX = parseInt(obj.x);  
    var objY = parseInt(obj.y);  
    var objWidth = parseInt(obj.width);  
    var objHeight = parseInt(obj.height);  
    var maxCons = 8;  
    var scaleCut = 10;  
    var topPositions = [], rightPositions = [], bottomPositions = [], leftPositions = [];  
    //get all possible connectors based on maxCons and scaleCut  
   var objCons = [];  
   for(var i= 0; i<maxCons; i++){  
     topPositions.push({x: (objX + ((objWidth-scaleCut)/maxCons)*i)+i*2, y: objY-1});  
     rightPositions.push({x: objX + objWidth + 1, y: (objY + ((objHeight-scaleCut)/maxCons)*i)+i*2});  
     bottomPositions.push({x: ((objX+3) + ((objWidth-(scaleCut-2))/maxCons)*i)+i*2, y: objY + objHeight +1});  
     leftPositions.push({x: objX - 1, y: ((objY+4) + ((objHeight-(scaleCut+1))/maxCons)*i)+i*2});    
    }  
    // push all positions to objCons array   
   pushArryToArray(topPositions, objCons);  
   pushArryToArray(rightPositions, objCons);  
   pushArryToArray(bottomPositions, objCons);  
   pushArryToArray(leftPositions, objCons);  
   //this.data('freeNodes',objCons);  
    return objCons;  
   }  
 //pushes one array contents to another array  
 var pushArryToArray = function(sourceArr, targetArr){  
  for(var i=0; i<sourceArr.length;i++){  
    // draw connecting points  
    // R.circle(sourceArr[i].x,sourceArr[i].y,2).attr({'fill':'red', 'stroke':'none'});  
    targetArr.push(sourceArr[i]);  
   }  
 }  
 var R = Raphael("canvas","400","400");  
 //window.onload = function() {  
 start = function() {  
     this.ox = this.attr("x");  
     this.oy = this.attr("y");  
     this.animate({  
       opacity: .75  
     }, 500, ">");  
 }  
 move = function(dx, dy) {  
  this.attr({  
      x: this.ox + dx,  
      y: this.oy + dy  
     });  
   //on moving events reintializing free nodes of all events   
   for(var i = 0; i<arrAllEvents.length; i++){  
      arrAllEvents[i].data('freeNodes', arrAllEvents[i].getNodes());  
     }  
   //rendering connections on event move  
   for (var i = connections.length; i--;) {  
     R.connection(connections[i]);  
   }  
    R.safari();  
 }  
 up = function() {  
 }  
 var eventOne = R.rect(10,10,100, 100).attr({  
       fill: Raphael.getColor(),  
       stroke: "none",  
       cursor: "move"  
     });  
 var eventTwo = R.rect(220,10,100, 100).attr({  
       fill: Raphael.getColor(),  
       stroke: "none",  
       cursor: "move"  
     });  
 var eventThree = R.rect(220,220,100, 100).attr({  
       fill: Raphael.getColor(),  
       stroke: "none",  
       cursor: "move"  
     });  
 //intializing free connecting nodes 1st time  
 eventOne.data('freeNodes', eventOne.getNodes());  
 eventTwo.data('freeNodes', eventTwo.getNodes());  
 eventThree.data('freeNodes', eventThree.getNodes());  
 //storing all events in array  
 var arrAllEvents = []  
 arrAllEvents.push(eventOne);  
 arrAllEvents.push(eventTwo);  
 arrAllEvents.push(eventThree);  
 //to draw the connections b/w events  
 var connections = [];  
 connections.push(R.connection(eventOne, eventTwo, Raphael.getColor()));  
 connections.push(R.connection(eventOne, eventTwo, Raphael.getColor()));  
 connections.push(R.connection(eventOne, eventTwo, Raphael.getColor()));  
 connections.push(R.connection(eventOne, eventThree, Raphael.getColor()));  
 connections.push(R.connection(eventOne, eventThree, Raphael.getColor()));  
 //dragging events  
 for(var i = 0; i<arrAllEvents.length; i++){  
      arrAllEvents[i].drag(move, start, up);  
     }  
 //}  


View it on Jsfiddle

Please let me know about my this effort, or to make it much more useful.

About Me

My photo
I play a lot of computer games, design stuff and enjoy the life with my cutest baby girl.