All versions of this documentation
X

Force layout

New general-purpose force-directed layout. charge defines the strength with which the nodes repel each other. gravity stands for the global force, pulling the graph to its mass center. elasticity defines how the nodes collide with each other.

Open in a new window.
          <!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="../build/ogma.min.js"></script>
  <style>
    html, body { font-family: Helvetica, Arial, Helvetica, sans-serif; padding: 0; margin: 0; }
    #graph-container { top: 0; bottom: 0; left: 0; right: 0; position: absolute; margin: 0; overflow: hidden; }
    .control { position: absolute; top: 20px; right: 20px; padding: 10px; border-radius: 5px; box-shadow: 0 0 5px rgba(0,0,0,0.5); background: #fff; }
    .control label { display: block; padding: 5px 0; }
    .control p { text-align: center; }
    .control .value { width: 50px; display: inline-block; font-family: Georgia, 'Times New Roman', Times, serif; font-weight: bold; }
  </style>
</head>
<body>
  <div id="graph-container"></div>
  <form class="control" id="params">
    <label>
      <span id="charge-value" class="value">5</span>
      <input type="range" min="0.5" max="50" value="5" name="charge" step="0.5" /> Charge
    </label>
    <label>
      <span id="elasticity-value" class="value">0.9</span>
      <input type="range" min="0" max="1.0" value="0.9" name="elasticity" step="0.01"/> Elasticity
    </label>
    <label>
      <span id="gravity-value" class="value">0.01</span>
      <input type="range" min="0.005" max="0.15" value="0.01" name="gravity" step="0.005" /> Gravity
    </label>
    <p><button type="button" id="randomize">Randomize</button><button type="button" id="run">Run</button></p>
  </form>

<script>
'use strict';

var ogma = new Ogma({
  container: 'graph-container',
  options: { interactions: { drag: { enabled: false }}}
});
var padding = 100;
// disable node dragging
//ogma.setOptions({ interactions: { drag: { enabled: false }}});

// generate random graph
ogma.generate.barabasiAlbert({
  nodes : 500,
  m0: 10,
  m: 1
}).then(function(graph) {
  // add some disconnected components and 'orphan' nodes
  graph.nodes.forEach(function (node) { delete node.attributes; });
  addSmallComponents(graph, Math.floor(Math.log(graph.nodes.length)), 5);
  addLooseNodes(graph, Math.floor(graph.nodes.length / 3));
  ogma.setGraph(graph);
  return ogma.view.locateGraph({ padding: 100 });
}).then(function() {
  return run({ padding: padding });
});


var form = document.querySelector('#params');
var callTimer = 0;

var charge, gravity, elasticity;
function update () {
  charge = parseFloat(form['charge'].value);
  gravity = parseFloat(form['gravity'].value);
  elasticity = parseFloat(form['elasticity'].value);

  document.getElementById('charge-value').innerHTML = charge;
  document.getElementById('gravity-value').innerHTML = gravity;
  document.getElementById('elasticity-value').innerHTML = elasticity;
}

form.addEventListener('input', function () {
  clearTimeout(callTimer);
  update();
  callTimer = setTimeout(run, 100);
}, true);

document.querySelector('#randomize').addEventListener('click', randomize);
document.querySelector('#run').addEventListener('click', function () { run(); });

function run (locate) {
  return ogma.layouts.force({
    //useWebWorker: false,
    charge: charge,
    gravity: gravity,
    elasticity: elasticity,
    locate: locate
  });
}

update();

function addLooseNodes (graph, n) {
  var baseId = graph.nodes.length;
  for (var i = 0; i < n; i++) {
    graph.nodes.push({ id: (baseId + i) });
  }
}


function addSmallComponents (graph, n, m) {
  for (var i = 0; i < n; i++) {
    var baseId = graph.nodes.length;
    for (var j = 0; j < m + 1; j++) {
      graph.nodes.push({ id: (baseId + j)});
    }
    for (var k = 1; k < m + 1; k++) {
      graph.edges.push({ source: baseId, target: baseId + k });
    }
  }
}


function randomize () {
  ogma.getNodes().forEach(function (node) {
    node.setAttributes({
      x: Math.random() * 150,
      y: Math.random() * 150
    });
  });
}

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