D3.js(v4) 力导向图布局 一定要用tick() 方法么才能得到正确地数据坐标点么?

lifesimple
  • 816

Demo
http://codepen.io/jingxiao/pe...


    var nodes = [ { name: "BeiJing"    }, { name: "XiaMen" },
                          { name: "XiAn"    }, { name: "HangZhou"   },
                          { name: "ShangHai"   }, { name: "QingDao"    },
                          { name: "NanJing"    } ];
                         
            var links = [  { 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 width = 800;
            var height = 600;
            var svg = d3.select("body")
                        .append("svg")
                        .attr("width",width)
                        .attr("height",height);
            
            // 通过布局来转换数据,然后进行绘制
            var simulation = d3.forceSimulation(nodes)
                  .force("link", d3.forceLink(links).distance(100))
                  .force("charge",d3.forceManyBody())
                  .force("center",d3.forceCenter(width/2, height/2));
    
    
            var color = d3.scaleOrdinal(d3.schemeCategory20);  
            // 绘制
            var svg_links = svg.selectAll("line")
                .data(links)
                .enter()
                .append("line")
                .style("stroke","#ccc")
                .style("stroke-width",3);
    
            var svg_nodes = svg.selectAll("circle")
                .data(nodes)
                .enter()
                .append("circle")
                .attr("r",10)
                .style("fill",function(d,i){
                    return color(i);
                })    
                .attr("cx",function(d){return d.x;})
                .attr("cy",function(d){return d.y;});
            
            var svg_text = svg.selectAll("text")
                .data(nodes)
                .enter()
                .append("text")
                .style("fill","#000")
                .attr("dx",20)
                .attr("dy",10)
                .text(function(d){return d.name;});
    
            console.log("转换后的nodes links数据:");
            console.log(nodes);
            console.log(links);
            
            function draw(){
                svg_nodes
                    .attr("cx",function(d){console.log(d);return d.x;})
                    .attr("cy",function(d){return d.y;});
    
                svg_text
                    .attr("x", function(d){ return d.x; })
                     .attr("y", function(d){ return d.y; });
    
                svg_links
                    .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; });
            }
            simulation.on("tick",draw);
            //draw();
        

通过力导向图来转换节点nodes和线路links为可绘制的数据,然后去绘制连线图。有个疑问是tick()方法。

上述代码中为什么我不能在得到nodes links数据后,直接调用draw() 绘制呢,这个时候的数据有问题,用tick正常,为什么?
类似问题
Why do we need force.on('tick'.. in d3

在console地方 感觉已经得到正确的节点线路坐标数据,

然后就可以直接绘制调用draw() 方法把对应的坐标数据绑定到元素上这样应该就ok了,但事实上在demo中注释tick方法调用,直接draw() 得到的结果是这样

都跑到左上角去了,事实上此时的坐标点位置并不是刚刚console.log()输出的那些数据。
我在draw() 方法中输出了数据

比如Beijingz这个点的 坐标位置(0,0),下面节点显示的位置也和之前不对。但我把输出的object展开看数据又是对的。

有点懵逼,这是怎么回事呢?

tick()方法的作用,我的理解是没到一个时刻都要调用里面的方法更新节点坐标位置。
但我只想初始化数据得到可绘制的数据,然后初始化显示,后面的节点拖拽更新自己写方法来做,只是想用力导向图来转换第一次的数据。

回复
阅读 10.7k
1 个回答

自问自答
有一点要清楚就是 力导向图布局的形成是一个异步的过程而且需要一定时间几秒钟
所以当draw() 去执行的时候,力导向图布局并没有完成,所以取到各节点的坐标是很小的偏移量,如上图三。所以绘制的图形都在左上角去了。
验证这一点,加个setTimeout就行了

setTimeout(draw,5000);

你会发现几秒后布局不好了,数据就正常了绘制出来的图形就OK了,但为什么console.log()打印出来的数据展开会变是什么原因呢,调试工具的问题,好奇怪。

宣传栏