//
// 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
