Skip to content
  1. Examples

Group edges

This example shows how to group parrallel edges by using the edgeGrouping transformation.

ts
import Ogma, { Color, EdgeGrouping } from '@linkurious/ogma';

const NB_EDGES = 10;
const COUNTRY = ['France', 'Russia'] as const;
type Country = (typeof COUNTRY)[number];

type NodeData = {};
type EdgeData = { country: Country };

const ogma = new Ogma<NodeData, EdgeData>({
  container: 'graph-container'
});

const COLORS: Record<Country, Color> = {
  France: '#de1d4d',
  Russia: '#1d60de'
};

ogma.addNodes([
  { id: 'n0', attributes: { x: -50, y: -50 } },
  { id: 'n1', attributes: { x: 50, y: 50 } }
]);

ogma.styles.addEdgeRule({
  color: edge => COLORS[edge.getData('country')] || 'grey'
});

ogma.view.locateGraph();

for (let i = 0; i < NB_EDGES; i++) {
  const country = COUNTRY[(Math.random() * COUNTRY.length) | 0];
  ogma.addEdge({
    id: 'e' + i,
    source: 'n0',
    target: 'n1',
    attributes: {
      text: country,
      width: 2
    },
    data: { country }
  });
}

let transformation: EdgeGrouping<EdgeData, NodeData> | null = null;

document.getElementById('group-btn')!.addEventListener('click', () => {
  const duration = (document.getElementById('animation') as HTMLInputElement)
    .checked
    ? 500
    : 0;
  if (!transformation) {
    // Groups all parallel edges that have the same data.country property
    // into meta-edges which the size is the sum of every edge and
    // the text is the content of data.country:
    transformation = ogma.transformations.addEdgeGrouping({
      groupIdFunction: edge => edge.getData('country'),
      generator: (edges, groupId) => ({
        data: {
          subEdges: edges.getId(),
          country: edges.getData('country')[0]
        },
        attributes: {
          width: edges.reduce((width, edge) => {
            return Number(edge.getAttribute('width')) + width;
          }, 0),
          text: groupId
        }
      }),
      duration
    });
  } else {
    transformation.toggle(duration);
  }

  // After the next transformation update takes place, update the button content
  ogma.transformations.afterNextUpdate().then(() => {
    const buttonText = transformation?.isEnabled()
      ? 'Ungroup edges'
      : 'Group edges';

    document.getElementById('group-btn')!.textContent = buttonText;
  });
});

ogma.events.on('click', evt => {
  if (evt.target && !evt.target.isNode) {
    const subEdges = evt.target.getData('subEdges');
    if (subEdges) console.log('sub edges:', subEdges);
  }
});
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>
    <div class="controls">
      <button id="group-btn">Group edges</button>
      <label for="animation"
        >Animated: <input id="animation" type="checkbox" checked
      /></label>
    </div>
    <script src="./index.ts"></script>
  </body>
</html>
css
#graph-container {
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  position: absolute;
  margin: 0;
  overflow: hidden;
}
.controls {
  position: absolute;
  top: 10px;
  left: 10px;
  background: #fff;
  padding: 10px;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.controls label {
  display: block;
  margin-top: 10px;
}