2013-03-04 150 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

感謝您的解決方案,它在錨點端被預定義時正常工作,就像這裏源始終位於左側,目標始終位於右側。

但是,如果它們是動態的,我們還需要自己實現邊選擇?

作爲一個解決方法,我所做的是在默認配置中設置更多可能的錨點位置。有什麼更好的想法

謝謝