d3js画动态tree图,点击后层级混乱,求助

发布于 2022-09-02 20:58:58 字数 9361 浏览 37 评论 0

按着教程画出来了但是发现点击后层级变化出错,求大神帮助看看
代码如下

<html>
<head>
    <meta charset="utf-8"/>
    <title>tree图</title>
</head>
<body>
<script src="/d3.v3.min.js"></script>
<script>
    var fontSize = 10
    var lineSpace = 2
    var boxHeight = 40
    var boxWidth = 130

    var width = 960
    var height = 1000


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


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

    var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .append("g")
            .attr("transform", "translate(80,0)");

    d3.json("city.json", function (error, root) {

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

        //以第一个节点为起始节点,重绘
        redraw(root);

        //重绘函数
        function redraw(source) {

            /*
             (1) 计算节点和连线的位置
             */

            //应用布局,计算节点和连线
            var nodes = tree.nodes(root);
            var links = tree.links(nodes);

            //重新计算节点的y坐标
            nodes.forEach(function (d) {
                d.y = d.depth * 180;
            });
            /*
             (2) 节点的处理
             */
            nodes_redraw(nodes);
            /*
             (3) 连线的处理
             */
            links_redraw(links);
            /*
             (4) 将当前的节点坐标保存在变量x0、y0里,以备更新时使用
             */
            nodes.forEach(function (d) {
                d.x0 = d.x;
                d.y0 = d.y;
            });


            /*
             节点的处理函数
             */
            function nodes_redraw(nodes) {   //获取节点的update部分
                var nodeUpdate = svg.selectAll(".node")
                        .data(nodes);
                //获取节点的enter部分
                var nodeEnter = nodeUpdate.enter();
                //获取节点的exit部分
                var nodeExit = nodeUpdate.exit();
                nodes_enter(nodeEnter);
                nodes_update(nodeUpdate);
                nodes_exit(nodeExit);
            }

            function nodes_enter(nodeEnter) {
                //1. 节点的 Enter 部分的处理办法
                var enterNodes = nodeEnter.append("g");

                enterNodes
                        .attr("class", "node")
                        .attr("transform", function (d) {
                                    return "translate(" + d.y + "," + d.x + ")";
                                }
                        )
                        .append("rect")
                        .attr('class', 'nodebox')
                        .attr("x", -boxWidth / 2)
                        .attr("y", -boxHeight / 2)
                        .attr("width", boxWidth)
                        .attr("height", boxHeight)

                enterNodes.append("text")
                        .attr("id", "nodetitle")
                        .attr("class", "nodeTitle")
                        .attr("y", -boxHeight / 2 + fontSize + 2 * lineSpace)
                        .attr("text-anchor", "middle")
                        .text(function (d) {
                            return d.name;
                        })

                enterNodes.append("text")
                        .attr("text-anchor", "middle")
                        .attr("class", "nodeText")
                        .attr("y", -boxHeight / 2 + 2 * fontSize + 4 * lineSpace)
                        .text(function (d) {
                            return d.age ? d.age : 100;
                        });


                //
                enterNodes.attr("transform", function (d) {
                    return "translate(" + source.y0 + "," + source.x0 + ")";
                }).on("click", function (d) {
                    console.log(' click -->');
                    console.log(d);
                    toggle(d);
                    redraw(d);
                });
            }

            function nodes_update(nodeUpdate) {
                //2. 节点的 Update 部分的处理办法
                var updateNodes = nodeUpdate.transition()
                        .duration(500)
                        .attr("transform", function (d) {
                            console.log('Update  -- > ');
                            console.log(d);
                            return "translate(" + d.y + "," + d.x + ")";
                        });
            }

            function nodes_exit(nodeExit) {
                //3. 节点的 Exit 部分的处理办法
                var exitNodes = nodeExit.transition()
                        .duration(500)
                        .attr("transform", function (d) {
                            console.log('exitNode  -- > ');
                            console.log(d);
                            return "translate(" + source.y + "," + source.x + ")";
                        })
                        .remove();
            }

            /*
             连线的处理函数
             */
            function links_redraw(links) {
                //获取连线的update部分
                var linkUpdate = svg.selectAll(".link")
                        .data(links);

                //获取连线的enter部分
                var linkEnter = linkUpdate.enter();

                //获取连线的exit部分
                var linkExit = linkUpdate.exit();

                links_enter(linkEnter);
                links_update(linkUpdate);
                links_exit(linkExit);
            }

            function links_enter(linkEnter) {
                //1. 连线的 Enter 部分的处理办法
                linkEnter.insert("path", ".node")
                        .attr("class", "link")
                        .attr("d", function (d) {
                            var o = {x: source.x0, y: source.y0};
                            return diagonal({source: o, target: o});
                        })
                        .transition()
                        .duration(500)
                        .attr("d", diagonal);
            }

            function links_update(linkUpdate) {
                //2. 连线的 Update 部分的处理办法
                linkUpdate.transition()
                        .duration(500)
                        .attr("d", diagonal);
            }

            function links_exit(linkExit) {
                //3. 连线的 Exit 部分的处理办法
                linkExit.transition()
                        .duration(500)
                        .attr("d", function (d) {
                            var o = {x: source.x, y: source.y};
                            return diagonal({source: o, target: o});
                        })
                        .remove();
            }

        }

    });


    //切换开关,d 为被点击的节点
    function toggle(d) {
        if (d.children) { //如果有子节点
            d._children = d.children; //将该子节点保存到 _children
            d.children = null;  //将子节点设置为null
        } else {//如果没有子节点
            d.children = d._children; //从 _children 取回原来的子节点
            d._children = null; //将 _children 设置为 null
        }
    }


    //DATA JOIN: Bind existing objects to new data
    //        var existingLinks = svg.selectAll(".link").data(links)
    //
    //        var existingNodes = svg.selectAll(".node").data(nodes)
    //
    //
    //        //ENTER: Create new objects where necessary
    //        existingLinks.enter().append("path")
    //                .attr("class", "link")
    //                .attr("d", diagonal)


    /*
     newNodes.on("mouseenter", function() {
     thisNode = d3.select(this)
     thisNode.selectAll(".nodeText")
     .attr('fill','red')
     thisNode.selectAll(".nodeTitle")
     .attr('fill','red')
     })

     newNodes.on("mouseleave", function(){
     thisNode = d3.select(this)
     thisNode.selectAll(".nodeText")
     .attr('fill','balck')

     thisNode.selectAll(".nodeTitle")
     .attr('fill','balck')
     })
     */

</script>
<style type="text/css">
    .nodebox {
        fill: #fff;
        stroke: steelblue;
        stroke-width: 3.5px;
    }

    .nodeTitle {
        font: 14px sans-serif;
    }

    .nodeText {
        font: 10px sans-serif;
    }

    .link {
        fill: none;
        stroke: #ccc;
        stroke-width: 3.5px;
    }
</style>
</body>
</html>

city.json文件如下

{
"name":"中国",
"age":"19" , 
"children":
[
    { 
      "name":"浙江" , 
      "age":"19" , 
        "children":
        [
                {"name":"杭州" , "age":"19"   },
      
                {"name":"宁波" , "age":"19" },
                {"name":"温州" , "age":"19" },
                {"name":"绍兴", "age":"19"  }
        ] 
      },
      
    { 
        "name":"广西" , 
        "children":
        [
            {"name":"桂林", "age":"19" },
            {"name":"南宁", "age":"19" },
            {"name":"柳州", "age":"19" },
            {"name":"防城港", "age":"19" }
        ] 
    },
    
    { 
        "name":"黑龙江",
        "children":
        [
            {"name":"哈尔滨"},
            {"name":"齐齐哈尔"},
            {"name":"牡丹江"},
            {"name":"大庆"}
        ] 
    },
    
    { 
        "name":"新疆" , 
        "children":
        [
            {"name":"乌鲁木齐"},
            {"name":"克拉玛依"},
            {"name":"吐鲁番"},
            {"name":"哈密"}
        ]
    }
]
}

d3.v3.min.js文件不贴了-官网地址

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

韵柒 2022-09-09 20:58:58

解决了
因为一行代码

    //获取节点的update部分
            var nodeUpdate = svg.selectAll(".node")
                    .data(nodes, function (d) {
                        return d.name;
                    });

我写的是

 var nodeUpdate = svg.selectAll(".node")
                        .data(nodes);

但是我没明白这个的作用是什么

帅哥哥的热头脑 2022-09-09 20:58:58

data() 函数有两个参数,第一个是被绑定数据,第二个参数用于指定绑定的顺序。在数据需要更新的时候常常会用到。

默认的情况下,data()函数是按照索引号依次绑定数组各项的。第0个元素绑定数组的第0项,第1个元素绑定数组的第1项,依此类推。也可以不按照此顺序进行绑定,这就要用到data()的第二个参数。这个参数是一个函数,称为键函数(key function)。

按照你之前的写法 执行这个函数以后

 //切换开关,d 为被点击的节点
    function toggle(d) {
        if (d.children) { //如果有子节点
            d._children = d.children; //将该子节点保存到 _children
            d.children = null;  //将子节点设置为null
        } else {//如果没有子节点
            d.children = d._children; //从 _children 取回原来的子节点
            d._children = null; //将 _children 设置为 null
        }
    }

以收起children为例
每次触发click以后 会减少4个node 但是我们是按照索引绑定数据的 被删除的是最后四个

改成 return d.name以后 是按照 name这个键值来绑定的 虽然也减少 4个node 但是我们默认是减少的name下 children 的node 所有正常

更多 查看这里 http://www.ourd3js.com/wordpr...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文