2012-12-18 8 views
7

Sto utilizzando il plug-in JSTreegraph per disegnare una struttura ad albero. Ma ora ho bisogno di una funzione di trascinamento, rilascio e rilascio in cui posso trascinare qualsiasi nodo dell'albero e collegarlo a qualsiasi altro nodo e successivamente tutti i figli del primo nodo saranno ora i nipotini del nuovo nodo (a cui è allegato).Applicare la funzionalità di trascinamento/rilascio su JSTreegraph utilizzando Jquery trascinabile

Per quanto ne so, questo plug-in non sembra avere questa funzionalità. Disegna semplicemente la struttura in base all'oggetto di dati passato ad esso.

Il plugin assegna fondamentalmente una classe Node a tutti i nodi (divs) dell'albero e un'altra classe NodeHover a un nodo su passaggio del mouse. No id è assegnato a questi div.

Così ho provato ad utilizzare JQuery Draggable solo per vedere se qualcuno di nodo può essere spostato in questo modo

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

ma doesnt sembrano funzionare. Quindi qualcuno può aiutarmi con questo.

Come è possibile ottenere funzionalità di trascinamento e collegamento?

* EDIT :: Pardon me sono non così grande con l'utilizzo del violino, quindi sono la condivisione di un codice di esempio qui a vostra disposizione: *

file HTML: che attirerà l'albero campione

<!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 di file: file plugin 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 file 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

Sorprendentemente questo è il più lungo che devo aspettare per una risposta qui :) – DarkKnightFan

+2

Se fornisci un violino le persone potrebbero essere più impegnate a scavare e provare a trovare una soluzione per questo. –

risposta

2

ho supose che ciò che è necessario è quello di stablish un meccanismo per modificare la struttura logica albero a trascinare e quindi ricaricare l'intero elemento albero. In questo modo il plugin renderà la tua nuova struttura modificata.

0

Questo non è un problema facile e non hai delineato le specifiche esatte.

  • Quando si sposta un nodo, tutti i nodi figlio dovrebbero spostarsi con esso?
  • Cosa succede a un nodo e ai suoi elementi figli quando un nodo viene rilasciato/collegato?

Il plug-in che si sta utilizzando funziona bene per disegnare alberi statici, ma non è scritto in modo tale da consentire la modifica dinamica dell'albero.

Devo concordare con @Bardo nel fatto che il modo più semplice per farlo funzionare per le proprie esigenze è capire come l'albero è stato manipolato. (Fortunatamente il plugin sembra fornire un'opzione onNodeClick che ti consentirà di capire quale nodo si intende manipolare). Una volta che l'albero è stato manipolato, deve essere completamente ridisegnato. (Non sembra essere un buon modo per disegnare parzialmente un albero).

+0

Bene, ho risposto a entrambe le vostre domande nella descrizione del mio problema. Se un nodo viene spostato e collegato a un altro nodo, i figli del primo diventano i nipotini di quest'ultimo, quindi gli elementi figlio devono essere spostati. Sto catturando l'evento 'onNodeClick' e sto facendo molte azioni su di esso. Ma suppongo che potremmo usare l'utility 'draggable' di Jquery sui nodi dell'albero (dopotutto quelli sono anche tag' div'). Ma come ho accennato nella mia descrizione, sembra trascurabile lavorare su di loro. – DarkKnightFan

Problemi correlati