Push nodes to desired layers

Dear Folks,

In radial layout chart, can we push particular node(s) to specific layer and relate to the other nodes, please help me to get this done. we are ready to purchase if it can be done.

Yes, I think that can be implemented easily. I’ll try it when I get some free time later this morning or this afternoon.
EDIT: Well, I’m not sure what you want to do. It seems to me that if you are going to assign the layers for each node/vertex it isn’t clear how the link relationships between the nodes affects the layout.

For example i have 100 users , i have to decide that they should be in which layer(circle) if i have layer1, 2,… post pushing to the layers need to establish the relationship between them. Hope it explains my requirements. Kindly update as quickly as possible

Oh, so are you saying that the links between the nodes should not have any bearing on the positioning of the nodes, as long as the nodes are in the specified layers? So you will guarantee that all nodes have their layer specified?

I’ll work on this tomorrow.

Yes, each user can be placed in any of layer but he/ she may or may not have relation with other user

For example
user1 in layer1
User2 in layer2
User3 in layer3

User1 relates to user3
It means for user2 it is not necessary to have relation but he should present in layer2 . This means all users will be present in any layer but relation is optional

If the layout does not need to consider links between nodes in different layers, then perhaps the easiest solution is to use multiple concentric CircularLayouts: Double Circle

We need links between nodes as well, kindly confirm can it be done?

Each CircularLayout tries to reduce the number of link crossings, but it will ignore links between layers.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Concentric Layout</title>
  <meta name="description" content="Arrange nodes into concentric circles using CircularLayout." />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
    function ConcentricLayout() {
      go.Layout.call(this);
    }
    go.Diagram.inherit(ConcentricLayout, go.Layout);

    ConcentricLayout.prototype.doLayout = function(coll) {
      var $ = go.GraphObject.make;  // for conciseness in defining templates
      this.diagram.startTransaction("Multi Circle Layout");
      var coll = this.collectParts(coll);

      // assume all circles will be centered at the origin
      this.nodesByLayer(coll, 0).each(function(n) { n.location = new go.Point(0, 0); });

      var radius = 100;
      var layer = 1;
      var nodes = null;
      while (nodes = this.nodesByLayer(coll, layer), nodes.count > 0) {
        var layout =
          $(go.CircularLayout,
            {
              radius: radius,
              arrangement: go.CircularLayout.ConstantAngle,
              spacing: NaN
            });
        layout.doLayout(nodes);
        // recenter at (0, 0)
        var cntr = layout.actualCenter;
        this.diagram.moveParts(nodes, new go.Point(-cntr.x, -cntr.y));
        // next layout uses a larger radius
        radius += 100;
        layer++;
      }

      this.diagram.commitTransaction("Multi Circle Layout");
    }

    ConcentricLayout.prototype.nodesByLayer = function(coll, layer) {
      var set = new go.Set(/*go.Node*/);
      coll.each(function(part) {
        if (part instanceof go.Node && part.data.layer === layer) set.add(part);
      });
      return set;
    }

    function init() {
      var $ = go.GraphObject.make;  // for conciseness in defining templates in this function

      myDiagram =
        $(go.Diagram, "myDiagramDiv",  // must be the ID or reference to div
          {
            layout: $(ConcentricLayout),
            initialAutoScale: go.Diagram.Uniform,
            "animationManager.isEnabled": false
          });

      myDiagram.nodeTemplate =
        $(go.Node, "Auto",
          { locationSpot: go.Spot.Center },
          $(go.Shape, "Circle",
            { fill: "gray", stroke: "#D8D8D8" },
            new go.Binding("fill", "color")),
          $(go.TextBlock,
            { margin: 5 },
            new go.Binding("text", "key"))
        );

      // create the model for the multiple circles
      var nodedata = [];
      // if you want a node in the center, set its layer: 0
      nodedata.push({ key: 0, layer: 0, color: "red" });
      for (var i = 0; i < 10; i++) nodedata.push({ key: nodedata.length, layer: 1, color: go.Brush.randomColor() });
      for (var i = 0; i < 20; i++) nodedata.push({ key: nodedata.length, layer: 2, color: go.Brush.randomColor() });
      for (var i = 0; i < 30; i++) nodedata.push({ key: nodedata.length, layer: 3, color: go.Brush.randomColor() });
      for (var i = 0; i < 40; i++) nodedata.push({ key: nodedata.length, layer: 4, color: go.Brush.randomColor() });

      var linkdata = [];
      for (var i = 0; i < nodedata.length-30; i++) {
        linkdata.push({ from: i, to: i + 20 + Math.floor(Math.random() * 10) });
      }
      myDiagram.model = new go.GraphLinksModel(nodedata, linkdata);
    }
  </script>
</head>
<body onload="init()">
<div id="sample">
  <div id="myDiagramDiv" style="background-color: white; border: solid 1px black; width: 100%; height: 700px"></div>
</div>
</body>
</html>

Hi,

Can we assign colors to each layer separately, kindly confirm.

Certainly. For example: Org Chart Editor

But since this layout is defined here rather than in the built-in TreeLayout, for you it is merely a matter of modifying the code. In this case I suggest that you modify the nodesByLayer method. You have a choice of modifying the Shape directly or using data Binding(s) and modifying the model.

Above examples are for setting color at node level, I need color for layer1, layer2… like this

Have you modified the nodesByLayer method to do what you want? What exactly is the problem that you are encountering?

Like in below image need circles drawn for each layer with colors

I could not get it how to modify nodesByLayer for drawing circles with colors, please send some sample code, Thanks for your patience and help.

image

Oh, I thought you were asking to change the colors of the nodes.
I can provide some example code later today when I get some free time.

ok, sure, my client is planning to purchase GoJs support once this implementation confirmed, and they wanted this to be a private discussion(our entire discussion on this topic).

Can we contact you via email, so that i can include my manager and others

Yes, send email to GoJS at our domain, nwoods.com.

I will still publish the code here, where other people could benefit from the solution.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Concentric Layout</title>
  <meta name="description" content="Arrange nodes into concentric circles using multiple CircularLayouts." />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
  <script src="go.js"></script>
  <script id="code">
    function ConcentricLayout() {
      go.Layout.call(this);
      // create a background grid Part consisting of concentric Circle Shapes
      this.colors = [];
      for (var i = 0; i < 10; i++) this.colors.push(go.Brush.mix("lightgreen", "blue", i/10));
      this.radius = 100;
      var back = new go.Part();
      back.layerName = "Grid";
      back.locationSpot = go.Spot.Center;
      back.location = new go.Point(0, 0);
      for (var i = this.colors.length-1; i >= 0; i--) {
        var shp = new go.Shape();
        shp.figure = "Circle";
        shp.fill = this.colors[i];
        shp.strokeWidth = 0;
        shp.desiredSize = new go.Size(i*this.radius*2+this.radius, i*this.radius*2+this.radius);
        var w = (this.colors.length-1-i)*this.radius;
        shp.position = new go.Point(w, w);
        back.add(shp);
      }
      this.backgroundShapes = back;
    }
    go.Diagram.inherit(ConcentricLayout, go.Layout);

    ConcentricLayout.prototype.doLayout = function(coll) {
      var $ = go.GraphObject.make;  // for conciseness in defining templates
      this.diagram.startTransaction("Multi Circle Layout");
      var coll = this.collectParts(coll);

      // assume all circles will be centered at the origin
      this.nodesByLayer(coll, 0).each(function(n) { n.location = new go.Point(0, 0); });

      var rad = this.radius;
      var layer = 1;
      var nodes = null;
      while (nodes = this.nodesByLayer(coll, layer), nodes.count > 0) {
        var layout =
          $(go.CircularLayout,
            {
              radius: rad,
              arrangement: go.CircularLayout.ConstantAngle,
              spacing: NaN
            });
        layout.doLayout(nodes);
        // recenter at (0, 0)
        var cntr = layout.actualCenter;
        this.diagram.moveParts(nodes, new go.Point(-cntr.x, -cntr.y));
        // next layout uses a larger radius
        rad += this.radius;
        layer++;
      }

      var list = new go.List(this.backgroundShapes.elements);
      for (var i = list.count-1; i >= 0 ; i--) {
        var shp = list.elt(i);
        shp.opacity = (i >= (list.count-layer)) ? 1.0 : 0.0;
      }
      if (this.backgroundShapes.diagram === null) {
        this.diagram.add(this.backgroundShapes);
      }
      this.diagram.commitTransaction("Multi Circle Layout");
    }

    ConcentricLayout.prototype.nodesByLayer = function(coll, layer) {
      var set = new go.Set(/*go.Node*/);
      coll.each(function(part) {
        if (part instanceof go.Node && part.data.layer === layer) set.add(part);
      });
      return set;
    }


    function init() {
      var $ = go.GraphObject.make;  // for conciseness in defining templates in this function

      myDiagram =
        $(go.Diagram, "myDiagramDiv",  // must be the ID or reference to div
          {
            layout: $(ConcentricLayout),
            initialAutoScale: go.Diagram.Uniform,
            "animationManager.isEnabled": false
          });

      myDiagram.nodeTemplate =
        $(go.Node, "Auto",
          { locationSpot: go.Spot.Center },
          $(go.Shape, "Circle",
            { fill: "gray", stroke: "#D8D8D8" },
            new go.Binding("fill", "color")),
          $(go.TextBlock,
            { margin: 5 },
            new go.Binding("text", "key"))
        );

      // create the model for the multiple circles
      var nodedata = [];
      // if you want a node in the center, set its layer: 0
      nodedata.push({ key: 0, layer: 0, color: "red" });
      for (var i = 0; i < 10; i++) nodedata.push({ key: nodedata.length, layer: 1, color: go.Brush.randomColor() });
      for (var i = 0; i < 20; i++) nodedata.push({ key: nodedata.length, layer: 2, color: go.Brush.randomColor() });
      for (var i = 0; i < 30; i++) nodedata.push({ key: nodedata.length, layer: 3, color: go.Brush.randomColor() });
      for (var i = 0; i < 40; i++) nodedata.push({ key: nodedata.length, layer: 4, color: go.Brush.randomColor() });

      var linkdata = [];
      for (var i = 0; i < nodedata.length-40; i++) {
        linkdata.push({ from: i, to: i + 20 + Math.floor(Math.random() * 20) });
      }
      myDiagram.model = new go.GraphLinksModel(nodedata, linkdata);
    }
  </script>
</head>
<body onload="init()">
<div id="sample">
  <div id="myDiagramDiv" style="background-color: white; border: solid 1px black; width: 100%; height: 700px"></div>
</div>
</body>
</html>

Thanks Walter, this is what exactly we wanted, thanks so much for your patience and support, post completing the demo with my client we will contact Northwoods Software to purchase licence.

Hi,
we encountered an issue is that if there is only one node in layer 1 or 2 or 3… the single node is placing at center, please help.