//
// Copyright © 2011-2025 Cambridge Intelligence Limited.
// All rights reserved.
//
// Sample Code
//
//! Reveal underlying links between combos.
import KeyLines from "keylines";
import { chartOptions } from "./reveallinks-data.js";
let chart;
let graphEngine;
function linkedToOpenCombo(linkId) {
const link = chart.getItem(linkId);
const node1 = chart.combo().find(link.id1);
const node2 = chart.combo().find(link.id2);
// Filter out non-combo ends of the link
const linkEndCombos = [node1, node2].filter((id) =>
chart.combo().isCombo(id)
);
// Return true only if one of the links is an open combo
return linkEndCombos.some((comboId) => chart.combo().isOpen(comboId));
}
function selectionHandler() {
// Get the current state
const ids = chart
.selection()
.filter((id) => chart.getItem(id).type === "node");
if (ids.length > 0) {
// Get, show (if required), and foreground the neighbours of the underlying items
graphEngine.load(chart.serialize());
// The method for getting neighbours of combos and noncombos is slightly different
// So we have to use a different method for each
const combos = ids.filter((id) => chart.combo().isCombo(id));
const comboNeighbours = chart.graph().neighbours(combos);
const nonCombos = ids.filter((id) => !chart.combo().isCombo(id));
const nonComboNeighbours = graphEngine.neighbours(nonCombos);
// Get all the links involved
const links = comboNeighbours.links.concat(nonComboNeighbours.links);
// And filter them such that they only include ones linked to an open combo.
chart.combo().reveal(links.filter(linkedToOpenCombo));
if (combos.length) {
// This allows combos to become selected as there's no 'all' option for chart.foreground
chart.foreground((item) => links.includes(item.id), {
type: "link",
items: "toplevel",
});
}
if (nonCombos.length) {
chart.foreground((item) => links.includes(item.id), { type: "link" });
}
} else {
// No items selected, foreground everything
chart.combo().reveal([]);
chart.foreground(() => true);
}
}
async function comboHandler(id) {
const comboId = chart.combo().find(id) || id;
const opts = { adapt: "inCombo" };
if (chart.combo().isCombo(comboId)) {
chart.foreground(() => true);
chart.combo().reveal([]);
if (chart.combo().isOpen(comboId)) {
await chart.combo().close(comboId, opts);
} else {
await chart.combo().open(comboId, opts);
}
}
}
function doubleClickHandler({ preventDefault, id }) {
if (chart.getItem(id)) {
comboHandler(id);
selectionHandler();
preventDefault();
}
}
async function startKeyLines() {
chart = await KeyLines.create({
container: "klchart",
options: {
drag: {
links: false,
},
selectionColour: "#444",
logo: { u: "/images/Logo.png" },
},
});
graphEngine = KeyLines.getGraphEngine();
// data is defined in reveallinks-data.js
chart.load(chartOptions);
// Setup UI
chart.on("selection-change", selectionHandler);
chart.on("double-click", doubleClickHandler);
chart.layout("organic");
}
window.addEventListener("DOMContentLoaded", startKeyLines);
<!DOCTYPE html>
<html lang="en" style="background-color: #2d383f;">
<head>
<meta charset="UTF-8">
<title>Combos: Reveal Links</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/font-awesome.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="/reveallinks.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%;">Combos: Reveal Links</text>
</svg>
</div>
<div class="tab-content-panel" data-tab-group="rhs">
<div class="toggle-content is-visible tabcontent" id="controlsTab">
<p>Select items in the chart to reveal their direct connections.</p>
<form autocomplete="off" onsubmit="return false" id="rhsForm">
</form>
</div>
</div>
</div>
</div>
<div id="moreParent">
<div id="moreContainer">
</div>
</div>
<div id="lazyScripts">
</div>
</body>
</html>
Loading source
