//
//     Copyright © 2011-2025 Cambridge Intelligence Limited.
//     All rights reserved.
//
//     Sample Code
//!    Use dependency analysis to find relations in hierarchies.
import KeyLines from "keylines";
import { chartData } from "./dependencies-data.js";

// declaring global vars
let chart;

function getOrientation() {
  const selection = chart.selection();
  if (selection.length > 0) {
    const item = chart.getItem(selection[0]);
    if (item.type === "node" && item.d.type === "person") {
      return "down";
    }
  }
  return "up";
}

function findConnected(ids) {
  // merge all the distances: we do not care about metrics here, but only if a node is reachable
  let items = [];
  const list = chart.getItem(ids);

  list.forEach((item) => {
    if (item.type === "node") {
      const direction = item.d.type === "company" ? "to" : "from";
      // merge results
      items = items.concat(
        Object.keys(chart.graph().distances(item.id, { direction }))
      );
    }
  });

  return items;
}

async function filterConnected(id) {
  chart.lock(true);
  const ids = [id, ...chart.selection()];
  const items = findConnected(ids);
  await chart.filter((item) => items.includes(item.id), { type: "node" });
  await chart.layout("sequential", { top: ids, orientation: getOrientation() });
  chart.lock(false);
}

async function restoreAndShowAll() {
  chart.lock(true);
  chart.selection([]);
  await chart.filter(() => true, { time: 500 });
  chart.layout("organic", { consistent: true, tightness: 2 });
  await chart.zoom("fit", { time: 500, animate: true });
  chart.lock(false);
}

function onClick({ id }) {
  const item = chart.getItem(id);
  if (item && item.type === "node") {
    filterConnected(id);
  }
}

function onDoubleclick({ id, preventDefault }) {
  const item = chart.getItem(id);
  if (item === null) {
    restoreAndShowAll();
  }
  // disable zoom
  preventDefault();
}

async function startKeyLines() {
  const imageAlignment = {
    "fas fa-user": { dy: -10 },
    "fas fa-building": { dy: 2, e: 0.9 },
  };

  const options = {
    logo: { u: "/images/Logo.png" },
    linkEnds: { avoidLabels: false },
    iconFontFamily: "Font Awesome 5 Free",
    imageAlignment,
    hover: 5,
    handMode: true,
  };
  chart = await KeyLines.create({ container: "klchart", options });

  chart.on("click", onClick);
  chart.on("double-click", onDoubleclick);

  chart.load(chartData);
  await chart.zoom("fit");
  chart.layout("organic", { consistent: true, tightness: 2 });
}

function loadKeyLines() {
  document.fonts.load('24px "Font Awesome 5 Free"').then(startKeyLines);
}

window.addEventListener("DOMContentLoaded", loadKeyLines);
<!DOCTYPE html>
<html lang="en" style="background-color: #2d383f;">
  <head>
    <meta charset="UTF-8">
    <title>Hierarchical Dependencies</title>
    <link rel="stylesheet" type="text/css" href="/css/keylines.css">
    <link rel="stylesheet" type="text/css" href="/css/minimalsdk.css">
    <link rel="stylesheet" type="text/css" href="/css/sdk-layout.css">
    <link rel="stylesheet" type="text/css" href="/css/demo.css">
    <link rel="stylesheet" type="text/css" href="/css/fontawesome5/fontawesome.css">
    <link rel="stylesheet" type="text/css" href="/css/fontawesome5/solid.css">
    <script src="/vendor/jquery.js" defer type="text/javascript"></script>
    <script id="keylines" src="/public/keylines.umd.cjs" defer type="text/javascript"></script>
    <script src="/dependencies.js" crossorigin="use-credentials" type="module"></script>
  </head>
  <body>
    <div class="chart-wrapper demo-cols">
      <div class="tab-content-panel flex1" id="lhs" data-tab-group="rhs">
        <div class="toggle-content is-visible" id="lhsVisual" style="width:100%; height: 100%;">
          <div class="klchart" id="klchart">
          </div>
        </div>
      </div>
      <div class="rhs citext closed" id="demorhscontent">
        <div class="title-bar">
          <svg viewBox="0 0 360 60" style="max-width: 360px; max-height: 60px; font-size: 24px; font-family: Raleway; flex: 1;">
            <text x="0" y="38" style="width: 100%;">Hierarchical Dependencies</text>
          </svg>
        </div>
        <div class="tab-content-panel" data-tab-group="rhs">
          <div class="toggle-content is-visible tabcontent" id="controlsTab">
            <p>Dependency analysis: who owns what?</p>
            <form autocomplete="off" onsubmit="return false" id="rhsForm">
              <div class="cicontent">
                <fieldset>
                  <legend>Instructions</legend>
                  <ol>
                    <li>Click a person to see what companies they own</li>
                    <li>Click a company to see who owns it</li>
                    <li>Double-click on the background of the chart to return to the full network</li>
                  </ol>
                </fieldset>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
    <div id="moreParent">
      <div id="moreContainer">
      </div>
    </div>
    <div id="lazyScripts">
    </div>
  </body>
</html>
Loading source