0

I've been using force layout as a sort of physic's engine for board game i'm making, and it's been working pretty well. However, I've been trying to figure out if it is possible to rotate nodes around a specific foci. Consider this codepen. I would like to make the 3 green nodes in the codepen rotate around the foci in a uniform fashion. In the tick() function I do the following:

var k = .1 * e.alpha;

// Push nodes toward their designated focus.
nodes.forEach(function(o, i) {
  o.y += (foci[o.id].y - o.y) * k;
  o.x += (foci[o.id].x - o.x) * k;
});

In the same way that I push nodes toward a foci, I'd like to make all nodes designated to a foci rotate around said foci. Is there any way to accomplish this by manipulating the o.y and o.x variables within the tick() function? I've tried to manually set the x and y values using this formula however I think possibly the charge and gravity of the force layout are messing it up. Any ideas?

I know i'm using force layout for something it's not quite intended to do, but any help would be appreciated.

Community
  • 1
  • 1
Zach Russell
  • 328
  • 3
  • 7
  • 1
    As an aside, shouldn't it be named *focus*? *Foci* is the plural of [*focus*](https://en.m.wiktionary.org/wiki/focus). If talking about *a specific* one, it should be *a specific focus* throughout your question. – altocumulus Feb 28 '16 at 13:39

1 Answers1

2

I have messed around with your code to get a basic movement around a point.

I changed the foci var to an object which is just two points :

 foci = {
    x: 300,
    y: 100
  };

Ive added to the data you have to give each node a start point :

nodes.push({
  id: 0,
  x:20,
  y:30
});
nodes.push({
  id: 0,
  x:40,
  y:60
});
nodes.push({
  id: 0,
  x:80,
  y:10
});

I have added an angle to each node so you can use these independently later:

 .attr("cx", function(d) {
            d.angle = 0; //added
      return d.x;
    })

And changed the tick so each node moves around the focal point. As said before I added an angle as these points will move around different circles with different sized radius as they will be different distances from the foci point. If you use one angle then all the nodes will move ontop of each other which is pointless :

Formula for point on a circle :

//c = centre point, r = radius, a = angle
x = cx + r * cos(a)
y = cy + r * sin(a)

Use this in tick :

var radius = 100; //made up radius

  node
    .attr("cx", function(d) {
       if(d.angle>(2*Math.PI)){ restart at full circle
         d.angle=0;
       }
    d.x = foci.x + radius *Math.cos(d.angle) //move x

      return d.x;
    })
    .attr("cy", function(d) {
    d.y = foci.y + radius *Math.sin(d.angle) //move y
      return d.y;
    });

Updated fiddle : https://jsfiddle.net/reko91/yg0rs4xc/7/

This should be simple to implement to change from circle movement to elliptical :))

Looking at this again, this only moves around half way. This is due to the tick function only lasting a couple of seconds. If you click one of the nodes, it will continue around the circle. If you want this to happen continuously, you'll have to set up a timer function so it runs around the circle non stop, but that should be easily implemented.

Instead of tick function just make another function with the timer inside, call it on load and it will run continuously :)

thatOneGuy
  • 9,977
  • 7
  • 48
  • 90
  • 1
    Thank you so much for taking the time to work this out. It's pretty close to what I wanted, I want the nodes to orbit around the foci with each node having a different location on the circumference but i'm pretty sure I can figure it out with what you posted. – Zach Russell Feb 27 '16 at 17:46
  • Nice glad I could help :))) There was obviously a few mistakes on my part but obviously it was enough to help you out – thatOneGuy Feb 28 '16 at 15:35