All versions of this documentation
X

Visual grouping


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;
    }

    #custom-group-btn {
      top: 40px;
    }
  </style>
</head>

<body>
  <div id="graph-container"></div>
  <button id="group-btn" onclick="toggleGroup()">Group by country</button>
  <button id="custom-group-btn" onclick="toggleGroup2()">Group France & Brazil</button>
</body>
<script>
  'use strict';

  var FLAGS = {
    'France': 'flags/fr.svg',
    'Japan': 'flags/jp.svg',
    'USA': 'flags/us.svg',
    'Brazil': 'flags/br.svg'
  };

  var ogma = new Ogma({
    container: 'graph-container'
  });
  ogma.styles.setHoveredNodeAttributes({ outline: null });
  ogma.styles.setSelectedNodeAttributes({ outline: null });


  ogma.parse.jsonFromUrl('files/countries.json')
    .then(function (graph) { return ogma.addGraph(graph); })
    .then(function () { return ogma.layouts.force({ locate: true }); });

  ogma.styles.addNodeRule({
    innerStroke: { color: '#555' },
    image: {
      url: function (node) { return FLAGS[node.getData('location')]; },
      minVisibleSize: 0,
    },
    opacity: function (node) { return node.getData('open') ? 0.32 : undefined; },
    badges: {
      bottomRight: { stroke: { color: '#999' } }
    }
  });

  var byCountry = null;
  var customGroup = null;
  // UI buttons
  var buttonFranceBrazilOnly = document.getElementById('custom-group-btn');
  var buttonGroupAll = document.getElementById('group-btn');

  buttonFranceBrazilOnly.disabled = true;

  function toggleGroup() {
    // In case this is the first time, create the transformation, but do not trigger it yet
    if (!byCountry) {
      // 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.
      byCountry = ogma.transformations.addNodeGrouping({
        groupIdFunction: function (node) {
          return node.getData('location');
        },
        nodeGenerator: function (nodes, country) {
          var isVisible = country !== 'Japan';
          return {
            id: 'special group ' + country,
            data: {
              country: country,
              open: isVisible
            },
            attributes: {
              text: country,
              // fixed radius for the nodes with hidden contents
              radius: isVisible ? undefined : 20,
              image: FLAGS[country]
            }
          };
        },
        showContents: function (node) {
          return node.getData('open');
        },
        onCreated: function (metaNode, visible, subNodes, subEdges) {
          if (visible) {
            return ogma.layouts.force({ nodes: subNodes });
          }
        },
        duration: 300,
        enabled: false
      });
    }
    // Toggle the grouping transformation now
    byCountry.toggle().then(function () {
      var buttonText = byCountry.isEnabled()
        ? "Ungroup by country"
        : "Group by country";

      buttonGroupAll.textContent = buttonText;
      buttonFranceBrazilOnly.disabled = !byCountry.isEnabled();

      return ogma.layouts.force();
    });

  }

  function toggleGroup2() {
    // In case this is the first time, create the transformation, but do not trigger it yet
    if (!customGroup) {
      customGroup = ogma.transformations.addNodeGrouping({
        groupIdFunction: function (node) {
          var id = node.getData('country');
          if (id === 'France' || id === 'Brazil') return 'Level 2';
          return undefined;
        },
        nodeGenerator: function (nodes, country) {
          return {
            id: 'special group ' + country,
            data: {
              country: country
            },
            attributes: {
              text: country,
              opacity: 0.32
            }
          };
        },
        // can be a function as well
        showContents: true,
        enabled: false,
        onCreated: function (metaNode, visible, subNodes, subEdges) {
          // do nothing here, in fact, this callback can be omitted then
        }
      });
    }

    // Toggle the grouping
    customGroup.toggle().then(function () {
      var buttonText = customGroup.isEnabled()
        ? "Ungroup France & Brazil"
        : "Group France & Brazil";

      buttonFranceBrazilOnly.textContent = buttonText;

      return ogma.layouts.force();
    });
  }

  ogma.events.onClick(function (evt) {
    var target = evt.target;
    if (target && target.isNode && target.isVirtual()) {
      console.log('sub nodes', target.getSubNodes().getId());
    }
  });

  ogma.events.onDoubleClick(function (evt) {
    var target = evt.target;
    if (target && target.isNode && target.isVirtual()) {
      var country = target.getData('country');
      target.setData('open', !target.getData('open'));
      byCountry.refresh();
    }
  });

</script>

</html>