如何更改力布局中节点之间的距离? [英] How to change the distance between nodes in a force layout?

查看:334
本文介绍了如何更改力布局中节点之间的距离?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是D3的新手,并尝试学习部队布局.我想更改节点之间的链接距离并保持原点形状.我发现更改链接的距离后,布局也发生了更改.

I am new to D3 and try to learn force layout. I want to change the link distance between nodes and maintain the origin shape. I find that after I change the distance of the links, the layout was changed.

图1是原始布局,然后我用代码distance([150])(在第80行)更改了链接距离,以使节点更远,但是布局发生了超出我预期的变化.

Figure one is the original layout, then I changed the link distance with code distance([150]) (at line 80) to make the nodes further, but the layout changes out of my expectation.

我希望布局会随着形状保持与原始形状一样长大,但是布局会发生很大变化.我现在不确定链接距离的含义. 有人可以帮忙吗?谢谢! 我在Codepen上的代码

I expected it the layout will grow up with keeping the shape as same as original, but the layout changes a lot. I am not sure about the meaning of link distance now. Can anyone help? Thank you! My code on codepen

推荐答案

按照其定义,力向图是动态的:您不能预先设置节点的位置,也不能期望节点会落在给定的位置.

By its very definition, a force directed chart is dynamic: you cannot previously set the nodes' position, or expect that the nodes will fall in a given position.

D3力模拟具有如此众多的参数,以至于其中一个参数的微小变化都会使布局完全不同.这实际上是预期的.

D3 force simulation has so many parameters that a minor change in one of them can make the layout completely different. That's actually expected.

因此,就您而言,这里没有什么奇怪的.您可以尝试一些不同的解决方案.在我看来,保持(大约)所需结构且在节点之间具有更大间距的方法是使用forceCollide,为中心节点设置不同的半径(橙色的):

So, in your case, there is nothing strange here. You can try a few different solutions. In my opinion, the one that keeps (approximately) the structure you want with a bigger separation between the nodes is using forceCollide, setting a different radius for the central node (the orange one):

.force('collide', d3.forceCollide(function(d){
    return d.id === "j" ? 100 : 50
}));

这是更新的CodePen: https://codepen.io/anon/pen/xJgYmP?editors = 0010

Here is the updated CodePen: https://codepen.io/anon/pen/xJgYmP?editors=0010

下面是堆栈代码段中的相同代码:

And here the same code in the Stack snippet:

graph = {
  nodes: [{
      id: 'a',
      group: 1
    },
    {
      id: 'b',
      group: 1
    },
    {
      id: 'c',
      group: 1
    },
    {
      id: 'd',
      group: 2
    },
    {
      id: 'e',
      group: 2
    },
    {
      id: 'f',
      group: 2
    },
    {
      id: 'g',
      group: 3
    },
    {
      id: 'h',
      group: 3
    },
    {
      id: 'i',
      group: 3
    },
    {
      id: 'j',
      group: 4
    }
  ],
  links: [{
      source: 'a',
      target: 'b',
      value: 2
    },
    {
      source: 'a',
      target: 'c',
      value: 2
    },
    {
      source: 'b',
      target: 'c',
      value: 1
    },
    {
      source: 'd',
      target: 'e',
      value: 2
    },
    {
      source: 'd',
      target: 'f',
      value: 2
    },
    {
      source: 'e',
      target: 'f',
      value: 1
    },
    {
      source: 'g',
      target: 'h',
      value: 1
    },
    {
      source: 'g',
      target: 'i',
      value: 2
    },
    {
      source: 'i',
      target: 'h',
      value: 2
    },
    {
      source: 'a',
      target: 'j',
      value: 2
    },
    {
      source: 'b',
      target: 'j',
      value: 1
    },
    {
      source: 'c',
      target: 'j',
      value: 1
    },
    {
      source: 'd',
      target: 'j',
      value: 1
    },
    {
      source: 'e',
      target: 'j',
      value: 1
    },
    {
      source: 'f',
      target: 'j',
      value: 1
    },
    {
      source: 'g',
      target: 'j',
      value: 1
    },
    {
      source: 'h',
      target: 'j',
      value: 2
    },
    {
      source: 'i',
      target: 'j',
      value: 2
    },
  ]
}
var graph = this.graph

var svg = d3.select('svg')
var width = +svg.attr('width')
var height = +svg.attr('height')

var color = d3.scaleOrdinal(d3.schemeCategory20)

var simulation = d3.forceSimulation()
  .force('link', d3.forceLink().id(function(d) {
    return d.id
  }))
  .force('charge', d3.forceManyBody())
  .force('collide', d3.forceCollide(function(d) {
    return d.id === "j" ? 100 : 50
  }))
  .force('center', d3.forceCenter(width / 2, height / 2))

var link = svg.append('g')
  .attr('class', 'links')
  .selectAll('line')
  .data(graph.links)
  .enter().append('line')
  .attr('stroke-width', function(d) {
    return Math.sqrt(d.value)
  })

var node = svg.append('g')
  .attr('class', 'nodes')
  .selectAll('circle')
  .data(graph.nodes)
  .enter().append('circle')
  .attr('r', 5)
  .attr('fill', function(d) {
    return color(d.group)
  })
  .call(d3.drag()
    .on('start', dragstarted)
    .on('drag', dragged)
    .on('end', dragended))

node.append('title')
  .text(function(d) {
    return d.id
  })

simulation
  .nodes(graph.nodes)
  .on('tick', ticked)

simulation.force('link')
  .links(graph.links)

function ticked() {
  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
    })

  node
    .attr('cx', function(d) {
      return d.x
    })
    .attr('cy', function(d) {
      return d.y
    })
}

function dragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart()
  d.fx = d.x
  d.fy = d.y
}

function dragged(d) {
  d.fx = d3.event.x
  d.fy = d3.event.y
}

function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0)
  d.fx = null
  d.fy = null
}

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: #fff;
  stroke-width: 1.5px;
}

<script src="https://d3js.org/d3.v4.min.js"></script>
<div class="container">
  <svg width="960" height="600"></svg>
</div>

这篇关于如何更改力布局中节点之间的距离?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆