2013-03-04 152 views
11

我想弄清楚如何动态添加端点锚到jsPlumb容器。jsPlumb - 每边动态端点锚

我想只在左侧有源端点,在右侧有目标端点。

问题是,我无法找到任何方法来解决问题,而无需诉诸一些黑客,就像我现在正在做的那样。

jsPlumb支持Continuous Anchors,但单个锚的位置将根据连接器之间的方向和连续锚的数量重新计算。这意味着源端点和目标端点可以共享容器的同一侧,这是我想避免的。

这里是一个jsFiddler code I came up with

这里是我使用的破解,并重新计算锚定位自己的代码的一部分(当添加按钮被点击),具有一定的越野车结果:(

function fixEndpoints(endpoints) { 

      //there are 2 types - input and output 

      var inputAr = $.grep(endpoints, function (elementOfArray, indexInArray) { 
       return elementOfArray.isSource; //input 
      }); 

      var outputAr = $.grep(endpoints, function (elementOfArray, indexInArray) { 
       return elementOfArray.isTarget; //output 
      }); 

      calculateEndpoint(inputAr, true); 
      calculateEndpoint(outputAr, false); 
     } 

     function calculateEndpoint(endpointArray, isInput) { 

      //multiplyer 
      var mult = 1/endpointArray.length; 

      for (var i = 0; i < endpointArray.length; i++) { 

       if (isInput) { 
        endpointArray[i].anchor.x = 1; 
        endpointArray[i].anchor.y = mult * i;//, 1, 0] }; 
       } 
       else { 
        endpointArray[i].anchor.x = 0; 
        endpointArray[i].anchor.y = mult * i;//, -1, 0] }; 
       } 
      } 
     } 



     //Add additional anchor 
     $(".button_add").live("click", function() { 

      var parentnode = $(this)[0].parentNode.parentNode; 

      jsPlumb.addEndpoint(
       parentnode, 
       anEndpointSource 
      ); 

      jsPlumb.addEndpoint(
       parentnode, 
       anEndpointDestination 
      ); 

      //get list of current endpoints 
      var endpoints = jsPlumb.getEndpoints(parentnode); 

      //fix endpoints 
      fixEndpoints(endpoints); 

      jsPlumb.recalculateOffsets(); 
      jsPlumb.repaint(parentnode); 
     }); 

Expected result

从上图中可以看到,左侧只有源端点(Dot)和右侧(Box)只有目标端点,一旦添加了新端点,将根据锚点上的锚点数重新计算锚点e方。

这个工作,但仍然错误:位置只更新一次我移动容器和容器之间的连接也不正确。

我想吃点什么,是为它工作并连接正确的物品(最好使用正确的jsPlumb代码,而不诉诸黑客)

回答

11

我终于想通了如何做到这一点的一种方式。这比我想象的要容易。

代码基本上与一些变化一样,here is updated fiddler sample

<!DOCTYPE html> 
<html> 
<head> 
<title>JS plumb test</title> 
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script> 
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"></script> 
    <script type="text/javascript" src="./include/jquery.jsPlumb-1.3.16-all-min.js"></script> 

<style> 
    .window { 
     background-color: #EEEEEF; 
     border: 1px solid #346789; 
     border-radius: 0.5em; 
     box-shadow: 2px 2px 5px #AAAAAA; 
     color: black; 
     height: 5em; 
     position: absolute; 
     width: 5em; 
    } 

    .window:hover { 
     box-shadow: 2px 2px 19px #AAAAAA; 
     cursor: pointer; 
    } 


    .button_add, .button_add_window, .button_remove, .button { 
     background-color: deepskyblue; 
     text-align: center; 
     border: 1px solid; 
    } 

    .button_container { 
     margin: 5px; 
     background-color: #aaaaaa 
    } 
</style> 

<script> 

    jsPlumb.ready(function() { 


     //FIX DOM: 
     $(("#container1"))[0].innerHTML = $(("#container0"))[0].innerHTML; 

     //all windows are draggable 
     jsPlumb.draggable($(".window")); 


     var anEndpointSource = { 
      endpoint: "Rectangle", 
      isSource: true, 
      isTarget: false, 
      maxConnections: 1, 

      anchor: [1, 0, 1, 0] 
     }; 

     var anEndpointDestination = { 
      endpoint: "Dot", 
      isSource: false, 
      isTarget: true, 
      maxConnections: 1, 

      anchor: [0, 1, -1, 0] 
     }; 


     //Fixes endpoints for specified target 
     function fixEndpoints(parentnode) { 

      //get list of current endpoints 
      var endpoints = jsPlumb.getEndpoints(parentnode); 

      //there are 2 types - input and output 

      var inputAr = $.grep(endpoints, function (elementOfArray, indexInArray) { 
       return elementOfArray.isSource; //input 
      }); 

      var outputAr = $.grep(endpoints, function (elementOfArray, indexInArray) { 
       return elementOfArray.isTarget; //output 
      }); 

      calculateEndpoint(inputAr, true); 
      calculateEndpoint(outputAr, false); 

      jsPlumb.repaintEverything(); 
     } 

     //recalculate endpoint anchor position manually 
     function calculateEndpoint(endpointArray, isInput) { 

      //multiplyer 
      var mult = 1/(endpointArray.length+1); 

      for (var i = 0; i < endpointArray.length; i++) { 

       if (isInput) { 

        //position 
        endpointArray[i].anchor.x = 1; 
        endpointArray[i].anchor.y = mult * (i + 1); 
       } 
       else { 

        //position 
        endpointArray[i].anchor.x = 0; 
        endpointArray[i].anchor.y = mult * (i + 1); 
       } 
      } 
     } 



     //Add additional anchor 
     $(".button_add").live("click", function() { 

      var parentnode = $(this)[0].parentNode.parentNode; 

      jsPlumb.addEndpoint(
       parentnode, 
       anEndpointSource 
      ); 

      jsPlumb.addEndpoint(
       parentnode, 
       anEndpointDestination 
      ); 

      fixEndpoints(parentnode); 
     }); 

     //Remove anchor 
     $(".button_remove").live("click", function() { 

      var parentnode = $(this)[0].parentNode.parentNode; 

      //get list of current endpoints 
      var endpoints = jsPlumb.getEndpoints(parentnode); 

      //remove 2 last one 

      if (endpoints.length > 1) { 
       jsPlumb.deleteEndpoint(endpoints[endpoints.length - 2]); 
      } 

      if (endpoints.length > 0) { 
       jsPlumb.deleteEndpoint(endpoints[endpoints.length - 1]); 
      } 

      fixEndpoints(parentnode); 
     }); 


     //adds new window 
     $(".button_add_window").click(function() { 

      var id = "dynamic_" + $(".window").length; 

      //create new window and add it to the body 
      $('<div class="window" id="' + id + '" >').appendTo('body').html($(("#container0"))[0].innerHTML); 

      //set jsplumb properties 
      jsPlumb.draggable($('#' + id)); 
     }); 
    }); 
</script> 

</head> 
<body > 

    <!-- Adds new windows to the page --> 
    <div class="window" style="left: 600px" id="details"> 
     <p style="text-align: center">Window</p> 
     <div class="button_container"> 
      <div class="button_add_window">Add</div> 
     </div> 
    </div> 

    <!-- Primary window - used as html templated for descendants --> 
    <div class="window" style="left: 20px" id="container0"> 
     <div class="button_container"> 
      <div class="button_add">Add</div> 
      <div class="button_remove">Remove</div> 
     </div> 
    </div> 

    <div class="window" style="left: 200px" id="container1"> 
    </div> 


</body> 
</html> 

变化,我提出:

  1. 现在我指定端点锚偏移,当我添加它,我只计算支撑点位,所以偏移从未改变,从一开始总是正确的:

    var anEndpointSource = { 
        endpoint: "Rectangle", 
        isSource: true, 
        isTarget: false, 
        maxConnections: 1, 
    
        anchor: [1, 0, 1, 0] 
    }; 
    
  2. 一旦端点补充的是,我重新计算锚位置和呼叫(这将重绘连接):

    jsPlumb.repaintEverything();

下面是最终的结果:

endpoints correctly connected

+0

很好:)有没有办法“删除”(选择)节点呢?我将创建一个状态机编辑器w/jsplumb,但只是在动态地添加/删除节点和连接而挣扎。一个jsfiddle将是如此之大:) – Dominik 2013-06-27 08:22:48

0

你可通过双击删除状态通过添加

     newState.dblclick(function(e) { 
         alert("This will delete the state and its connections"); 
         instance.detachAllConnections($(this)); 
         $(this).remove(); 
         e.stopPropagation(); 
        }); 

函数为您的jsPlumb.ready函数。您可以通过添加

var windows = jsPlumb.getSelector(".statemachine-demo .state"); 
      windows.dblclick(function(e) { 
      alert("This will delete the state and its connections"); 
      instance.detachAllConnections($(this)); 
      $(this).remove(); 
      e.stopPropagation(); 
     }); 

这里的statemachine-演示添加到您的所有状态是DIV的ID在你contaner和国家是阶级国家的div。

0

感谢您的解决方案,它在锚点端被预定义时正常工作,就像这里源始终位于左侧,目标始终位于右侧。

但是,如果它们是动态的,我们还需要自己实现边选择?

作为一个解决方法,我所做的是在默认配置中设置更多可能的锚点位置。有什么更好的想法

谢谢