【问题标题】:How to draw the force chart in d3 v4?如何在d3 v4中绘制力图?
【发布时间】:2017-04-22 04:30:20
【问题描述】:

我是 d3 的新手,当我学习如何绘制力图时,我遇到了一些问题。首先,让我们在这里看看我的代码:

<html>
<head>
<meta charset="UTF-8">
<title>the force chart</title>
</head>
 
<body>
    <script src="http://d3js.org/d3.v4.min.js"></script>
    <script> 
        var width = 400;        
        var height = 400;    
        var svg = d3.select("body")    
                    .append("svg")     
                    .attr("width",width)      
                    .attr("height",height);     
        var nodes = [ { "id": "English" },{ "id": "Italy" },
                      { "id": "America" },{ "id": "Canada" },
                      { "id": "Australia" },{ "id": "Japan" },
                      { "id": "China" } ];
        var edges = [ { "source": 0 , "target": 1 } , { "source": 0 , "target": 2 },
                      { "source": 0 , "target": 3 } , { "source": 1 , "target": 4 },
                      { "source": 1 , "target": 5 } , { "source": 1 , "target": 6 }, ];


        var force = d3.forceSimulation(nodes)  
                    .force("link",d3.forceLink()
                    .id(function(d){return d.id})
                    .distance(function(d){return 150}).strength([-400]))
                    .force("charge",d3.forceManyBody())
                    .force("center",d3.forceCenter(width , height));

            force.restart(); //start

        var svg_edges = svg.selectAll("line")
            .data(edges)
            .enter()
            .append("line")
            .style("stroke","#ccc")
            .style("stroke-width",1);

        var color = d3.scaleOrdinal(d3.schemeCategory20);

        //add nodes
        var svg_nodes = svg.selectAll("circle")
            .data(nodes)
            .enter()
            .append("r",20)
            .style("fill",function(d,i){
                return color(i);
            })
            .call(d3.drag());   //to drag the nodes

        //add information
        var svg_texts = svg.selectAll("text")
            .data(nodes)
            .enter()
            .append("text")
            .style("fill", "black")
            .attr("dx", 20)
            .attr("dy", 8)
            .text(function(d){
                return d.id;
            });

        force.on("tick", function(){ //update the position of lines
            svg_edges.attr("x1",function(d){ return d.source.x; })
                .attr("y1",function(d){ return d.source.y; })
                .attr("x2",function(d){ return d.target.x; })
                .attr("y2",function(d){ return d.target.y; })

            //update the position of nodes
            svg_nodes.attr("cx",function(d){ return d.x; })
                .attr("cy",function(d){ return d.y; });

            //update the position of information
            svg_texts.attr("x",function(d){ return d.x; })
                .attr("y",function(d){ return d.y; });

        });
    </script>     
</body>
</html>

我想画这样一张图:

但是我的代码只能显示一个节点,就像这样:

所以我感到很困惑,因为开发者工具中没有错误。当我布置力时,我推断https://github.com/d3/d3-force/blob/master/README.md#links。所以我解决了不同版本导致的问题。但为什么它仍然不起作用?你可以帮帮我吗?如果您能帮助我,我将不胜感激!谢谢!

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    除了@Vinod 已经解释的要点:

    .append("circle")
    

    .force("center", d3.forceCenter(width/2, height/2));
    

    您有一个尾随逗号。但最重要的是,要显示边缘:

    首先,将边添加到模拟中:

    force.force("link")
        .links(edges);
    

    然后,更改链接 ID。目前,没有名为id 的属性。所以,应该是:

    .force("link", d3.forceLink()
        .id(function(d,i) {
            return i
        })
        //the rest of the function
    

    这是一个演示:

     var width = 400;
     var height = 400;
     var svg = d3.select("body")
         .append("svg")
         .attr("width", width)
         .attr("height", height);
     var nodes = [{
         "id": "English"
     }, {
         "id": "Italy"
     }, {
         "id": "America"
     }, {
         "id": "Canada"
     }, {
         "id": "Australia"
     }, {
         "id": "Japan"
     }, {
         "id": "China"
     }];
     var edges = [{
         "source": 0,
         "target": 1
     }, {
         "source": 0,
         "target": 2
     }, {
         "source": 0,
         "target": 3
     }, {
         "source": 1,
         "target": 4
     }, {
         "source": 1,
         "target": 5
     }, {
         "source": 1,
         "target": 6
     }];
    
    
     var force = d3.forceSimulation()
         .force("link", d3.forceLink()
             .id(function(d,i) {
                 return i
             })
             .distance(function(d) {
                 return 150
             }))
         .force("charge", d3.forceManyBody())
         .force("center", d3.forceCenter(width/2, height/2));
    
     force.restart(); //start
    
     var svg_edges = svg.selectAll("line")
         .data(edges)
         .enter()
         .append("line")
         .style("stroke", "#ccc")
         .style("stroke-width", 1);
    
     var color = d3.scaleOrdinal(d3.schemeCategory20);
    
     //add nodes
     var svg_nodes = svg.selectAll("circle")
         .data(nodes)
         .enter()
         .append("circle")
    		 .attr("r", 20)
         .style("fill", function(d, i) {
             return color(i);
         })
         .call(d3.drag()); //to drag the nodes
    
     //add information
     var svg_texts = svg.selectAll("text")
         .data(nodes)
         .enter()
         .append("text")
         .style("fill", "black")
         .attr("dx", 20)
         .attr("dy", 8)
         .text(function(d) {
             return d.id;
         });
    		 
    	force.nodes(nodes);
    	force.force("link")
          .links(edges);
    
     force.on("tick", function() { //update the position of lines
         svg_edges.attr("x1", function(d) {
                 return d.source.x;
             })
             .attr("y1", function(d) {
                 return d.source.y;
             })
             .attr("x2", function(d) {
                 return d.target.x;
             })
             .attr("y2", function(d) {
                 return d.target.y;
             })
    
         //update the position of nodes
         svg_nodes.attr("cx", function(d) {
                 return d.x;
             })
             .attr("cy", function(d) {
                 return d.y;
             });
    
         //update the position of information
         svg_texts.attr("x", function(d) {
                 return d.x;
             })
             .attr("y", function(d) {
                 return d.y;
             });
    
     });
    &lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 哦,谢谢你的帮助!效果很好,但是为什么我的节点不能拖?因为我添加了代码: .call(d3.drag()) 。我需要添加代码“on”吗?此外,我不明白这一点:你有一个尾随逗号。你能帮助我吗?谢谢!
    • 尾随昏迷在edges。关于拖动,您必须设置类型名称。检查这个例子:bl.ocks.org/mbostock/4062045
    • 天哪!感谢您的帮助!我只是在边缘找到了尾随昏迷。再次感谢您的帮助!我会按照例子再试一次。
    【解决方案2】:

    你的代码有几个错误

    首先你需要像这样附加圆圈

      var svg_nodes = svg.selectAll("circle")
    
            .data(nodes)
            .enter()
            .append("circle")
            .attr("r",20)
            .style("fill",function(d,i){
                return color(i);
            })
            .call(d3.drag());   //to drag the nodes
    

    当您的代码附加 r 时,它不是 SVG 标记,而且图形的中心不应该是宽度和高度,它应该是宽度/2 和高度/2 以使其位于中心

    看这个小提琴http://jsfiddle.net/Qh9X5/9515/

    类似地,您使用的边缘数据没有 x,y 值,您需要传递 xy 值来绘制线条

    有关 v3.3 中的完整解决方案说明,请参阅此 https://jsfiddle.net/3uehrfj8/1/ 以及所有节点和边

    【讨论】:

    • 但是我在 d3 v4 中使用边缘数据,那么我如何使用它呢?力与v3.3不同。
    • 谢谢你的意见,我完全忘记在我的代码中添加 r。
    • @Charlie 是的,我正打算在某个时候更新该解决方案 从这里开始应该是这样的 plnkr.co/edit/RwhCmYeQHHMiRUeFEQXN?p=preview
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 2013-11-29
    • 2017-11-25
    • 2017-02-25
    • 2016-12-02
    • 1970-01-01
    • 2018-04-24
    相关资源
    最近更新 更多