All versions of this documentation
X

Sequential Layout


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; }
    #wrapper {
      position: absolute;
      top: 10px;
      right: 10px;
      z-index: 400;
      background: white;
      padding: 10px;
    }

    .control-bar {
      font-family: Helvetica, Arial, sans-serif;
      box-shadow: 0 1px 5px rgba(0,0,0,0.65);
      border-radius: 4px;
    }
    .control-bar label { display: block; }
    .concept {
      height: 10px;
      width: 10px;
      background-color: #2ca02c;
      border-radius: 50%;
      display: inline-block;
    }
    .table {
      height: 10px;
      width: 10px;
      background-color: #ff9896;
      border-radius: 50%;
      display: inline-block;
    }
  </style>
</head>
<body>
  <div id="graph-container"></div>
  <form id="wrapper" class="control-bar">
    <p>How to order the sequence:</p>
    <label><input type="radio" name="layering" checked value="0" /> Auto</label>
    <label><input type="radio" name="layering" value="2" /> One color per layer</label>
    <label><input type="radio" name="layering" value="1" /> <span class="concept"></span> Concept &rarr; <span class="table"></span> Table</label>
  </form>

<script>
'use strict';
var ogma = new Ogma({
  container: 'graph-container',
});

var defaultLayoutOptions = {
  direction: 'TB',           // Direction of the layout. Can be TB, BT, LR, or RL,
                            // where T = top, B = bottom, L = left, and R = right.
  duration: 300,           // Duration of the animation
  nodeDistance:  15,       // Number of pixels that separate nodes horizontally in the layout.
  levelDistance: 50,       // Number of pixels between each layer in the layout.
};

ogma.parse.jsonFromUrl('files/data-flow.json')
  .then(function (graph) { return ogma.setGraph(graph); })
  .then(function () { return ogma.view.locateGraph(); })
  .then(function () {
    return runLayout(defaultLayoutOptions)
  });

function runLayout (options) {
  ogma.layouts.sequential(options)
    .then(function () {
      ogma.view.locateGraph({
        easing: 'linear',
        duration: 300
      });
    });
}

var form = document.getElementById('wrapper');

form.addEventListener('change', function () { setTimeout(onChange); });

function onChange () {
  var mode = Number(Array.prototype.filter.call(form['layering'], function(input) {
    return input.checked;
  })[0].value);

  var modes = {
    // you can mix layering and roots/sinks definitions
    1: {'Concept': 0, 'Table': 'sink'},
    // or control the layer by layer as well
    2: {'Concept': 0, 'Subject': 1, 'Area': 2, 'DataElement': 3, 'DataOwner': 4, 'DataSteward': 5, 'Column': 6, 'Table': 7, 'DQMetric': 8, 'Database': 9, 'DQDimension': 10, 'DataPolicy': 11, 'DataPrinciple': 12}
  };

  ogma.getNodes().fillData('layer', null);

  var sinks = [];

  // check if it's a supported mode
  if(mode in modes){
    var customLogic = modes[mode];

    // pick the sinks first
    sinks = ogma.getNodes().filter(function(node){
      var category = node.getData('categories')[0];
      return customLogic[category] === 'sink';
    });

    // now set the custom layering
    ogma.getNodes().forEach(function(node){
      var category = node.getData('categories')[0];

      var layer = customLogic[category];

      if(typeof layer === 'number'){
        // save the layer in the node data
        node.setData('layer', layer);
      }
    });
  }

  // create fresh new options
  var newOptions = {};
  for( var prop in defaultLayoutOptions){
    newOptions[prop] = defaultLayoutOptions[prop];
  }
  // save the sinks in the layout options
  newOptions.sinks = sinks;

  runLayout(newOptions);
}

</script>
</body>
</html>