Skip to content
  1. Examples

Remove nodes overlap

This example shows how to use the force layout to remove overlapping between the nodes, without destroying the existing layout by setting all forces to 0 but elasticity.

ts
import Ogma from '@linkurious/ogma';

const ogma = new Ogma({
  container: 'graph-container'
});

const getRandomColor = () => {
  const letters = '0123456789ABCDEF';
  let color = '#';
  for (let i = 0; i < 6; i++) {
    color += letters[Math.floor(Math.random() * 16)];
  }
  return color;
};

// 1. Preparation

// generate random graph
ogma.generate
  .randomTree({ nodes: 30 })
  .then(g => {
    // colorize and assign random sizes to the nodes
    g.nodes.forEach(node => {
      node.attributes!.radius = 5 + Math.random() * 10;
      node.attributes!.color = getRandomColor();
    });
    return g;
  })
  // add graph to the visualisation
  .then(g => ogma.addGraph(g))
  // run the layout and center view
  .then(() => ogma.layouts.force({ locate: true, duration: 0 }))
  // randomize leafs around the parent nodes
  .then(() => {
    const leafs = ogma.getNodes().filter(n => n.getDegree() === 1);
    leafs.forEach(leaf => {
      const pos = leaf.getAdjacentNodes().get(0).getPosition();
      leaf.setAttributes({
        x: pos.x + Math.random() * 10 - 5,
        y: pos.y + Math.random() * 10 - 5
      });
    });
  });

// 2. Remove overlap
const removeOverlap = () =>
  ogma.layouts.force({
    gravity: 0,
    charge: 0,
    edgeStrength: 0,
    elasticity: 0.02
  });

document.getElementById('remove-overlap')!.addEventListener('click', evt => {
  evt.preventDefault();
  removeOverlap();
});
html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
      rel="stylesheet"
    />
    <link type="text/css" rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div id="graph-container"></div>
    <div class="panel"><button id="remove-overlap">Remove overlap</button></div>
    <script type="module" src="index.ts"></script>
  </body>
</html>
css
html,
body {
  font-family: 'IBM Plex Sans', sans-serif;
}

:root {
  --base-color: #4999f7;
  --active-color: var(--base-color);
  --gray: #d9d9d9;
  --white: #ffffff;
  --lighter-gray: #f4f4f4;
  --light-gray: #e6e6e6;
  --inactive-color: #cee5ff;
  --group-color: #525fe1;
  --group-inactive-color: #c2c8ff;
  --selection-color: #04ddcb;
  --darker-gray: #b6b6b6;
  --dark-gray: #555;
  --dark-color: #3a3535;
  --edge-color: var(--dark-color);
  --border-radius: 5px;
  --button-border-radius: var(--border-radius);
  --edge-inactive-color: var(--light-gray);
  --button-background-color: #ffffff;
  --shadow-color: rgba(0, 0, 0, 0.25);
  --shadow-hover-color: rgba(0, 0, 0, 0.5);
  --button-shadow: 0 0 4px var(--shadow-color);
  --button-shadow-hover: 0 0 4px var(--shadow-hover-color);
  --button-icon-color: #000000;
  --button-icon-hover-color: var(--active-color);
  --font: 'IBM Plex Sans', sans-serif;
}

#graph-container {
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  position: absolute;
  margin: 0;
  overflow: hidden;
}

.ui {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 0.5em;
}

#custom-group-btn {
  top: 40px;
}

.panel {
  background: var(--button-background-color);
  border-radius: var(--button-border-radius);
  box-shadow: var(--button-shadow);
  position: absolute;
  top: 2em;
  right: 2em;
  padding: 1em;
}

.panel h2 {
  text-transform: uppercase;
  font-weight: 400;
  font-size: 14px;
  margin: 0;
}

.panel button {
  background: var(--button-background-color);
  border: none;
  font-family: var(--font);
  border-radius: var(--button-border-radius);
  border-color: var(--shadow-color);
  padding: 5px 10px;
  cursor: pointer;
  width: 100%;
  color: var(--dark-gray);
  border: 1px solid var(--light-gray);
}

.panel button:hover {
  background: var(--lighter-gray);
  border: 1px solid var(--darker-gray);
}

.panel button[disabled] {
  color: var(--light-gray);
  border: 1px solid var(--light-gray);
  background-color: var(--lighter-gray);
}