All versions of this documentation
X

Group nodes


Open in a new window.
          <!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="../build/ogma.min.js"></script>
  <style>
    #graph-container { top: 0; bottom: 0; left: 0; right: 0; position: absolute; margin: 0; overflow: hidden; }
    button { position: absolute; top:10px; left: 10px; }
  </style>
</head>
<body>
  <div id="graph-container"></div>
  <button id="group-btn" onclick="toggleGroup()">Group nodes</button>
</body>
<script>
  'use strict';

  var LOCATION = ['France', 'Russia', 'USA'];

  var FLAGS = {
    'France': 'flags/fr.svg',
    'Russia': 'flags/ru.svg',
    'USA': 'flags/us.svg',
  };

  var duration = 300;

  function randomGraph(N, E) {
    var g = {nodes:[], edges:[]};

    for (var i = 0; i < N; i++) {
      var location = LOCATION[(Math.random() * LOCATION.length | 0)];
      g.nodes.push({
        id: 'n' + i,
        attributes: {
          x: Math.random() * 100,
          y: Math.random() * 100,
          text: 'Node ' + i + ' - ' + location,
          image: {
            url: FLAGS[location]
          }
        },
        data: {
          location: location
        }
      });
    }

    for (var i = 0; i < E; i++) {
      g.edges.push({
        id: 'e' + i,
        source: 'n' + (Math.random() * N | 0),
        target: 'n' + (Math.random() * N | 0)
      });
    }

    return g;
  }

  var g = randomGraph(10, 10);

  var ogma = new Ogma({
    graph: g,
    container: 'graph-container'
  });

  ogma.styles.addNodeRule({
    innerStroke: {
      color: '#999'
    },
    badges: {
      bottomRight: {
        stroke: {
          color: '#999'
        }
      }
    }
  });

  var transformation = null;

  function toggleGroup() {
    if (!transformation) {
      // Groups all active nodes that have the same `location` data property
      // into a single node that will have the combined size of all nodes,
      // and be at the center of the grouped nodes.
      transformation = ogma.transformations.addNodeGrouping({
        groupIdFunction: function (node) {
          return node.getData('location');
        },
        nodeGenerator: function (nodes, groupId) {
          return {
            id: 'special group ' + groupId,
            data: {
              groupId: groupId,
              subNodes: nodes
            },
            attributes: {
              radius: nodes.reduce(function (acc, node) {
                return acc + node.getAttribute('radius');
              }, 0),
              text: groupId,
              badges: {
                bottomRight: {
                  text: nodes.size
                }
              },
              image: FLAGS[groupId]
            }
          };
        },
        duration: duration
      });
    } else {
      // Toggle the grouping
      transformation.toggle(duration);
    }

    // After the next transformation update takes place, update the button content
    ogma.transformations.afterNextUpdate().then(function () {
      var buttonText = transformation.isEnabled() ? "Ungroup nodes" : "Group nodes";

      document.getElementById('group-btn').textContent = buttonText;
    });
  }

  ogma.events.onClick(function(evt) {
    if (evt.target && evt.target.isNode) {
      var subNodes = evt.target.getData('subNodes');

      console.log(subNodes && subNodes.getId());
    }
  });
</script>
</html>