Skip to content
  1. Examples

Timeline with node lifespans

This is the example of nodes with different lifespans in timeline mode.

ts
import Ogma from '@linkurious/ogma';
import { Controller as TimelinePlugin } from '@linkurious/ogma-timeline-plugin';

const ogma = new Ogma({
  container: 'graph-container'
});
ogma.styles.addNodeRule({
  innerStroke: {
    color: '#555',
    scalingMethod: 'fixed',
    width: 1
  }
});
const range = Date.now() - new Date('August 19, 1975 23:15:30').getTime();
Ogma.parse
  .gexfFromUrl('files/arctic.gexf')
  .then(graph => {
    graph.nodes.forEach((node, i) => {
      // add a random date to the node
      const start = Date.now() - Math.random() * range;
      const end = start + Math.random() * range;
      node.data = { start, end };
    });
    return ogma.setGraph(
      {
        nodes: graph.nodes.slice(50, 100),
        edges: graph.edges
      },
      { ignoreInvalid: true }
    );
  })
  .then(() => {
    const container = document.getElementById('timeline');
    const timelinePlugin = new TimelinePlugin(ogma, container, {
      minTime: new Date('January 1, 1975 00:00:00').getTime(),
      maxTime: new Date('January 1, 2022 00:00:00').getTime(),
      timeBars: [
        new Date('January 1, 1975 00:00:00'),
        new Date('January 1, 2025 00:00:00')
      ],
      barchart: {
        nodeGroupIdFunction: node => node.getData('nodeType')
      },
      timeline: {
        nodeGroupIdFunction: node => node.getData('nodeType')
      }
    });

    let isSelecting = false;
    timelinePlugin.on('select', ({ nodes, edges }) => {
      isSelecting = true;
      ogma.getNodes().setSelected(false);
      ogma.getEdges().setSelected(false);

      if (nodes) {
        nodes.setSelected(true);
      }
      if (edges) {
        edges.setSelected(true);
      }
      isSelecting = false;
    });
    ogma.events.on(
      ['nodesSelected', 'edgesSelected', 'nodesUnselected', 'edgesUnselected'],
      () => {
        if (isSelecting) return;
        timelinePlugin.setSelection({
          nodes: ogma.getSelectedNodes(),
          edges: ogma.getSelectedEdges()
        });
      }
    );

    const filter = ogma.transformations.addNodeFilter({
      criteria: node => {
        return timelinePlugin.filteredNodes.has(node.getId());
      }
    });
    //Hook it to the timeline events
    timelinePlugin.on('timechange', () => {
      filter.refresh();
    });
  });
html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <link
      href="https://cdn.jsdelivr.net/npm/vis-timeline@latest/styles/vis-timeline-graph2d.min.css"
      rel="stylesheet"
      type="text/css"
    />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@linkurious/ogma-timeline-plugin@latest/dist/style.css"
    />
    <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=Roboto:wght@300&display=swap"
      rel="stylesheet"
    />
    <link type="text/css" rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div id="graph-container"></div>
    <div id="timeline"></div>
    <script src="index.ts" type="module"></script>
  </body>
</html>
css
body {
  display: grid;
  grid-template-rows: auto 33%;
  height: 100vh;
  margin: 0;
  padding: 0;
}
#timeline > div {
  height: 100%;
}
json
{
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@linkurious/ogma": "^5.2.3",
    "vis-data": "7.1.16",
    "vis-timeline": "7.7.2",
    "leaflet": "1.9.4",
    "@linkurious/ogma-timeline-plugin": "0.2.15"
  }
}