2016-01-20 2 views
1

Я создаю дерево и пытаюсь добавить метки для краев. В тех же узлах дерева можно добавлять «на лету» с помощью кнопки «плюс», которая появляется при нажатии на родительский узел. Проблема возникает, когда я добавляю нового ребенка.Вставить многократное время в d3 js tree

(извините за длинный код, не может сделать меньше рабочий пример - комментировал код для целей простого анализа)

Проблем

Когда я проверил DOM я могу видеть что элемент text с классом text-link был добавлен в элемент g с классом edge-container несколько раз. (ознакомьтесь с фрагментом кода). Предоставленная разметка - это что-то вроде этого. (только с указанием соответствующей части)

<g class="edge-container"> 
<path class="link" id="rightlink1-2" d="M0,230C90,230 90,76.66666666666667 180,76.66666666666667"></path> 
<text class="text-link" x="135" y="230" text-anchor="start" style="font-size: 14px;">test-label</text> 
</g> 

<g class="edge-container"> 
<path class="link" id="rightlink1-3" d="M0,230C90,230 90,230 180,230"></path> 
<text class="text-link" x="135" y="172.5" text-anchor="start" style="font-size: 14px;">test-label</text> 
<text class="text-link" x="135" y="287.5" text-anchor="start" style="font-size: 14px;">test-label</text> 
</g> 
<g class="edge-container"> 
<path class="link" id="rightlink1-4" d="M0,230C90,230 90,383.33333333333337 180,383.33333333333337"></path> 
<text class="text-link" x="135" y="153.33333333333334" text-anchor="start" style="font-size: 14px;">test-label</text> 
<text class="text-link" x="135" y="230" text-anchor="start" style="font-size: 14px;">test-label</text> 
<text class="text-link" x="135" y="306.6666666666667" text-anchor="start" style="font-size: 14px;">test-label</text> 
</g> 

Что я делаю неправильно?

Это для каждого добавления нового узла, все предыдущие метки также привязаны к вновь созданному edge-container.

Какие изменения должны быть внесены в код, который для каждого ребра добавляется только к соответствующему text-link внутри родительского элемента g.

Операция

Нажмите на узел так, чтобы добавить появится кнопка, нажмите на кнопку Добавить, чтобы добавить дочерний узел. (Пожалуйста, смотрите фрагмент кода на весь экран для простоты использования)

var treeData = [{ 
 
    "name": "Device", 
 
    "parent": "null" 
 
    } 
 

 
]; 
 
var treeData2 = [{ 
 
    "name": "Device", 
 
    "parent": "null" 
 
    } 
 

 
]; 
 

 
$(document).ready(function($) { 
 

 

 

 
    var margin = { 
 
     top: 20, 
 
     right: 120, 
 
     bottom: 20, 
 
     left: 120 
 
    }, 
 
    width = 2260 - margin.right - margin.left, 
 
    height = 500 - margin.top - margin.bottom; 
 

 
    var svg = d3.select('.doubletree-container').append("svg") 
 
    .attr("width", width + margin.right + margin.left) 
 
    .attr("height", height + margin.top + margin.bottom); 
 

 

 
    $.fn.makeDoubleTree = function() { 
 

 
    this.makeRightTree(); 
 
    this.makeLeftTree(); 
 

 
    }; 
 

 

 
}(jQuery)); 
 

 

 
$.fn.makeRightTree = function() { 
 
    // ************** Generate the tree diagram ***************** 
 
    var margin = { 
 
     top: 20, 
 
     right: 120, 
 
     bottom: 20, 
 
     left: 120 
 
    }, 
 
    width = 1260 - margin.right - margin.left, 
 
    height = 500 - margin.top - margin.bottom; 
 

 
    var i = 0, 
 
    duration = 750, 
 
    root; 
 

 
    var tree = d3.layout.tree() 
 
    .size([height, width]); 
 

 
    var diagonal = d3.svg.diagonal() 
 
    .projection(function(d) { 
 
     return [d.y, d.x]; 
 
    }); 
 

 

 

 
    var svg = d3.select("svg").append("g") 
 
    .attr("class", "right-tree-container") 
 
    .attr("transform", "translate(600,0)"); 
 
    svg.append("g").attr("id", "right-edges") 
 

 

 
    root = treeData[0]; 
 
    oldrx = root.x0 = height/2; 
 
    oldry = root.y0 = 0; 
 

 
    update(root); 
 

 

 

 
    function update(source) { 
 

 
    // Compute the new tree layout. 
 
    var nodes = tree.nodes(root).reverse(), 
 
     links = tree.links(nodes); 
 

 
    // Normalize for fixed-depth. 
 
    nodes.forEach(function(d) { 
 
     d.y = d.depth * 180; 
 
    }); 
 

 
    // Update the nodes… 
 
    var node = svg.selectAll("g.node") 
 
     .data(nodes, function(d) { 
 
     return d.id || (d.id = ++i); 
 
     }); 
 

 
    // Enter any new nodes at the parent's previous position. 
 
    var nodeEnter = node.enter().append("g") 
 
     .attr("class", function(d) { 
 
     console.log(d); 
 
     if (d.parent == "null") { 
 

 
      if (d.children) 
 

 
      { 
 
      return "node rightparent collapsed" //since its root its parent is null 
 
      } else { 
 
      return "node rightparent" 
 
      } 
 

 
     } else { 
 
      if (d.children) { 
 
      return "node rightchild collapsed" //all nodes with parent will have this class 
 
      } else { 
 
      return "node rightchild" //all nodes with parent will have this class 
 
      } 
 
     } 
 

 
     }) 
 
     .attr("transform", function(d) { 
 
     return "translate(" + source.y0 + "," + source.x0 + ")"; 
 
     }) 
 
     .on("click", click); 
 

 
    nodeEnter.append("rect") 
 
     .attr("id", function(d) { 
 
     return "rightnode" + d.id; 
 
     }) 
 
     .attr("x", "-10") 
 
     .attr("y", "-15") 
 
     .attr("height", 30) 
 
     .attr("width", 100) 
 
     .attr("rx", 15) 
 
     .attr("ry", 15) 
 
     .style("fill", "#f1f1f1"); 
 

 
    nodeEnter.append("image") 
 
     .attr("xlink:href", "img.png") 
 
     .attr("x", "0") 
 
     .attr("y", "-10") 
 
     .attr("width", 16) 
 
     .attr("height", 16); 
 

 

 

 

 
    nodeEnter.append("text") 
 
     .attr("x", function(d) { 
 
     return d.children || d._children ? -13 : 13; 
 
     }) 
 
     .attr("dy", ".35em") 
 
     .attr("text-anchor", function(d) { 
 
     return d.children || d._children ? "end" : "start"; 
 
     }) 
 
     .text(function(d) { 
 
     return d.name; 
 
     }) 
 
     .style("fill-opacity", 1e-6); 
 

 

 

 

 
    var addRightChild = nodeEnter.append("g").attr("class", "addRightChild"); 
 
    addRightChild.append("rect") 
 
     .attr("x", "90") 
 
     .attr("y", "-10") 
 
     .attr("height", 20) 
 
     .attr("width", 20) 
 
     .attr("rx", 10) 
 
     .attr("ry", 10) 
 
     .style("stroke", "#444") 
 
     .style("stroke-width", "2") 
 
     .style("fill", "#ccc"); 
 

 
    addRightChild.append("line") 
 
     .attr("x1", 95) 
 
     .attr("y1", 1) 
 
     .attr("x2", 105) 
 
     .attr("y2", 1) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 
    addRightChild.append("line") 
 
     .attr("x1", 100) 
 
     .attr("y1", -4) 
 
     .attr("x2", 100) 
 
     .attr("y2", 6) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 

 

 
    // adding the right chevron 
 
    var rightChevron = nodeEnter.append("g").attr("class", "right-chevron"); 
 

 

 

 

 
    rightChevron.append("line") 
 
     .attr("x1", 75) 
 
     .attr("y1", -5) 
 
     .attr("x2", 80) 
 
     .attr("y2", 0) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 
    rightChevron.append("line") 
 
     .attr("x1", 80) 
 
     .attr("y1", 0) 
 
     .attr("x2", 75) 
 
     .attr("y2", 5) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 
    rightChevron.on("click", function(d) { 
 

 

 
    }); 
 

 

 

 

 
    // Transition nodes to their new position. 
 
    var nodeUpdate = node.transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { 
 
     if (d.parent == "null") { 
 
      d.y = oldry; 
 
      d.x = oldrx; 
 
     } 
 

 
     return "translate(" + d.y + "," + d.x + ")"; 
 
     }); 
 

 

 

 
    nodeUpdate.select("text") 
 
     .style("fill-opacity", 1); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    var nodeExit = node.exit().transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { 
 
     return "translate(" + source.y + "," + source.x + ")"; 
 
     }) 
 
     .remove(); 
 

 

 
    nodeExit.select("text") 
 
     .style("fill-opacity", 1e-6); 
 

 

 

 

 
    // Update the links… 
 

 
    /*************************************** 
 

 
    start of relevant code , where group edge-container edge is added 
 

 
     ************************/ 
 

 
    var edge = d3.select("#right-edges") 
 
     .append("g") 
 
     .attr("class", "edge-container") 
 
     .data(links); 
 

 
    var link = edge.selectAll("path.link") 
 
     .data(links, function(d) { 
 
     return d.target.id; 
 
     }); 
 

 

 

 

 
    // Enter any new links at the parent's previous position. 
 
    link.enter().insert("path", "edge-container") 
 
     .attr("class", "link") 
 
     .attr("id", function(d) { 
 
     return ("rightlink" + d.source.id + "-" + d.target.id) 
 
     }) 
 
     .attr("d", function(d) { 
 
     var o = { 
 
      x: source.x0, 
 
      y: source.y0 
 
     }; 
 

 
     return diagonal({ 
 
      source: o, 
 
      target: o 
 
     }); 
 
     }).on("click", removelink) 
 
     .on("mouseover", showRemoveButton) 
 
     .on("mouseout", hideRemoveButton); 
 

 
    function showRemoveButton() { 
 
     console.log("hover"); 
 
    } 
 

 
    function hideRemoveButton() { 
 
     console.log("hover-out"); 
 
    } 
 

 

 

 

 
    var text = edge.selectAll("text.text-link") 
 
     .data(links, function(d) { 
 
     return d.target.id + d.source.id; 
 
     }); 
 

 
    text.enter().insert("text", "edge-container") 
 
     .attr("class", "text-link") 
 

 
    .attr("x", function(d) { 
 
     var x = (d.source.y + d.target.y)/2 
 
     return parseInt(x + 45); 
 
     }) 
 
     .attr("y", function(d) { 
 
     var y = (d.source.x + d.target.x)/2 
 
     return y; 
 
     }) 
 
     .text("test-label") 
 
     .attr("text-anchor", "start") 
 
     .style("font-size", "14px"); 
 

 
    var link = edge.selectAll("path.link") 
 
     .data(links, function(d) { 
 
     return d.target.id; 
 
     }); 
 

 

 

 

 
    // Enter any new links at the parent's previous position. 
 
    link.enter().insert("path", "edge-container") 
 
     .attr("class", "link") 
 
     .attr("id", function(d) { 
 
     return ("rightlink" + d.source.id + "-" + d.target.id) 
 
     }) 
 
     .attr("d", function(d) { 
 
     var o = { 
 
      x: source.x0, 
 
      y: source.y0 
 
     }; 
 

 
     return diagonal({ 
 
      source: o, 
 
      target: o 
 
     }); 
 
     }).on("click", removelink) 
 
     .on("mouseover", showRemoveButton) 
 
     .on("mouseout", hideRemoveButton); 
 

 
    function showRemoveButton() { 
 
     console.log("hover"); 
 
    } 
 

 
    function hideRemoveButton() { 
 
     console.log("hover-out"); 
 
    } 
 

 

 

 

 
    /***** end of relevant code *******/ 
 

 

 
    function removelink(d) { 
 

 
     var confirmDelete = confirm("Are you sure you want to delete?"); 
 
     if (confirmDelete) { 
 
     //this is the links target node which you want to remove 
 
     var target = d.target; 
 
     //make new set of children 
 
     var children = []; 
 
     //iterate through the children 
 
     target.parent.children.forEach(function(child) { 
 
      if (child.id != target.id) { 
 
      //add to the child list if target id is not same 
 
      //so that the node target is removed. 
 
      children.push(child); 
 
      } 
 
     }); 
 
     //set the target parent with new set of children sans the one which is removed 
 
     target.parent.children = children; 
 
     //redraw the parent since one of its children is removed 
 
     update(d.target.parent) 
 
     } 
 

 

 

 
    } 
 

 
    var link = svg.selectAll("path.link") 
 
     .data(links, function(d) { 
 
     return d.target.id; 
 
     }); 
 

 
    // Transition links to their new position. 
 
    link.transition() 
 
     .duration(duration) 
 
     .attr("d", diagonal); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    link.exit().transition() 
 
     .duration(duration) 
 
     .attr("d", function(d) { 
 
     var o = { 
 
      x: source.x, 
 
      y: source.y 
 
     }; 
 
     return diagonal({ 
 
      source: o, 
 
      target: o 
 
     }); 
 
     }) 
 
     .remove(); 
 

 
    // Stash the old positions for transition. 
 
    nodes.forEach(function(d) { 
 
     d.x0 = d.x; 
 
     d.y0 = d.y; 
 
    }); 
 

 

 
    addRightChild.on("click", function(d) { 
 

 

 
     event.stopPropagation(); 
 
     $("#child-info").show(); 
 
     $("#child-text").val(""); 
 

 
     $("#btn-add-child").off('click'); 
 
     $("#btn-add-child").click(function() { 
 
     var childname = $("#child-text").val(); 
 

 

 
     if (typeof d._children === 'undefined' || d._children === null) { 
 
      if (typeof d.children === 'undefined') { 
 

 

 
      var newChild = [{ 
 
       "name": childname, 
 
       "parent": "Son Of A", 
 
      }]; 
 

 

 
      var newnodes = tree.nodes(newChild); 
 
      d.children = newnodes[0]; 
 
      // console.log(d.children); 
 
      update(d); 
 

 

 
      } else { 
 
      var newChild = { 
 
       "name": childname, 
 
       "parent": "Son Of A", 
 
      }; 
 
      // console.log(d.children); 
 
      d.children.push(newChild); 
 
      // console.log(d.children); 
 
      update(d); 
 
      } 
 
     } else { 
 
      var newChild = { 
 
      "name": childname, 
 
      "parent": "Son Of A", 
 
      }; 
 

 
      d.children = d._children; 
 
      d.children.push(newChild); 
 
      // console.log(d.children); 
 
      update(d); 
 

 

 
     } 
 

 

 
     $("#child-info").hide(); 
 
     }); 
 
    });; 
 
    } 
 

 
    // Toggle children on click. 
 
    function click(d) { 
 

 
    if (d.children) { 
 
     d._children = d.children; 
 
     d.children = null; 
 
    } else { 
 
     d.children = d._children; 
 
     d._children = null; 
 
    } 
 
    update(d); 
 

 
    $(".addLeftChild, .addRightChild").hide(); 
 
    if (d.id === 1) { 
 
     $(".rightparent").children(".addRightChild").show(); 
 
     $(this).children(".addRightChild").show(); 
 
    } else { 
 
     $(this).children(".addRightChild").show(); 
 

 
    } 
 
    d3.selectAll("rect").style("fill", "#f1f1f1"); //reset all node colors 
 
    d3.selectAll("path").style("stroke", "#85e0e0"); //reset the color for all links 
 
    while (d.parent) { 
 

 
     d3.select("#leftnode1").style("fill", "#F7CA18"); 
 
     d3.selectAll("#rightnode" + d.id).style("fill", "#F7CA18"); //color the node 
 
     if (d.parent != "null") 
 
     d3.selectAll("#rightlink" + d.parent.id + "-" + d.id).style("stroke", "#F7CA18"); //color the path 
 
     d = d.parent; 
 
    } 
 
    } 
 
} 
 

 

 
$.fn.makeLeftTree = function() { 
 
    // ************** Generate the tree diagram ***************** 
 
    var margin = { 
 
     top: 20, 
 
     right: 120, 
 
     bottom: 20, 
 
     left: 120 
 
    }, 
 
    width = 1260 - margin.right - margin.left, 
 
    height = 500 - margin.top - margin.bottom; 
 

 
    var i = 0, 
 
    duration = 750, 
 
    root; 
 

 
    var tree = d3.layout.tree() 
 
    .size([height, width]); 
 

 
    var diagonal = d3.svg.diagonal() 
 
    .projection(function(d) { 
 
     return [d.y, d.x]; 
 
    }); 
 

 
    var svg = d3.select("svg").append("g") 
 
    .attr("class", "left-tree-container") 
 
    .attr("transform", "translate(-421,0)"); 
 

 
    svg.append("g").attr("id", "left-edges") 
 

 
    root = treeData2[0]; 
 
    oldlx = root.x0 = height/2; 
 
    oldly = root.y0 = width; 
 

 
    update(root); 
 

 
    function update(source) { 
 

 
    // Compute the new tree layout. 
 
    var nodes = tree.nodes(root).reverse(), 
 
     links = tree.links(nodes); 
 

 
    // Normalize for fixed-depth. 
 
    nodes.forEach(function(d) { 
 
     d.y = width - (d.depth * 180); 
 
    }); 
 

 
    // Update the nodes… 
 
    var node = svg.selectAll("g.node") 
 
     .data(nodes, function(d) { 
 
     return d.id || (d.id = ++i); 
 
     }); 
 

 
    // Enter any new nodes at the parent's previous position. 
 
    var nodeEnter = node.enter().append("g") 
 
     .attr("class", function(d) { 
 
     if (d.parent == "null") { 
 
      return "node leftparent" //since its root its parent is null 
 
     } else 
 
      return "node leftchild" //all nodes with parent will have this class 
 
     }) 
 
     .attr("transform", function(d) { 
 
     return "translate(" + source.y0 + "," + source.x0 + ")"; 
 
     }) 
 
     .on("click", click); 
 

 
    nodeEnter.append("rect") 
 
     .attr("x", "-10") 
 
     .attr("id", function(d) { 
 
     return "leftnode" + d.id; 
 
     }) 
 
     .attr("y", "-15") 
 
     .attr("height", 30) 
 
     .attr("width", 100) 
 
     .attr("rx", 15) 
 
     .attr("ry", 15) 
 
     .style("fill", "#f1f1f1"); 
 

 
    nodeEnter.append("image") 
 
     .attr("xlink:href", "img.png") 
 
     .attr("x", "60") 
 
     .attr("y", "-10") 
 
     .attr("width", 16) 
 
     .attr("height", 16); 
 

 
    nodeEnter.append("text") 
 
     .attr("x", function(d) { 
 
     return d.children || d._children ? -13 : 13; 
 
     }) 
 
     .attr("dy", ".35em") 
 
     .attr("text-anchor", function(d) { 
 
     return d.children || d._children ? "end" : "start"; 
 
     }) 
 
     .text(function(d) { 
 
     return d.name; 
 
     }) 
 
     .style("fill-opacity", 1e-6); 
 

 
    var addLeftChild = nodeEnter.append("g").attr("class", "addLeftChild"); 
 
    addLeftChild.append("rect") 
 
     .attr("x", "-30") 
 
     .attr("y", "-10") 
 
     .attr("height", 20) 
 
     .attr("width", 20) 
 
     .attr("rx", 10) 
 
     .attr("ry", 10) 
 
     .style("stroke", "#444") 
 
     .style("stroke-width", "2") 
 
     .style("fill", "#ccc"); 
 

 
    addLeftChild.append("line") 
 
     .attr("x1", -25) 
 
     .attr("y1", 1) 
 
     .attr("x2", -15) 
 
     .attr("y2", 1) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 
    addLeftChild.append("line") 
 
     .attr("x1", -20) 
 
     .attr("y1", -4) 
 
     .attr("x2", -20) 
 
     .attr("y2", 6) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 

 
    var leftChevron = nodeEnter.append("g").attr("class", "left-chevron"); 
 

 
    leftChevron.append("line") 
 
     .attr("x1", 5) 
 
     .attr("y1", -5) 
 
     .attr("x2", 0) 
 
     .attr("y2", 0) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 
    leftChevron.append("line") 
 
     .attr("x1", 0) 
 
     .attr("y1", 0) 
 
     .attr("x2", 5) 
 
     .attr("y2", 5) 
 
     .attr("stroke", "#444") 
 
     .style("stroke-width", "2"); 
 

 

 

 

 
    // Transition nodes to their new position. 
 
    var nodeUpdate = node.transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { 
 
     if (d.parent == "null") { 
 
      d.y = oldly; 
 
      d.x = oldlx; 
 
     } 
 
     return "translate(" + d.y + "," + d.x + ")"; 
 
     }); 
 

 

 

 
    nodeUpdate.select("text") 
 
     .style("fill-opacity", 1); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    var nodeExit = node.exit().transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { 
 
     return "translate(" + source.y + "," + source.x + ")"; 
 
     }) 
 
     .remove(); 
 

 
    // nodeExit.select("circle") 
 
    //  .attr("r", 1e-6); 
 

 
    nodeExit.select("text") 
 
     .style("fill-opacity", 1e-6); 
 

 
    var edge = d3.select("#left-edges") 
 
     .append("g") 
 
     .attr("class", "edge-container") 
 
     .data(links); 
 

 

 
    d3.selectAll(".left-tree-container .text-link").remove(); 
 

 
    var text = edge.selectAll(".text-link") 
 
     .data(links, function(d) { 
 
     return d.target.id + d.source.id; 
 
     }); 
 

 
    text.enter().append("text") 
 
     .attr("class", "text-link") 
 

 
    .attr("x", function(d) { 
 
     var x = (d.source.y + d.target.y)/2 
 
     return parseInt(x + 45); 
 
     }) 
 
     .attr("y", function(d) { 
 
     var y = (d.source.x + d.target.x)/2 
 
     return y; 
 
     }) 
 
     .text("test-label") 
 
     .attr("text-anchor", "middle") 
 
     .style("font-size", "14px"); 
 

 
    var link = edge.selectAll("path.link") 
 
     .data(links, function(d) { 
 
     return d.target.id; 
 
     }); 
 

 
    // Update the links… 
 

 

 
    // Enter any new links at the parent's previous position. 
 
    link.enter().insert("path", "edge-container") 
 
     .attr("class", "link") 
 
     .attr("id", function(d) { 
 
     return ("leftlink" + d.source.id + "-" + d.target.id) 
 
     }) 
 
     .attr("d", function(d) { 
 
     var o = { 
 
      x: source.x0, 
 
      y: source.y0 
 
     }; 
 
     return diagonal({ 
 
      source: o, 
 
      target: o 
 
     }); 
 
     }).on("click", removelink); 
 

 
    function removelink(d) { 
 

 
     var confirmDelete = confirm("Are you sure you want to delete?"); 
 

 

 
     if (confirmDelete) { 
 

 
     //this is the links target node which you want to remove 
 
     var target = d.target; 
 
     //make new set of children 
 
     var children = []; 
 
     //iterate through the children 
 
     target.parent.children.forEach(function(child) { 
 
      if (child.id != target.id) { 
 
      //add to teh child list if target id is not same 
 
      //so that the node target is removed. 
 
      children.push(child); 
 
      } 
 
     }); 
 
     //set the target parent with new set of children sans the one which is removed 
 
     target.parent.children = children; 
 
     //redraw the parent since one of its children is removed 
 
     update(d.target.parent) 
 
     } 
 

 
    } 
 

 
    var link = svg.selectAll("path.link") 
 
     .data(links, function(d) { 
 
     return d.target.id; 
 
     }); 
 

 
    // Transition links to their new position. 
 
    link.transition() 
 
     .duration(duration) 
 
     .attr("d", diagonal); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    link.exit().transition() 
 
     .duration(duration) 
 
     .attr("d", function(d) { 
 
     var o = { 
 
      x: source.x, 
 
      y: source.y 
 
     }; 
 
     return diagonal({ 
 
      source: o, 
 
      target: o 
 
     }); 
 
     }) 
 
     .remove(); 
 

 
    // Stash the old positions for transition. 
 
    nodes.forEach(function(d) { 
 

 

 
     d.x0 = d.x; 
 
     d.y0 = d.y; 
 
    }); 
 

 

 
    addLeftChild.on("click", function(d) { 
 

 
     event.stopPropagation(); 
 
     $("#child-info").show(); 
 
     $("#child-text").val(""); 
 

 
     $("#btn-add-child").off('click'); 
 
     $("#btn-add-child").click(function() { 
 
     var childname = $("#child-text").val(); 
 

 
     if (typeof d._children === 'undefined' || d._children === null) { 
 
      if (typeof d.children === 'undefined') { 
 

 

 
      var newChild = [{ 
 
       "name": childname, 
 
       "parent": "Son Of A", 
 
      }]; 
 

 
      // console.log(tree.nodes(newChild[0])); 
 
      var newnodes = tree.nodes(newChild); 
 
      d.children = newnodes[0]; 
 
      // console.log(d.children); 
 
      update(d); 
 

 

 
      } else { 
 
      var newChild = { 
 
       "name": childname, 
 
       "parent": "Son Of A", 
 
      }; 
 
      // console.log(d.children); 
 
      d.children.push(newChild); 
 
      // console.log(d.children); 
 
      update(d); 
 
      } 
 
     } else { 
 
      var newChild = { 
 
      "name": childname, 
 
      "parent": "Son Of A", 
 
      }; 
 
      console.log("collapsed case"); 
 
      d.children = d._children; 
 
      d.children.push(newChild); 
 
      // console.log(d.children); 
 
      update(d); 
 

 

 
     } 
 

 

 
     $("#child-info").hide(); 
 
     }); 
 
    }); 
 
    } 
 

 
    // Toggle children on click. 
 
    function click(d) { 
 

 
    if (d.id !== 1) { 
 

 
     if (d.children) { 
 
     d._children = d.children; 
 
     d.children = null; 
 
     } else { 
 
     d.children = d._children; 
 
     d._children = null; 
 
     } 
 
     update(d); 
 
    } 
 

 

 
    $(".addLeftChild, .addRightChild").hide(); 
 
    if (d.id === 1) { 
 
     $(".rightparent").children(".addRightChild").show(); 
 
     $(this).children(".addLeftChild").show(); 
 
    } else { 
 
     $(this).children(".addLeftChild").show(); 
 

 
    } 
 

 

 
    d3.selectAll("rect").style("fill", "#f1f1f1"); //reset all node colors 
 
    d3.selectAll("path").style("stroke", "#85e0e0"); //reset the color for all links 
 
    while (d.parent) { 
 
     d3.selectAll("#leftnode" + d.id).style("fill", "#F7CA18"); //color the node 
 
     if (d.parent != "null") 
 
     d3.selectAll("#leftlink" + d.parent.id + "-" + d.id).style("stroke", "F7CA18"); //color the path 
 
     d = d.parent; 
 
    } 
 

 
    } 
 
}
body { 
 
    font-family: 'Roboto', sans-serif; 
 
    margin: 0; 
 
    padding: 0; 
 
} 
 
#child-info { 
 
    width: 100px; 
 
    height: 50px; 
 
    height: auto; 
 
    position: fixed; 
 
    padding: 10px; 
 
    display: none; 
 
    left: 40%; 
 
    z-index: 100; 
 
} 
 
#btn-add-child {} .control-bar { 
 
    min-height: 50px; 
 
    padding: 10px 0px; 
 
    background: #f1f1f1; 
 
    border-bottom: 1px solid #ccc; 
 
    box-shadow: 0 3px 2px -2px rgba(200, 200, 200, 0.2); 
 
    color: #666; 
 
    position: relative; 
 
} 
 
.asset-title { 
 
    padding: 15px; 
 
    float: left; 
 
} 
 
.control-buttons { 
 
    float: right; 
 
    padding: 10px; 
 
} 
 
.control-buttons button { 
 
    border: none; 
 
    border-radius: 0px; 
 
    background: #fff; 
 
    color: #666; 
 
    height: 30px; 
 
    width: 30px; 
 
} 
 
.image-viewer { 
 
    position: fixed; 
 
    height: 100px; 
 
    width: 150px; 
 
    left: 50px; 
 
    bottom: 50px; 
 
    border: 1px solid #ccc; 
 
    z-index: 100; 
 
    background: white; 
 
} 
 
.node { 
 
    cursor: pointer; 
 
} 
 
.node text { 
 
    font: 12px sans-serif; 
 
} 
 
.link { 
 
    fill: none; 
 
    stroke: #85e0e0; 
 
    stroke-width: 2px; 
 
} 
 
.rightparent>rect { 
 
    display: none; 
 
} 
 
.leftparent>rect { 
 
    fill: #f1f1f1; 
 
    stroke: #ccc; 
 
    stroke-width: 2; 
 
} 
 
.leftparent .left-chevron { 
 
    display: none; 
 
} 
 
.leftparent image { 
 
    display: none; 
 
} 
 
.addLeftChild, 
 
.addRightChild { 
 
    display: none; 
 
} 
 
.left-chevron, 
 
.right-chevron { 
 
    display: none; 
 
} 
 
.collapsed .left-chevron, 
 
.collapsed .right-chevron { 
 
    display: block; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="child-info" style="display:none"> 
 

 
    <input type="text" id="child-text" placeholder="child name"> 
 

 
    <button id="btn-add-child">add</button> 
 
</div> 
 

 
<div id="panzoom" class="doubletree-container"> 
 

 

 

 
</div> 
 
<script> 
 
    $(document).ready(function() { 
 

 
    $(".doubletree-container").makeDoubleTree(); 
 

 

 

 

 

 
    }); 
 
</script>

+0

проблема только на правой стороне – aitnasser

ответ

0

решаемая проблема, добавив следующий код:

/* transition labels to new positions */ 
     var label = svg.selectAll("text.text-link") 
      .data(links, function(d) { 
       return d.target.id; 
      }); 


     label.transition() 
      .duration(duration) 
      .attr("d", diagonal); 


     label.exit().transition() 
      .duration(duration) 
      .attr("d", function(d) { 
       var o = { 
        x: source.x, 
        y: source.y 
       }; 
       return diagonal({ 
        source: o, 
        target: o 
       }); 
      }) 
      .remove(); 
0

Вы забыли удалить старую текстовую ссылку, как вы сделали для левой стороны, затем добавить эту строку вы следует добавить:

d3.selectAll(".right-tree-container .text-link").remove(); 

в вашем makeRightTree функции следующим образом:

$.fn.makeRightTree = function() { 
    // ************** Generate the tree diagram ***************** 
    var margin = { 
     top: 20, 
     right: 120, 
     bottom: 20, 
     left: 120 
    }, 
    width = 1260 - margin.right - margin.left, 
    height = 500 - margin.top - margin.bottom; 

    var i = 0, 
    duration = 750, 
    root; 

    var tree = d3.layout.tree() 
    .size([height, width]); 

    var diagonal = d3.svg.diagonal() 
    .projection(function(d) { 
     return [d.y, d.x]; 
    }); 



    var svg = d3.select("svg").append("g") 
    .attr("class", "right-tree-container") 
    .attr("transform", "translate(600,0)"); 
    svg.append("g").attr("id", "right-edges") 


    root = treeData[0]; 
    oldrx = root.x0 = height/2; 
    oldry = root.y0 = 0; 

    update(root); 



    function update(source) { 

    // Compute the new tree layout. 
    var nodes = tree.nodes(root).reverse(), 
     links = tree.links(nodes); 

    // Normalize for fixed-depth. 
    nodes.forEach(function(d) { 
     d.y = d.depth * 180; 
    }); 

    // Update the nodes… 
    var node = svg.selectAll("g.node") 
     .data(nodes, function(d) { 
     return d.id || (d.id = ++i); 
     }); 

    // Enter any new nodes at the parent's previous position. 
    var nodeEnter = node.enter().append("g") 
     .attr("class", function(d) { 
     console.log(d); 
     if (d.parent == "null") { 

      if (d.children) 

      { 
      return "node rightparent collapsed" //since its root its parent is null 
      } else { 
      return "node rightparent" 
      } 

     } else { 
      if (d.children) { 
      return "node rightchild collapsed" //all nodes with parent will have this class 
      } else { 

      return "node rightchild" //all nodes with parent will have this class 
      } 
     } 

     }) 
     .attr("transform", function(d) { 
     return "translate(" + source.y0 + "," + source.x0 + ")"; 
     }) 
     .on("click", click); 

    nodeEnter.append("rect") 

     .attr("id", function(d) { 
     return "rightnode" + d.id; 
     }) 
     .attr("x", "-10") 
     .attr("y", "-15") 
     .attr("height", 30) 
     .attr("width", 100) 
     .attr("rx", 15) 
     .attr("ry", 15) 
     .style("fill", "#f1f1f1"); 

    nodeEnter.append("image") 
     .attr("xlink:href", "img.png") 
     .attr("x", "0") 
     .attr("y", "-10") 
     .attr("width", 16) 
     .attr("height", 16); 




    nodeEnter.append("text") 
     .attr("x", function(d) { 
     return d.children || d._children ? -13 : 13; 
     }) 
     .attr("dy", ".35em") 
     .attr("text-anchor", function(d) { 
     return d.children || d._children ? "end" : "start"; 
     }) 
     .text(function(d) { 
     return d.name; 
     }) 
     .style("fill-opacity", 1e-6); 




    var addRightChild = nodeEnter.append("g").attr("class", "addRightChild"); 
    addRightChild.append("rect") 
     .attr("x", "90") 
     .attr("y", "-10") 
     .attr("height", 20) 
     .attr("width", 20) 
     .attr("rx", 10) 
     .attr("ry", 10) 
     .style("stroke", "#444") 
     .style("stroke-width", "2") 
     .style("fill", "#ccc"); 

    addRightChild.append("line") 
     .attr("x1", 95) 
     .attr("y1", 1) 
     .attr("x2", 105) 
     .attr("y2", 1) 
     .attr("stroke", "#444") 
     .style("stroke-width", "2"); 

    addRightChild.append("line") 
     .attr("x1", 100) 
     .attr("y1", -4) 
     .attr("x2", 100) 
     .attr("y2", 6) 
     .attr("stroke", "#444") 
     .style("stroke-width", "2"); 



    // adding the right chevron 
    var rightChevron = nodeEnter.append("g").attr("class", "right-chevron"); 





    rightChevron.append("line") 
     .attr("x1", 75) 
     .attr("y1", -5) 
     .attr("x2", 80) 
     .attr("y2", 0) 
     .attr("stroke", "#444") 
     .style("stroke-width", "2"); 

    rightChevron.append("line") 
     .attr("x1", 80) 
     .attr("y1", 0) 
     .attr("x2", 75) 
     .attr("y2", 5) 
     .attr("stroke", "#444") 
     .style("stroke-width", "2"); 

    rightChevron.on("click", function(d) { 


    }); 




    // Transition nodes to their new position. 
    var nodeUpdate = node.transition() 
     .duration(duration) 
     .attr("transform", function(d) { 
     if (d.parent == "null") { 
      d.y = oldry; 
      d.x = oldrx; 


     } 

     return "translate(" + d.y + "," + d.x + ")"; 
     }); 



    nodeUpdate.select("text") 
     .style("fill-opacity", 1); 

    // Transition exiting nodes to the parent's new position. 
    var nodeExit = node.exit().transition() 
     .duration(duration) 
     .attr("transform", function(d) { 
     return "translate(" + source.y + "," + source.x + ")"; 
     }) 
     .remove(); 

    nodeExit.select("text") 
     .style("fill-opacity", 1e-6); 

    var edge = d3.select("#right-edges") 
     .append("g") 
     .attr("class", "edge-container") 
     .data(links); 

**d3.selectAll(".right-tree-container .text-link").remove();** 
    var text = edge.selectAll("text.text-link") 
     .data(links, function(d) { 
     return d.target.id + d.source.id; 
     }); 

    text.enter().insert("text", "edge-container") 
     .attr("class", "text-link") 

    .attr("x", function(d) { 
     var x = (d.source.y + d.target.y)/2 
     return parseInt(x + 45); 
     }) 
     .attr("y", function(d) { 
     var y = (d.source.x + d.target.x)/2 
     return y; 
     }) 
     .text("test-label") 
     .attr("text-anchor", "start") 
     .style("font-size", "14px"); 

    var link = edge.selectAll("path.link") 
     .data(links, function(d) { 
     return d.target.id; 
     }); 





    // Enter any new links at the parent's previous position. 
    link.enter().insert("path", "edge-container") 
     .attr("class", "link") 
     .attr("id", function(d) { 
     return ("rightlink" + d.source.id + "-" + d.target.id) 
     }) 
     .attr("d", function(d) { 
     var o = { 
      x: source.x0, 
      y: source.y0 
     }; 

     return diagonal({ 
      source: o, 
      target: o 
     }); 
     }).on("click", removelink) 
     .on("mouseover", showRemoveButton) 
     .on("mouseout", hideRemoveButton); 

    function showRemoveButton() { 
     console.log("hover"); 
    } 

    function hideRemoveButton() { 
     console.log("hover-out"); 
    } 




    /***** end of relevant code *******/ 


    function removelink(d) { 

     var confirmDelete = confirm("Are you sure you want to delete?"); 


     if (confirmDelete) { 

     //this is the links target node which you want to remove 
     var target = d.target; 
     //make new set of children 
     var children = []; 
     //iterate through the children 
     target.parent.children.forEach(function(child) { 
      if (child.id != target.id) { 
      //add to the child list if target id is not same 
      //so that the node target is removed. 
      children.push(child); 
      } 
     }); 
     //set the target parent with new set of children sans the one which is removed 
     target.parent.children = children; 
     //redraw the parent since one of its children is removed 
     update(d.target.parent) 
     } 



    } 

    var link = svg.selectAll("path.link") 
     .data(links, function(d) { 
     return d.target.id; 
     }); 

    // Transition links to their new position. 
    link.transition() 
     .duration(duration) 
     .attr("d", diagonal); 

    // Transition exiting nodes to the parent's new position. 
    link.exit().transition() 
     .duration(duration) 
     .attr("d", function(d) { 
     var o = { 
      x: source.x, 
      y: source.y 
     }; 
     return diagonal({ 
      source: o, 
      target: o 
     }); 
     }) 
     .remove(); 

    // Stash the old positions for transition. 
    nodes.forEach(function(d) { 


     d.x0 = d.x; 
     d.y0 = d.y; 
    }); 


    addRightChild.on("click", function(d) { 



     event.stopPropagation(); 
     $("#child-info").show(); 
     $("#child-text").val(""); 

     $("#btn-add-child").off('click'); 
     $("#btn-add-child").click(function() { 
     var childname = $("#child-text").val(); 


     if (typeof d._children === 'undefined' || d._children === null) { 
      if (typeof d.children === 'undefined') { 


      var newChild = [{ 
       "name": childname, 
       "parent": "Son Of A", 
      }]; 



      var newnodes = tree.nodes(newChild); 
      d.children = newnodes[0]; 
      // console.log(d.children); 
      update(d); 


      } else { 
      var newChild = { 
       "name": childname, 
       "parent": "Son Of A", 
      }; 
      // console.log(d.children); 
      d.children.push(newChild); 
      // console.log(d.children); 
      update(d); 
      } 
     } else { 
      var newChild = { 
      "name": childname, 
      "parent": "Son Of A", 
      }; 


      d.children = d._children; 
      d.children.push(newChild); 
      // console.log(d.children); 
      update(d); 


     } 


     $("#child-info").hide(); 
     }); 
    });; 

    } 


    // Toggle children on click. 
    function click(d) { 

    if (d.children) { 
     d._children = d.children; 
     d.children = null; 
    } else { 
     d.children = d._children; 
     d._children = null; 
    } 
    update(d); 

    $(".addLeftChild, .addRightChild").hide(); 
    if (d.id === 1) { 
     $(".rightparent").children(".addRightChild").show(); 
     $(this).children(".addRightChild").show(); 
    } else { 
     $(this).children(".addRightChild").show(); 

    } 
    d3.selectAll("rect").style("fill", "#f1f1f1"); //reset all node colors 
    d3.selectAll("path").style("stroke", "#85e0e0"); //reset the color for all links 
    while (d.parent) { 

     d3.select("#leftnode1").style("fill", "#F7CA18"); 
     d3.selectAll("#rightnode" + d.id).style("fill", "#F7CA18"); //color the node 
     if (d.parent != "null") 
     d3.selectAll("#rightlink" + d.parent.id + "-" + d.id).style("stroke", "#F7CA18"); //color the path 
     d = d.parent; 
    } 
    } 
} 

это working demo

+0

Спасибо за ответ. Но это не решает всей проблемы. –

+0

Я обновил [demo] (http://codepen.io/aitnasser/pen/jWYPro/) теперь он отлично работает – aitnasser

+0

Извините, это не то, что я ищу. Я отредактировал вопрос для лучшего понимания. –

Смежные вопросы