Skip to content
  1. Examples

Animate to bounds

This example shows how to animate the camera to focus on a specific cluster. It uses the moveToBounds method to automatically compute the bouding box of the cluster and animate the camera to focus on it.

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

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

ogma.styles.setSelectedNodeAttributes({
  color: '#1499ff',
  innerStroke: {
    width: 1
  },
  outerStroke: {
    color: '#1499ff'
  }
});

function zoomToRandomHub() {
  // get the list of big hubs
  const nodes = ogma.getNodes();
  const highDegreeNodes = ogma.getNodes().filter(n => n.getDegree() > 15);
  const root = highDegreeNodes.get(
    Math.floor(Math.random() * highDegreeNodes.size)
  );

  // get a random hub
  const randomHub = root
    .getAdjacentNodes()
    .filter(n => n.getDegree() === 1)
    .concat(root.toList());

  // highlight the hub
  nodes.setSelected(false);
  randomHub.setSelected(true);

  // animate to it
  return ogma.view.moveToBounds(randomHub.getBoundingBox(), {
    easing: (document.getElementById('easing')! as HTMLInputElement)
      .value as Easing
  });
}

ogma.generate
  .barabasiAlbert({
    nodes: 1600,
    m0: 10,
    m: 1
  })
  .then(ogma.setGraph)
  .then(() =>
    ogma.layouts.force({
      autoStop: true,
      gravity: 0.001,
      duration: 0
    })
  )
  .then(() => ogma.view.locateGraph())
  .then(() => setTimeout(startAnimation, 500));

const playButton = document.getElementById('play-button') as HTMLInputElement;
const stepButton = document.getElementById('step-button') as HTMLButtonElement;

let timer = 0;
let animating = playButton.checked;

function animate() {
  if (animating) {
    zoomToRandomHub().then(() => {
      // @ts-expect-error
      timer = setTimeout(animate, 1000);
    });
  }
}

function startAnimation() {
  if (!animating) {
    animating = true;
    animate();
    stepButton.setAttribute('disabled', 'disabled');
  } else {
    clearTimeout(timer);
    animating = false;
    stepButton.removeAttribute('disabled');
  }
}

function step() {
  zoomToRandomHub();
}

playButton.addEventListener('click', startAnimation);
stepButton.addEventListener('click', step);

startAnimation();
html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <link
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/solid.min.css"
      rel="stylesheet"
    />
    <link
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/fontawesome.min.css"
      rel="stylesheet"
    />
    <link type="text/css" rel="stylesheet" href="styles.css" />
  </head>

  <body>
    <div id="graph-container"></div>
    <div id="controls">
      <label
        >Easing
        <select id="easing">
          <option value="quadraticOut">quadraticOut</option>
          <option value="linear">linear</option>
          <option value="quadraticIn">quadraticIn</option>
          <option value="quadraticInOut">quadraticInOut</option>
          <option value="cubicIn">cubicIn</option>
          <option value="cubicOut">cubicOut</option>
          <option value="cubicInOut">cubicInOut</option>
        </select>
      </label>
      <p>
        <label><input type="checkbox" id="play-button" checked />Repeat</label>
        <button id="step-button" disabled>
          <i class="fas fa-step-forward"></i>
        </button>
      </p>
    </div>
    <script type="module" src="index.ts"></script>
  </body>
</html>
css
#graph-container {
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  position: absolute;
  margin: 0;
  overflow: hidden;
}

#controls {
  font-family: Georgia, 'Times New Roman', Times, serif;
  position: absolute;
  background: #ffffff;
  padding: 15px;
  top: 20px;
  right: 20px;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
  border-radius: 5px;
}