在d3 js树中插入多次工作

时间:2016-01-20 13:23:04

标签: javascript d3.js

我正在创建一个树并尝试为边添加标签。在同一个树中,可以使用单击父节点时出现的加号按钮动态添加节点。当我添加一个新孩子时会出现问题。

(抱歉长代码,无法做出更小的工作示例 - 为了便于分析而对代码进行了评论)

问题

当我检查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>

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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();