Arkadiy Stepanov
Arkadiy Stepanov

Reputation: 181

How to center nodes without using centering force?

I have a force layout graph where user adds nodes dynamically. How can i center all my nodes with a bit distance between, and make them move independently and not around the center.

I have tried removing the d3.forceCenter(width / 2, height / 2) which makes nodes move independently but then it possitions all nodes at (0, 0).

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

I want all the nodes to be centered and move independently.

EDIT:

I tried setting cx and cy values but that did not work either.

  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));

Upvotes: 0

Views: 1329

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102218

Given what you said in your comment...

If i move 1 node then all other nodes move relatively in order to keep the center of mass at the same spot.

... you already know that forceCenter is the wrong tool for the task, since it will keep the centre of mass.

Therefore, just replace it for forceX and forceY:

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

Since you didn't provide enough code here is a general demo:

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>

Upvotes: 2

Related Questions