【问题标题】:How to position nodes Force Directed Graph D3 with CSS?如何使用 CSS 定位节点 Force Directed Graph D3?
【发布时间】:2017-06-18 12:11:33
【问题描述】:

我正在用 D3 制作一个力有向图,并让它与节点的 svg 圆一起工作。但是,当我将 div 与 CSS left 和 top 属性结合使用时,节点就错位了。我无法弄清楚我在这里做错了什么。我使用强制 D3 生成的 x 和 y 坐标作为 left 和 top 属性,但也许这不是要走的路?

这是我的 JS:

var url = "https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json";

d3.json(url, function(json){

  var data = json;

  var margin = {top: 40, right: 40, bottom: 40, left: 40};

  var w = 1000 - margin.left - margin.right;
  var h = 1000 - margin.top - margin.bottom;

  var svg = d3.select("#chart")
              .append("svg")
                .attr("width", w + margin.left + margin.right)
                .attr("height", h + margin.top + margin.bottom)
              .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  var nodes = data.nodes;
  var links = data.links;

  //Create a force layout object and define its properties
  var force = d3.layout.force()
                .size([w,h])
                .nodes(nodes)
                .links(links);

  force.linkDistance(h/20);

  force.charge(-120)

  var link = svg.selectAll(".link")
                .data(links)
                .enter()
                .append("line")
                .attr("class", "link");

  var node = d3.select("#chart").selectAll(".node")
                .data(nodes)
                .enter()
                .append("div")

  force.on("end", function(){
  //set node and link position attributes once force calculations have finished  

    //position the nodes
    node.style("left", function(d){

            return d.x  + "px";

        })
        .style("top", function(d){

            return d.y + "px";

        })
        .attr("class", function(d){

            return "flag flag-" + d.code + " node";

        })
        .attr("src", "https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png");

    link.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;

        })



  })//force.on


  force.start();
  //let the force start its calculations

})

我的 CSS:

svg {

  background-color: white;
  box-shadow: 0 0 10px #888888;

}

.link {

  stroke: #2c3e50;
  stroke-width: 2px;

}

.flag {
    display: inline-block;
    position:absolute;
    width: 16px;
    height: 11px;
    background: url('https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png') no-repeat;
}

.flag.flag-ml {
    background-position: -224px -88px;
}

到目前为止在 codepen 上的图表:

https://codepen.io/chemok78/full/VPMgGx/

【问题讨论】:

标签: javascript css d3.js svg data-visualization


【解决方案1】:

考虑 SVG 中的链接从窗口偏移了多少:它们移动了 margin.left,向下移动了 margin.top,还向下移动了 <h1><h2> 的高度(加上填充)。

例如,在我的浏览器中,使用以下代码的标志看起来定位正确:

node.style("left", function(d){

        return d.x + margin.left + 150 + "px";

    })
    .style("top", function(d){

        return d.y + margin.top + "px";

    })

请注意,这是因为<div> 标志元素的默认lefttop 属性为0,即使它们的父元素是<div#chart>。我已经硬编码了 150,但您也可以设计一种动态计算它的方法。

您使用<circle> 而不是<div> 的原因是圆圈是SVG 元素和<svg> 的子元素,因此它们已经处于正确的起始位置。可能有另一种解决方案,您可以在 SVG 中保留标志:将节点添加为 <g><rect> 而不是 <div>xy 的属性而不是 lefttop<svg> 的孩子而不是 <div#chart>。但是,我还没有探索如何实现将标志分配给每个节点,因为您没有为每个标志文件指向不同的 URL。

【讨论】:

    【解决方案2】:

    谢谢大家,

    我最终使用Element.getBoundingClientRect() 获得了图表中 SVG g 元素的位置,并使用左上角的位置来定位所有节点。

    //Get position of g element of the chart
      var position = document.getElementById("area").getBoundingClientRect();
    
    force.on("tick", function(){
    
        node.style("left", function(d){
    
                return d.x  + position.left + "px";
    
            })
            .style("top", function(d){
    
                return d.y  + position.top  +  "px";
    
            })
            .attr("class", function(d){
    
                return "flag flag-" + d.code + " node";
    
            })
            .attr("src", "https://res.cloudinary.com/dettjqo9j/image/upload/v1485942660/flags_xf9dde.png")
    
        link.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;
    
            })
    
      })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 1970-01-01
      • 2017-10-10
      • 1970-01-01
      • 2012-01-28
      • 2013-04-27
      • 2011-11-10
      相关资源
      最近更新 更多