Create node cluster's focal points by data attribute in d3?

一曲冷凌霜 提交于 2019-12-06 14:19:25

All the clustering work takes place here:

// Push different nodes in different directions for clustering.
var k = 6 * e.alpha;
json.nodes.forEach(function(o, i) {
    o.y += i & 3 ? k : -k;
    o.x += i & 2 ? k : -k;      
});

Admittedly, I don't get how it works in this particular example. It seems indirect and hard to understand. More generally, this is what you want to do in order to cluster:

force.on("tick", function(e) {
  var k = e.alpha * .1;
  nodes.forEach(function(node) {
    var center = ...; // here you want to set center to the appropriate [x,y] coords
    node.x += (center.x - node.x) * k;
    node.y += (center.y - node.y) * k;
  });

It's taken straight out of this example and you can view source to see the code.

In this code, it's easier to understand how, on tick, the nodes are pushed closer to a desired focal point. So now you need to come up with a way to map a node to a focal point based on its group param so that you fill in that var center = ...; line.

First, you need to get an inventory of all the groups in json.nodes. d3.nest() is good for that:

var groups = d3.nest()
  .key(function(d) { return d.group; })
  .map(json.nodes)

That will give you a mapping of groups to node. Since your example json has just 2 groups in it ("1" and "6"), it'll look like this:

{
  "1": [
    {
      "name": "Null",
      "radius": 40,
      "color": "#ff0000",
      "gravity": 0.05,
      "group": 1
    },
    {
      "name": "One",
      "radius": 40,
      "color": "#ffff00",
      "gravity": 0.05,
      "group": 1
    },
    {
      "name": "Two",
      "radius": 40,
      "color": "#33cc33",
      "gravity": 0.2,
      "group": 1
    },
    {
      "name": "Three",
      "radius": 40,
      "color": "#3399ff",
      "gravity": 0.9,
      "group": 1
    }
  ],
  "6": [
    {
      "name": "Four",
      "radius": 40,
      "color": "#ffff00",
      "gravity": 0.05,
      "group": 6
    },
    {
      "name": "Five",
      "radius": 40,
      "color": "#33cc33",
      "gravity": 0.2,
      "group": 6
    },
    {
      "name": "Six",
      "radius": 40,
      "color": "#3399ff",
      "gravity": 0.9,
      "group": 6
    }
  ]
}

Then you can loop over groups and assign each group a center point as you'd like. How you do that depends on what you're trying to achieve. Perhaps you'd like to distribute the focal points in a circle around the center of the screen. It's up to you... But the goal is to end up with something where groups["1"].center equals something like {x:123, y:456}, because then you can plug that back into the tick handler from above:

force.on("tick", function(e) {
  var k = e.alpha * .1;
  nodes.forEach(function(node) {
    var center = groups[node.group].center;
    node.x += (center.x - node.x) * k;
    node.y += (center.y - node.y) * k;
  });

And (hopefully) voila!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!