【问题标题】:How to center nodes without using centering force?如何在不使用定心力的情况下使节点居中?
【发布时间】:2019-10-16 01:10:35
【问题描述】:

我有一个强制布局图,用户可以在其中动态添加节点。我怎样才能使我的所有节点在中间有一点距离,并使它们独立移动而不是围绕中心移动。

我已尝试删除 d3.forceCenter(width / 2, height / 2),它使节点独立移动,但随后它将所有节点定位在 (0, 0)。

simulation = d3.forceSimulation()
    .force('charge', d3.forceManyBody().strength(0))
    .force('center', d3.forceCenter(width / 2, height / 2));

我希望所有节点都居中并独立移动。

编辑:

我尝试设置 cxcy 值,但这也不起作用。

  const nodeEnter = nodeElements
    .enter()
    .append('circle')
    .attr('r', 20)
    .attr('fill', 'orange')
    .attr('cx', (d, i) => {
      return (width / 2) + i * 10;
    })
    .attr('cy', (d, i) => {
      return (height / 2) + i * 10;
    })
    .call(dragDrop(simulation))
    .on('click', ({ id }) => handleClick(id));

【问题讨论】:

  • 为什么不能同时使用这两种力量?独立是什么意思?
  • @thedude 当 forceCenter 存在时,所有节点都放置在 (width / 2, height / 2) 周围。如果我移动 1 个节点,那么所有其他节点都会相对移动,以将质心保持在同一位置。我不想要那种行为。我希望所有节点都放在中心。但是当我移动 1 个节点时,其余节点应该留在原地。

标签: d3.js centering force-layout


【解决方案1】:

鉴于你在your comment...中所说的...

如果我移动 1 个节点,那么所有其他节点都会相对移动,以将质心保持在同一位置。

...您已经知道forceCenter 是执行任务的错误工具,因为它会保持重心。

因此,只需将其替换为forceXforceY

const simulation = d3.forceSimulation()
    .force('centerX', d3.forceX(width / 2))
    .force('centerY', d3.forceY(height / 2));

由于您没有提供足够的代码,这里是一个通用演示:

svg {
  background-color: wheat;
}
<svg width="400" height="300"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
  const svg = d3.select('svg');

  const width = svg.attr('width');
  const height = svg.attr('height');

  const data = d3.range(50).map(() => ({}));

  const node = svg.selectAll()
    .data(data)
    .enter()
    .append('circle')
    .attr('r', 10)
    .attr('fill', 'teal')
    .attr('stroke', 'black')
    .call(d3.drag()
      .on('start', dragstarted)
      .on('drag', dragged)
      .on('end', dragended));

  const simulation = d3.forceSimulation()
    .force('charge', d3.forceManyBody().strength(-15))
    .force('centerX', d3.forceX(width / 2))
    .force('centerY', d3.forceY(height / 2));

  simulation
    .nodes(data)
    .on('tick', ticked);

  function ticked() {
    node.attr('cx', d => d.x)
      .attr('cy', d => 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;
  }
</script>

【讨论】:

  • 是的,我也试过这个,但这会使拖动端的节点返回中心。但是,我希望他们留在我离开他们的地方。
  • 是添加到拖拽的d.fx = d3.event.x;d.fy = d3.event.y; 的最佳方式吗?
  • 我发现这不是最佳方式。我的代码包括不允许节点重叠的.force('collision', d3.forceCollide().radius(20))。但是,如果我拖动一个节点并将其留在一个地方,那么它可以与其他节点重叠。
  • “是的,我也试过这个”...所以,把它放在问题中。关于您的其他 cmets,这些是不同的问题。请每个问题只保留一个问题。
猜你喜欢
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-19
  • 2020-10-17
  • 2020-06-14
  • 1970-01-01
相关资源
最近更新 更多