Skip to content
  1. Examples

Force layout auto-stop

This example shows how to use the autostop option, which makes the force layout much faster on graphs already layed out or partially layed out. It is usefull when adding or removing nodes and edges to the graph.

ts
import Ogma, { LocateOptions, RawGraph } from '@linkurious/ogma';

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

// generate random graph
Ogma.parse
  .jsonFromUrl('files/relativity.json')
  .then(graph => {
    // add some disconnected components and 'orphan' nodes
    graph.nodes.forEach(node => {
      delete node.attributes;
    });
    return ogma.setGraph(graph);
  })
  .then(() => ogma.view.locateGraph({ padding: 100 }))
  .then(() => run({ padding: padding }));

const form = document.querySelector<HTMLFormElement>('#params')!;
let callTimer = 0;

let charge: number, gravity: number, edgeStrength: number, autoStop: boolean;
function update() {
  charge = parseFloat(form['charge'].value);
  gravity = parseFloat(form['gravity'].value);
  edgeStrength = parseFloat(form['edgeStrength'].value);
  autoStop = form['auto-stop'].checked;

  document.getElementById('charge-value')!.innerHTML = charge.toString();
  document.getElementById('gravity-value')!.innerHTML = gravity.toString();
  document.getElementById('edgeStrength-value')!.innerHTML =
    edgeStrength.toString();
}

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

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

function run(locate?: LocateOptions) {
  const start = Date.now();
  return ogma.layouts
    .force({
      charge: charge,
      gravity: gravity,
      locate: locate,
      duration: animationDuration,
      edgeStrength: edgeStrength,
      autoStop: autoStop
    })
    .then(() => {
      const duration = Date.now() - start;
      document.getElementById('time')!.innerHTML =
        'done in ' + ((duration - animationDuration) / 1000).toFixed(2) + 's';
    });
}

update();

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

function randomize() {
  ogma.getNodes().forEach(node => {
    node.setAttributes({
      x: Math.random() * 150,
      y: Math.random() * 150
    });
  });
}
html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <link type="text/css" rel="stylesheet" href="styles.css" />
  </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="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>
      <label>
        <span id="edgeStrength-value" class="value">0.75</span>
        <input
          type="range"
          min="0.0"
          max="30"
          value="0.75"
          name="edgeStrength"
          step="0.25"
        />
        Edge strength
      </label>
      <label>
        <input type="checkbox" checked name="auto-stop" /> Auto stop
      </label>
      <p>
        <button type="button" id="randomize">Randomize</button
        ><button type="button" id="run">Run</button>
      </p>
      <div id="time"></div>
    </form>
    <script type="module" src="index.ts"></script>
  </body>
</html>
css
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;
}

#time {
  text-align: center;
  font-family: Georgia, 'Times New Roman', Times, serif;
}