2012-12-18 3 views
7

Używam wtyczki JSTreegraph do rysowania struktury drzewa. Ale teraz potrzebuję funkcji przeciągania, upuszczania i dołączania, w której mogę przeciągnąć dowolny węzeł drzewa i dołączyć do dowolnego innego węzła, a następnie wszystkie dzieci pierwszego węzła będą teraz grand-dziećmi nowego węzła (do którego jest dołączone).Zastosuj funkcję przeciągnij i upuść/dołącz do JSTreegraf używając Jquery draggable

O ile mi wiadomo, ta wtyczka nie ma tej funkcji. Po prostu rysuje strukturę na podstawie przekazanego do niej obiektu danych.

Wtyczka zasadniczo przypisuje klasę Node do wszystkich węzłów (div) drzewa i innej klasy NodeHover do węzła po najechaniu kursorem. Nr id jest przypisany do tych elementów div.

Tak próbowałem przy użyciu jQuery Draggable tylko zobaczyć, czy któryś z węzła mogą być przenoszone przez robić to

$('.Node').draggable(); 
$('.NodeHover').draggable(); 

Ale to nie robi wydaje się działać. Czy ktoś może mi w tym pomóc?

Jak mogę uzyskać funkcję przeciągania i dołączania?

* EDIT :: pardon nie jestem tak wielki z użyciem Fiddle, więc dzielę przykładowy kod tutaj do użytku: *

plik HTML: który opracuje drzewo próbki

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
    <link href="css/JSTreeGraph.css" rel="stylesheet" type="text/css" /> 
    <script src="js/JSTreeGraph.js" type="text/javascript"></script> 
    <script src="js/jquery-1.7.1.min.js" type="text/javascript"></script> 
    <script src="js/jquery.ui.position.js" type="text/javascript"></script> 
    <style type="text/css"> 
    .Container { 
     position: absolute; 
     top: 100px; 
     left: 50px; 
     id: Container; 
    } 


</style> 
</head> 
<body> 
    <div id="tree"> 
     Ctrl+Click to Add Node 
     <br /> 
     Double Click to Expand or Collapse 
     <br /> 
     Shift+Click to Delete Node 
     <br /> 
     <select id="dlLayout" onchange="ChangeLayout()"> 
      <option value="Horizontal"> 
       Horizontal 
      </option> 
      <option value="Vertical" selected> 
       Vertical 
      </option> 
     </select> 
     <div class="Container" id="dvTreeContainer"></div> 


     <script type="text/javascript"> 

    var selectedNode; 
    // Root node 
    var rootNode = { Content: "Onida", Nodes:[] }; 

    // First Level 
    rootNode.Nodes[0] = { Content: "Employee Code", navigationType: "0"}; 
    rootNode.Nodes[1] = { Content: "Problem Area", navigationType: "1" }; 

    // Second Level 
    rootNode.Nodes[1].Nodes = [{ Content : "ACC-HO", Collapsed: true /* This node renders collapsed */ }, 
           { Content : "ACC-SALES" }, 
           { Content : "BUSI. HEAD", /*This node looks different*/ ToolTip: "Click ME!" }, 
           { Content : "CEO"}, 
           { Content : "HO-ADMIN"}, 
           { Content : "HO-FACTORY"}, 
           { Content : "SALES"}]; 

    // Third Level 
    rootNode.Nodes[1].Nodes[0].Nodes = [{ Content: "Billing" }, 
             { Content: "Credit Limit" }, 
             { Content: "Reconciliation" }]; 

    rootNode.Nodes[1].Nodes[1].Nodes = [{ Content: "Billing" }, 
             { Content: "Others" }]; 

    rootNode.Nodes[1].Nodes[2].Nodes = [{ Content: "AC" }, 
             { Content: "CTV" }, 
             { Content: "DVD" }, 
             { Content: "Washing Machine" }]; 

    rootNode.Nodes[1].Nodes[6].Nodes = [{ Content: "Appointments" }, 
             { Content: "Resignations" }, 
             { Content: "Others" }]; 

    // Draw the tree for the first time 
    RefreshTree(); 


    function RefreshTree() { 
     DrawTree({ Container: document.getElementById("dvTreeContainer"), 
        RootNode: rootNode, 
        Layout: document.getElementById("dlLayout").value, 
        OnNodeClickFirefox: NodeClickFF, 
        OnNodeClickIE: NodeClickIE, 
        OnNodeDoubleClick: NodeDoubleClick 
        }); 
    } 

    //function 
    function NodeClickFF(e) { 
     if (e.shiftKey){ 
      // Delete Node 
      if (!this.Node.Collapsed) { 
       for(var index=0; index<this.Node.ParentNode.Nodes.length; index++) { 
        if(this.Node.ParentNode.Nodes[index].Content == this.Node.Content) { 
         this.Node.ParentNode.Nodes.splice(index, 1); 
         break; 
        } 
       } 
       RefreshTree(); 
      } 
       // return false; 
     } 
     else if (e.ctrlKey) { 
      // Add new Child if Expanded      
      if (!this.Node.Collapsed) { 
       if (!this.Node.Nodes) this.Node.Nodes = new Array(); 
       var newNodeIndex = this.Node.Nodes.length; 
       this.Node.Nodes[newNodeIndex] = new Object(); 
       this.Node.Nodes[newNodeIndex].Content = this.Node.Content + "." + (newNodeIndex + 1); 
       RefreshTree(); 
      } 
       // return false; 
     } 
     else{ 
      fnNodeProperties(this.Node); 
     } 
    } 

    function NodeClickIE() { 
     if (typeof(event) == "undefined" && event.ctrlKey) { 
      // Add new Child if Expanded 
      if (!this.Node.Collapsed) { 
       if (!this.Node.Nodes) this.Node.Nodes = new Array(); 
       var newNodeIndex = this.Node.Nodes.length; 
       this.Node.Nodes[newNodeIndex] = new Object(); 
       this.Node.Nodes[newNodeIndex].Content = this.Node.Content + "." + (newNodeIndex + 1); 
       RefreshTree(); 
      } 
     } 
     else if (typeof(event) == "undefined" && event.shiftKey) { 
      // Delete Node 
      if (!this.Node.Collapsed) { 
       for(var index=0; index<this.Node.ParentNode.Nodes.length; index++) { 
        if(this.Node.ParentNode.Nodes[index].Content == this.Node.Content) { 
         this.Node.ParentNode.Nodes.splice(index, 1); 
         break; 
        } 
       } 
       RefreshTree(); 
      } 
     } 
     else{ 
      fnNodeProperties(this.Node); 
     } 
    }   

    function NodeDoubleClick() { 
     if (this.Node.Nodes && this.Node.Nodes.length > 0) { // If has children 
      this.Node.Collapsed = !this.Node.Collapsed; 
      RefreshTree(); 
     } 
    } 

    function ChangeLayout() { 

     RefreshTree(); 
    } 

</script> 
    </div> 
</body> 
</html> 

JSTreeGraph JS plik: plik wtyczki js

function DrawTree(options) { 

// Prepare Nodes 
PrepareNode(options.RootNode); 

// Calculate Boxes Positions 
if (options.Layout == "Vertical") { 
    PerformLayoutV(options.RootNode); 
} else { 
    PerformLayoutH(options.RootNode); 
} 

// Draw Boxes 
options.Container.innerHTML = ""; 
DrawNode(options.RootNode, options.Container, options); 

// Draw Lines 
DrawLines(options.RootNode, options.Container); 
} 

function DrawLines(node, container) { 
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // Has children and Is Expanded 
    for (var j = 0; j < node.Nodes.length; j++) { 
     if(node.ChildrenConnectorPoint.Layout=="Vertical") 
      DrawLineV(container, node.ChildrenConnectorPoint, node.Nodes[j].ParentConnectorPoint); 
     else 
      DrawLineH(container, node.ChildrenConnectorPoint, node.Nodes[j].ParentConnectorPoint); 

     // Children 
     DrawLines(node.Nodes[j], container); 
    } 
} 
} 

function DrawLineH(container, startPoint, endPoint) { 
    var midY = (startPoint.Y + ((endPoint.Y - startPoint.Y)/2)); // Half path between start en end Y point 

    // Start segment 
    DrawLineSegment(container, startPoint.X, startPoint.Y, startPoint.X, midY, 1); 

    // Intermidiate segment 
    var imsStartX = startPoint.X < endPoint.X ? startPoint.X : endPoint.X; // The lower value will be the starting point 
    var imsEndX = startPoint.X > endPoint.X ? startPoint.X : endPoint.X; // The higher value will be the ending point 
    DrawLineSegment(container, imsStartX, midY, imsEndX, midY, 1); 

    // End segment 
    DrawLineSegment(container, endPoint.X, midY, endPoint.X, endPoint.Y, 1); 
} 

    function DrawLineV(container, startPoint, endPoint) { 
var midX = (startPoint.X + ((endPoint.X - startPoint.X)/2)); // Half path between start en end X point 

// Start segment 
DrawLineSegment(container, startPoint.X, startPoint.Y, midX, startPoint.Y, 1); 

// Intermidiate segment 
var imsStartY = startPoint.Y < endPoint.Y ? startPoint.Y : endPoint.Y; // The lower value will be the starting point 
var imsEndY = startPoint.Y > endPoint.Y ? startPoint.Y : endPoint.Y; // The higher value will be the ending point 
DrawLineSegment(container, midX, imsStartY, midX, imsEndY, 1); 

// End segment 
DrawLineSegment(container, midX, endPoint.Y, endPoint.X, endPoint.Y, 1); 
} 

function DrawLineSegment(container, startX, startY, endX, endY, lineWidth) { 

var lineDiv = document.createElement("div"); 
lineDiv.style.top = startY + "px"; 
lineDiv.style.left = startX + "px"; 

if (startX == endX) { // Vertical Line 
    lineDiv.style.width = lineWidth + "px"; 
    lineDiv.style.height = (endY - startY) + "px"; 
} 
else{ // Horizontal Line 
    lineDiv.style.width = (endX - startX) + "px"; 
    lineDiv.style.height = lineWidth + "px"; 
} 

lineDiv.className = "NodeLine"; 
container.appendChild(lineDiv); 
} 

function DrawNode(node, container, options) { 
var nodeDiv = document.createElement("div"); 
nodeDiv.style.top = node.Top + "px"; 
nodeDiv.style.left = node.Left + "px"; 
nodeDiv.style.width = node.Width + "px"; 
nodeDiv.style.height = node.Height + "px"; 

if (node.Collapsed) { 
    nodeDiv.className = "NodeCollapsed"; 
} else { 
    nodeDiv.className = "Node"; 
} 

if (node.Class) 
    nodeDiv.className = node.Class; 

if (node.Content) 
    nodeDiv.innerHTML = "<div class='NodeContent'>" + node.Content + "</div>"; 

if (node.ToolTip) 
    nodeDiv.setAttribute("title", node.ToolTip); 

nodeDiv.Node = node; 

// Events 
if (options.OnNodeClickIE){ 
    //alert('OnNodeClick'); 
    nodeDiv.onclick = options.OnNodeClickIE;   
} 
// Events 
if (options.OnNodeClickFirefox){ 
    //alert('OnNodeClick'); 
    nodeDiv.onmousedown = options.OnNodeClickFirefox;   
} 
//on right click 
if (options.OnContextMenu){ 
     //alert('OnContextMenu'); 
     nodeDiv.oncontextmenu = options.OnContextMenu; 
    } 

if (options.OnNodeDoubleClick) 
    nodeDiv.ondblclick = options.OnNodeDoubleClick; 

nodeDiv.onmouseover = function() { // In 
    this.PrevClassName = this.className; 
    this.className = "NodeHover"; 
}; 

nodeDiv.onmouseout = function() { // Out 
    if (this.PrevClassName) { 
     this.className = this.PrevClassName; 
     this.PrevClassName = null; 
    } 
}; 

container.appendChild(nodeDiv); 

// Draw children 
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // Has Children and is Expanded 
    for (var i = 0; i < node.Nodes.length; i++) { 
     DrawNode(node.Nodes[i], container, options); 
    } 
} 
} 

function PerformLayoutV(node) { 

var nodeHeight = 30; 
var nodeWidth = 100; 
var nodeMarginLeft = 40; 
var nodeMarginTop = 20; 

var nodeTop = 0; // defaultValue 

// Before Layout this Node, Layout its children 
if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { 
    for (var i = 0; i < node.Nodes.length; i++) { 
     PerformLayoutV(node.Nodes[i]); 
    } 
} 

if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // If Has Children and Is Expanded 

    // My Top is in the center of my children 
    var childrenHeight = (node.Nodes[node.Nodes.length - 1].Top + node.Nodes[node.Nodes.length - 1].Height) - node.Nodes[0].Top; 
    nodeTop = (node.Nodes[0].Top + (childrenHeight/2)) - (nodeHeight/2); 

    // Is my top over my previous sibling? 
    // Move it to the bottom 
    if (node.LeftNode && ((node.LeftNode.Top + node.LeftNode.Height + nodeMarginTop) > nodeTop)) { 
     var newTop = node.LeftNode.Top + node.LeftNode.Height + nodeMarginTop; 
     var diff = newTop - nodeTop; 
     /// Move also my children 
     MoveBottom(node.Nodes, diff); 
     nodeTop = newTop; 
    } 

} else { 
    // My top is next to my top sibling 
    if (node.LeftNode) 
     nodeTop = node.LeftNode.Top + node.LeftNode.Height + nodeMarginTop; 
} 

node.Top = nodeTop; 

// The Left depends only on the level 
node.Left = (nodeMarginLeft * (node.Level + 1)) + (nodeWidth * (node.Level + 1)); 
// Size is constant 
node.Height = nodeHeight; 
node.Width = nodeWidth; 

// Calculate Connector Points 
// Child: Where the lines get out from to connect this node with its children 
var pointX = node.Left + nodeWidth; 
var pointY = nodeTop + (nodeHeight/2); 
node.ChildrenConnectorPoint = { X: pointX, Y: pointY, Layout: "Vertical" }; 
// Parent: Where the line that connect this node with its parent end 
pointX = node.Left; 
pointY = nodeTop + (nodeHeight/2); 
node.ParentConnectorPoint = { X: pointX, Y: pointY, Layout: "Vertical" }; 
} 

function PerformLayoutH(node) { 

var nodeHeight = 30; 
var nodeWidth = 100; 
var nodeMarginLeft = 20; 
var nodeMarginTop = 50; 

var nodeLeft = 0; // defaultValue 

// Before Layout this Node, Layout its children 
if ((!node.Collapsed) && node.Nodes && node.Nodes.length>0) { 
    for (var i = 0; i < node.Nodes.length; i++) { 
     PerformLayoutH(node.Nodes[i]); 
    } 
} 

if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // If Has Children and Is Expanded 

    // My left is in the center of my children 
    var childrenWidth = (node.Nodes[node.Nodes.length-1].Left + node.Nodes[node.Nodes.length-1].Width) - node.Nodes[0].Left; 
    nodeLeft = (node.Nodes[0].Left + (childrenWidth/2)) - (nodeWidth/2); 

    // Is my left over my left node? 
    // Move it to the right 
    if(node.LeftNode&&((node.LeftNode.Left+node.LeftNode.Width+nodeMarginLeft)>nodeLeft)) { 
     var newLeft = node.LeftNode.Left + node.LeftNode.Width + nodeMarginLeft; 
     var diff = newLeft - nodeLeft; 
     /// Move also my children 
     MoveRigth(node.Nodes, diff); 
     nodeLeft = newLeft; 
    } 
} else { 
    // My left is next to my left sibling 
    if (node.LeftNode) 
     nodeLeft = node.LeftNode.Left + node.LeftNode.Width + nodeMarginLeft; 
} 

node.Left = nodeLeft; 

// The top depends only on the level 
node.Top = (nodeMarginTop * (node.Level + 1)) + (nodeHeight * (node.Level + 1)); 
// Size is constant 
node.Height = nodeHeight; 
node.Width = nodeWidth; 

// Calculate Connector Points 
// Child: Where the lines get out from to connect this node with its children 
var pointX = nodeLeft + (nodeWidth/2); 
var pointY = node.Top + nodeHeight; 
node.ChildrenConnectorPoint = { X: pointX, Y: pointY, Layout:"Horizontal" }; 
// Parent: Where the line that connect this node with its parent end 
pointX = nodeLeft + (nodeWidth/2); 
pointY = node.Top; 
node.ParentConnectorPoint = { X: pointX, Y: pointY, Layout: "Horizontal" }; 
} 

function MoveRigth(nodes, distance) { 
for (var i = 0; i < nodes.length; i++) { 
    nodes[i].Left += distance; 
    if (nodes[i].ParentConnectorPoint) nodes[i].ParentConnectorPoint.X += distance; 
    if (nodes[i].ChildrenConnectorPoint) nodes[i].ChildrenConnectorPoint.X += distance; 
    if (nodes[i].Nodes) { 
     MoveRigth(nodes[i].Nodes, distance); 
    } 
} 
} 

function MoveBottom(nodes, distance) { 
for (var i = 0; i < nodes.length; i++) { 
    nodes[i].Top += distance; 
    if (nodes[i].ParentConnectorPoint) nodes[i].ParentConnectorPoint.Y += distance; 
    if (nodes[i].ChildrenConnectorPoint) nodes[i].ChildrenConnectorPoint.Y += distance; 
    if (nodes[i].Nodes) { 
     MoveBottom(nodes[i].Nodes, distance); 
    } 
} 
} 

function PrepareNode(node, level, parentNode, leftNode, rightLimits) { 

if (level == undefined) level = 0; 
if (parentNode == undefined) parentNode = null; 
if (leftNode == undefined) leftNode = null; 
if (rightLimits == undefined) rightLimits = new Array(); 

node.Level = level; 
node.ParentNode = parentNode; 
node.LeftNode = leftNode; 

if ((!node.Collapsed) && node.Nodes && node.Nodes.length > 0) { // Has children and is expanded 
    for (var i = 0; i < node.Nodes.length; i++) { 
     var left = null; 
     if (i == 0 && rightLimits[level]!=undefined) left = rightLimits[level]; 
     if (i > 0) left = node.Nodes[i - 1]; 
     if (i == (node.Nodes.length-1)) rightLimits[level] = node.Nodes[i]; 
     PrepareNode(node.Nodes[i], level + 1, node, left, rightLimits); 
    } 
} 
} 

JSTreeGraph plik CSS:

.NodeContent 
{ 
font-family:Verdana; 
font-size:small; 
} 

.Node 
{ 
position:absolute; 
background-color: #CCDAFF; 
border: 1px solid #5280FF; 
text-align:center; 
vertical-align:middle; 
cursor:pointer; 
overflow:hidden; 
} 

.NodeHover 
{ 
position:absolute; 
background-color: #8FADFF; 
border: 1px solid #5280FF; 
text-align:center; 
vertical-align:middle; 
cursor:pointer; 
overflow:hidden; 
} 

.NodeCollapsed 
{ 
position:absolute; 
background-color: #8FADFF; 
border: 2px solid black; 
text-align:center; 
vertical-align:middle; 
cursor:pointer; 
overflow:hidden; 
} 


.NodeLine 
{ 
background-color: #000066; 
position:absolute; 
overflow:hidden; 
} 
+0

O dziwo, to najdłużej muszę czekać na odpowiedź tutaj :) – DarkKnightFan

+2

Jeśli zapewnimy skrzypce, ludzie mogą być bardziej zaangażowani, aby zagłębić się i spróbować znaleźć rozwiązanie. –

Odpowiedz

2

Przypuszczam, że to, co potrzebne jest do utwierdzi mechanizm do modyfikowania drzewo struktury logicznej na przeciąganie a następnie załaduj cały elementu drzewa. W ten sposób wtyczka wyrenderuje twoją nową zmodyfikowaną strukturę.

0

To nie jest łatwy problem i nie podano dokładnych specyfikacji.

  • Gdy przenosisz węzeł, czy wszystkie węzły podrzędne powinny się nim poruszać?
  • Co dzieje się z węzłem i jego elementami podrzędnymi, gdy węzeł jest upuszczany/dołączany?

Wtyczka, z której korzystasz, działa dobrze podczas rysowania statycznych drzew, ale nie jest napisana w taki sposób, aby umożliwić dynamiczną edycję drzewa.

Muszę zgodzić się z @Bardo w tym, że najłatwiejszym sposobem, aby to działało zgodnie z twoimi potrzebami, jest zrozumienie, w jaki sposób drzewo zostało zmanipulowane. (Na szczęście wtyczka wydaje się zapewniać opcję onNodeClick, która pozwoli ci zrozumieć, który węzeł zamierzasz manipulować). Kiedy drzewo zostanie zmanipulowane, musi zostać całkowicie przerysowane. (Nie wydaje się być dobrym sposobem na częściowe narysowanie drzewa).

+0

Cóż, odpowiedziałem na oba pytania w opisie problemu. JEŻELI węzeł zostanie przeniesiony i przyłączony do innego węzła, dzieci pierwszego z nich staną się grand-dziećmi tego ostatniego, tj. Elementy potomne również powinny zostać przeniesione. Przechwytywam zdarzenie 'onNodeClick' i robię na nim wiele akcji. Ale zakładam, że moglibyśmy użyć 'przeciągalnego' narzędzia Jquery na węzłach drzewa (po tym wszystkim są również znaczniki 'div'). Ale jak wspomniałem w moim opisie, przeciąganie nie działa na nich. – DarkKnightFan

Powiązane problemy