//
//     Copyright © 2011-2025 Cambridge Intelligence Limited.
//     All rights reserved.
//
//     Sample Code
//
//!    Populate the contents of combos on demand.
import KeyLines from "keylines";
import {
  randomColour,
  baseNode,
  baseLink,
  plusIcon,
} from "./comboload-data.js";

let chart;
let idCount = 0;

const maxNodes = 12;
const minNodes = 3;
const linkDensity = 0.2;

function createRandomNodes(parent) {
  // Create random nodes with links between them all in a given parent
  const items = [];
  const nodeCount =
    Math.floor(Math.random() * (maxNodes - minNodes + 1)) + minNodes;
  const colour = randomColour();
  // Create nodes
  for (let n = 0; n < nodeCount; n++) {
    items.push(
      Object.assign({}, baseNode, {
        id: `node${idCount++}`,
        parentId: parent,
        c: colour.node,
        g: [plusIcon],
      })
    );
  }
  // Create links
  for (let n1 = 0; n1 < nodeCount; n1++) {
    for (let n2 = n1 + 1; n2 < nodeCount; n2++) {
      if (Math.random() < linkDensity) {
        items.push(
          Object.assign({}, baseLink, {
            id: `link${idCount++}`,
            id1: items[n1].id,
            id2: items[n2].id,
          })
        );
      }
    }
  }
  return { items, colour };
}

async function createParentCombo(id) {
  const data = createRandomNodes(id);
  // Create the new combo with the nodes
  await chart.merge(data.items);
  await chart.setProperties({ id, g: [], oc: { c: data.colour.oc } });
  await chart.combo().arrange(id, { animate: false });
  await chart.combo().open(id);
}

function isNode(id) {
  const item = chart.getItem(id);
  return item?.type === "node";
}

function handleClick({ id, preventDefault }) {
  if (id && !chart.combo().isCombo(id) && isNode(id)) {
    createParentCombo(id);
    preventDefault();
  }
}

async function startKeyLines() {
  const options = {
    handMode: true,
    // Set the name of the font we want to use for icons (a font must be loaded in the browser
    // with exactly this name)
    iconFontFamily: "Font Awesome 5 Free",
    logo: { u: "/images/Logo.png" },
    selectionColour: "rgb(68, 68, 68)",
  };

  chart = await KeyLines.create({
    container: "klchart",
    options,
  });
  chart.on("double-click", handleClick);

  chart.load({ type: "LinkChart", items: createRandomNodes(null).items });
  chart.zoom("fit", { animate: false });
  chart.layout("organic", { time: 400 });
}

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>Load Data into Combos</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="/comboload.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%;">Load Data into Combos</text>
          </svg>
        </div>
        <div class="tab-content-panel" data-tab-group="rhs">
          <div class="toggle-content is-visible tabcontent" id="controlsTab">
            <form autocomplete="off" onsubmit="return false" id="rhsForm">
              <div class="cicontent">
                <p>Double-click nodes to see their contents. </p>
                <p>A <i class="fas fa-plus"></i> glyph indicates the node's contents have not yet been loaded into the chart. Double-clicking these nodes will 
                  turn them into combos, and populate them with a new set of data.
                </p>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
    <div id="moreParent">
      <div id="moreContainer">
      </div>
    </div>
    <div id="lazyScripts">
    </div>
  </body>
</html>
Loading source