d3 v4中的可折叠径向树

时间:2016-10-15 15:45:16

标签: d3.js

我是d3的新手,我正在尝试创建this question的可折叠版本 在第4节。在v3中有各种各样的例子可以解释相同,但我找不到适合v4的例子。 我实现了打开子项的onClick函数,但问题是点击后链接放错了位置。它们向右移动,节点保持在同一位置。 请在下面找到我的更新功能代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
<!--
.node circle {
  //fill: #999;
  fill: #fff;
  stroke: steelblue;
  stroke-width: 3px;
}



.node text {
  font: 10px sans-serif;
}

.node--internal circle {
  fill: #555;
}

.node--internal text {
  text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}

.link {
  fill: none;
  stroke: #555;
  stroke-opacity: 0.4;
  stroke-width: 1.5px;
}
-->
.node {
  cursor: pointer;
}

.node circle {
  fill: #999;
  stroke: steelblue;
  stroke-width: 1.5px;
}

.node text {
  font: 10px sans-serif;
}

.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1.5px;
</style>
<body>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>



var width = 960,
height = 1000,
duration = 750;

var nodes,links;
    var i = 0;


    var svg = d3.select("body").append("svg")
                .attr("width",width)
                .attr("height",height);
    var g = svg.append("g").attr("transform", "translate(" + (width / 2 + 40) + "," + (height / 2 + 90) + ")");

    function connector(d) {
        return "M" + project(d.x, d.y)
                                     + "C" + project(d.x, (d.y + d.parent.y) / 2)
                                     + " " + project(d.parent.x, (d.y + d.parent.y) / 2)
                                     + " " + project(d.parent.x, d.parent.y)
    /*
  return "M" + d.y + "," + d.x +
    "C" + (d.y + d.parent.y) / 2 + "," + d.x +
    " " + (d.y + d.parent.y) / 2 + "," + d.parent.x +
    " " + d.parent.y + "," + d.parent.x;  */
}



    var treeMap = d3.tree()
    .size([360,250]),
    root;
    var nodeSvg, linkSvg, nodeEnter, linkEnter ;



    d3.json("treeData.json",function(error,treeData){
        if(error) throw error;

        root = d3.hierarchy(treeData,function(d){
            return d.children;
        });

         root.each(function (d) {
         console.log(d);
                d.name = d.data.name; //transferring name to a name variable
                d.id = i; //Assigning numerical Ids
                i += i;
            });

         root.x0 = height / 2;
            root.y0 = 0;

            function collapse(d) {
    if (d.children) {
      d._children = d.children;
      d._children.forEach(collapse);
      d.children = null;
    }
  }
         //root.children.forEach(collapse);
            update(root);
    });


function update(source) {


        //root = treeMap(root);
        nodes = treeMap(root).descendants();
        //console.log(nodes);
        //links = root.descendants().slice(1);
        links = nodes.slice(1);
        //console.log(links);
        var nodeUpdate;
                var nodeExit;

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

  nodeSvg = g.selectAll(".node")
                    .data(nodes,function(d) { return d.id || (d.id = ++i); });


        //nodeSvg.exit().remove();

        var nodeEnter = nodeSvg.enter()
                    .append("g")
                    //.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
                    .attr("class", "node")
                    .attr("transform", function(d) { return "translate(" + project(d.x, d.y) + ")"; })
                    //.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
                    .on("click",click)
                    .on("mouseover", function(d) { return "minu"; });



        nodeEnter.append("circle")
            .attr("r", 5)
            .style("fill", color);



      nodeEnter.append("text")
            .attr("dy", ".31em")
            //.attr("x", function(d) { return d.x < 180 === !d.children ? 6 : -6; })
            .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
            .style("text-anchor", function(d) { return d.x < 180 === !d.children ? "start" : "end"; })
            //.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
            .attr("transform", function(d) { return "rotate(" + (d.x < 180 ? d.x - 90 : d.x + 90) + ")"; })
            .text(function(d) {  return d.data.name; });

            // Transition nodes to their new position.
  var nodeUpdate = nodeSvg.merge(nodeEnter).transition()
      .duration(duration);
     // .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });


    nodeSvg.select("circle")
      .style("fill", color);


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

      // Transition exiting nodes to the parent's new position.
  var nodeExit = nodeSvg.exit().transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) //for the animation to either go off there itself or come to centre
      .remove();

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

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

      nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });


        linkSvg = g.selectAll(".link")
                    .data(links, function(link) { var id = link.id + '->' + link.parent.id; return id; });



        // Transition links to their new position.
                linkSvg.transition()
                    .duration(duration);
                   // .attr('d', connector);

        // Enter any new links at the parent's previous position.
                linkEnter = linkSvg.enter().insert('path', 'g')
                    .attr("class", "link")
                    .attr("d", function(d) {
                                return "M" + project(d.x, d.y)
                                     + "C" + project(d.x, (d.y + d.parent.y) / 2)
                                     + " " + project(d.parent.x, (d.y + d.parent.y) / 2)
                                     + " " + project(d.parent.x, d.parent.y);
                            });
                            /*
                            function (d) {
                        var o = {x: source.x0, y: source.y0, parent: {x: source.x0, y: source.y0}};
                        return connector(o);
                    });*/



                    // Transition links to their new position.
                linkSvg.merge(linkEnter).transition()
                    .duration(duration)
                    .attr("d", connector);


                    // Transition exiting nodes to the parent's new position.
                linkSvg.exit().transition()
                    .duration(duration)
                    .attr("d", /*function (d) {
                        var o = {x: source.x, y: source.y, parent: {x: source.x, y: source.y}};
                        return connector(o);
                    })*/function(d) {
                                return "M" + project(d.x, d.y)
                                     + "C" + project(d.x, (d.y + d.parent.y) / 2)
                                     + " " + project(d.parent.x, (d.y + d.parent.y) / 2)
                                     + " " + project(d.parent.x, d.parent.y);
                            })
                    .remove();

                    // Stash the old positions for transition.


}

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


function color(d) {
  return d._children ? "#3182bd" // collapsed package
      : d.children ? "#c6dbef" // expanded package
      : "#fd8d3c"; // leaf node
}


function flatten (root) {
  // hierarchical data to flat data for force layout
  var nodes = [];
  function recurse(node) {
    if (node.children) node.children.forEach(recurse);
    if (!node.id) node.id = ++i;
    else ++i;
    nodes.push(node);
  }
  recurse(root);
  return nodes;
}


function project(x, y) {
  var angle = (x - 90) / 180 * Math.PI, radius = y;
  return [radius * Math.cos(angle), radius * Math.sin(angle)];
}

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

treeData.json:

{
  "name": "United States",
  "children": [
    {
        "name": "Arizona",
        "children":[
        {   "name" : "Arizona Airport", "size": 13}
      ]
    },
    {
        "name": "California",
        "children":[
        {"name": "San Francisco","size":15},
        {"name": "San Jose","size":25},
        {"name": "Los Angeles","size":17}
        ]
    },
    { 
      "name": "Illinois",
      "children":[
      { "name" : "Chicago O'Hare", "size": 13},
      { "name" : "Midway", "size": 18 }
      ]
    },
    {
        "name": "Colorado",
        "children" : [
        { "name": "Denver","size": 7}
        ]
    },
    {
        "name": "Florida","size":2
    },
    {
        "name": "Georgia", "size": 25
    },
    {
        "name": "Kentucky","size":2
    },
    {
        "name": "Massachussets", "size": 25
    },
    {
        "name": "Michigan","size":2
    },
    {
        "name": "Minnesota", "size": 25
    },
    {
        "name": "Missouri","size":2
    },
    {
        "name": "North Carolina", "size": 25
    },
    {
        "name": "Nevada","size":2
    },
    { 
        "name": "Newyork", "size": 12 
    },
    {
        "name": "Oregon","size":2
    },
    {
        "name": "Pennsylvania", "size": 25
    },
    {
        "name": "Washington",
        "children": [
        { "name" : "Seattle","size" : 13}
        ]
    },
    {
        "name": "Hawaii", "size": 25
    },
    {
        "name": "Texas",
        "children" : [
        { "name": "Dallas" ,"size": 9},
        { "name": "Houston" ,"size": 13},
        { "name": "Austin" ,"size": 17}
        ]
    },
    {
        "name": "Utah", "size": 25
    },
    {
        "name": "Virginia", "size": 25
    }
  ]
}

1 个答案:

答案 0 :(得分:3)

@Minu没有更新问题中的代码,所以这就是我为了让它发挥作用所做的一切:

只需改变:

// Transition nodes to their new position.
var nodeUpdate = nodeSvg.merge(nodeEnter).transition()
.duration(duration);

到此:

// Transition nodes to their new position.
var nodeUpdate = nodeSvg.merge(nodeEnter).transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + project(d.x, d.y) + ")"; });

希望这对想要使径向树可折叠的其他人有所帮助。