visjs / vis-network

:dizzy: Display dynamic, automatically organised, customizable network views.
https://visjs.github.io/vis-network/
Apache License 2.0
3k stars 366 forks source link

Network clustering nodes which have a common property #1147

Open JJn9 opened 3 years ago

JJn9 commented 3 years ago

Hello, I'm trying to create a cluster of nodes based on a node property. The documentation mentions : var options = { joinCondition:function(nodeOptions) { return nodeOptions.cid === 1; } }

In this case only nodes with cid == 1 will be in the same cluster, I was wondering if it was possible to cluster all nodes based on their cid value within a single joinCondition or do I have to create a function for each cid possible values ?

Thomaash commented 3 years ago

Hi @AlexandreLedru,

network.cluster(…) creates a cluster. If you need to create multiple clusters, you have to call it for each one of them. The property nodeOptions.cid is actually not understood by Vis Network at all, you can use nodeOptions.cluster.name or Math.random() for that matter. Is there any particular reason why you don't want to call the method multiple times?

JJn9 commented 3 years ago

Hi @Thomaash ,

First, thanks for your answer, I'm actually developing a network map which has to represent stacks and its devices (switch, firewall, etc...) on stack click, I want it to be dynamic so when a new stack is added to the network I don't have to develop a joinCondition based on it's devices' stack_id, I'm currently working with Hasura/GraphQL to use real-time subscriptions to a database that contains all my network informations. Ideally I would like the Vis.js network to "listen" each devices' stack_id field and automatically cluster them all based on this id without having to hardcode nodeOptions.stack_id === 2 for example, I don't know if something like this is possible...

Thomaash commented 3 years ago

This isn't possible at the moment, network.cluster(…) is a one shot thing.

JJn9 commented 3 years ago

Ok, thanks ! :)

th3cr0w commented 3 years ago

I had similar scenario, maybe a bit simpler to execute:

network structure taken from DB, switches, wireless access points, firewalls ... Design idea was to have switch and all access points supported by it represented as cluster. Network of 100 switches and 1000 access points is too busy if everything is visible at once.

I had only 2 groups to look for so it might not help in your case but this is how it is working in my use case:

var switches = nodes.getIds({
  filter: function (item) {
    return (item.group == "switch");
  },
});

function clusterWAPs (switchid){
  network.clusterByConnection(switchid,{
    joinCondition: function(parentNodeOptions, childNodeOptions){
      return (childNodeOptions.group === "wap" || parentNodeOptions.group === "wap");
    },
...

}

switches.forEach((switchid, i) => {
  clusterWAPs(switchid);
});

get list of things to iterate over (that your cluster must have) and do clustering based on: nodeOptions.stack_id === iteration_item.stack_id

scenaristeur commented 3 years ago

Hi! perharps could help, here is my solution to build many clusters on https://scenaristeur.github.io/ipgs/ first a config_cid that list all my cids :

let cid_config = {
  // Standard
  1: { id: "help", label: "Help / Aide"},
  2: { id: "examples", label: "Examples", shape: 'star', color: '#7FD1B9'},
  //Vis
  5: { id: "networks", label: "Networks"},
  6: { id: "history", label: "Navigation History"},
  //Solid
  20: { id: "storage", label: "Storage"},
  21: { id: "profile", label: "User Profile"},
  22: { id: "friends", label: "Solid Friends"},
  //Data
  30: { id: "sources", label: "Data Sources"},
  // Types
  40: { id: "type", label: "Types"},
  41: { id: "literal", label: "Literals"},
  42: { id: "resource", label: "Resources"},
  43: { id: "actors", label: "Persons or Actors / Agents"},
}

then i get an array of all cids used in the network

with var cids = [...new Set(network.nodes.map(item => item.cid))].filter(Boolean);

filter(Boolean) is here to remove "undefined" when node has no cid (https://stackoverflow.com/questions/281264/remove-empty-elements-from-an-array-in-javascript)

Then i can apply clustering for each cid found even if it is not in the cid_config

 cids.forEach((cid) => {
      network.cluster({
        joinCondition: function (childOptions) {
          return childOptions.cid == cid;
        },
        clusterNodeProperties: {
          id: cid_config[cid] && cid_config[cid].id ? cid_config[cid].id : cid,
          borderWidth: 3,
          shape: cid_config[cid] && cid_config[cid].shape ? cid_config[cid].shape : "box",
          color: cid_config[cid] && cid_config[cid].color ? cid_config[cid].color : "#ECC046",
          label: cid_config[cid] &&cid_config[cid].label ? cid_config[cid].label : "no name group"
        },
      });
    });

I hope it can help as much as vis js helps me in my projects