Layouts give spatial positions to nodes to help with pattern recognition and other user interactions.
Organic
The default layout, highly optimised for great performance on large datasets. The organic layout excels at untangling big networks and intuitively adapts to updates in the network with as little changes to the overall graph as possible.
Sequential
Arranges nodes in a way that minimises link crossings and makes the most of the available screen space. Useful when nodes are grouped in distinct levels, with a clear sequence of links from one level to the next. Learn more in the Sequential Layouts demo.
Hierarchy
Arranges nodes in a tree-like hierarchical structure. Useful for data such as class diagrams, ontologies and family trees. The hierarchy can be automatically calculated from a given node, or explicitly defined in the data.
Lens
Lays out nodes in a circle with more densely-connected nodes pushed towards the centre and less densely-connected nodes pushed to the edges.
Radial
Gives an 'egocentric' view of the network, best thought of as a circular tree-like structure. Nodes are placed in concentric rings based on how well connected they are to a specified node, with better connected items closer to the centre. This layout is useful for seeing the relationships of individual nodes.
Structural
Groups nodes that are linked to the same set of nodes together. Useful with data with a complex structure.
Key function used:
import KeyLines from "keylines";
import { data } from "./data.js";
let chart;
const orientationEl = document.getElementById("orientation");
const tightnessEl = document.getElementById("slider");
// Gets the top nodes for Radial and Hierarchy layouts if no nodes are selected
function getTopNodes() {
const selectedItemsIds = chart.selection().filter((item) => chart.getItem(item).type === "node");
return selectedItemsIds.length ? selectedItemsIds : ["2", "5"];
}
// Gets the selected layout name
function getLayoutName() {
return document.querySelector('input[name="layoutName"]:checked').value;
}
function layout() {
// Use the currently selected layout name and options for the layout
const layoutName = getLayoutName();
const orientation = orientationEl.options[orientationEl.selectedIndex].value;
const tightness = parseFloat(tightnessEl.value);
let options;
switch (layoutName) {
case "radial":
options = { top: getTopNodes(), tightness };
break;
case "hierarchy":
options = { top: getTopNodes(), orientation, tightness };
break;
case "sequential":
options = { top: getTopNodes(), orientation, tightness };
break;
default:
options = { tightness };
break;
}
chart.layout(layoutName, options);
}
function initialiseInteractions() {
// Run a layout based on current selected menu options
document.getElementById("layout").addEventListener("click", layout);
// Run applicable layout when orientation selection changes
orientationEl.addEventListener("change", () => {
const layoutName = getLayoutName();
if (layoutName === "hierarchy" || layoutName === "sequential") {
layout();
}
});
// Run a layout when tightness selection changes and update the menu display
tightnessEl.addEventListener("change", () => {
const tightnessValue = tightnessEl.value;
document.getElementById("tightnessValue").innerHTML = ` ${tightnessValue}`;
layout();
});
}
async function loadKeyLines() {
const options = {
drag: {
links: false,
},
logo: { u: "/images/Logo.png" },
handMode: true,
};
chart = await KeyLines.create({ container: "klchart", options });
chart.load(data);
chart.layout();
initialiseInteractions();
}
window.addEventListener("DOMContentLoaded", loadKeyLines); export const data = {
type: "LinkChart",
items: [
{
type: "link",
id: "3-5",
id1: "3",
id2: "5",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "3-7",
id1: "3",
id2: "7",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "3-9",
id1: "3",
id2: "9",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "3-11",
id1: "3",
id2: "11",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "5-15",
id1: "5",
id2: "15",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "5-23",
id1: "5",
id2: "23",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "5-29",
id1: "5",
id2: "29",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "15-13",
id1: "15",
id2: "13",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "15-17",
id1: "15",
id2: "17",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "15-19",
id1: "15",
id2: "19",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "15-21",
id1: "15",
id2: "21",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "29-35",
id1: "29",
id2: "35",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "29-25",
id1: "29",
id2: "25",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "29-27",
id1: "29",
id2: "27",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "29-31",
id1: "29",
id2: "31",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "29-33",
id1: "29",
id2: "33",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "29-37",
id1: "29",
id2: "37",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "29-39",
id1: "29",
id2: "39",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "2-4",
id1: "2",
id2: "4",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "2-6",
id1: "2",
id2: "6",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "2-8",
id1: "2",
id2: "8",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "2-10",
id1: "2",
id2: "10",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "2-12",
id1: "2",
id2: "12",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "2-14",
id1: "2",
id2: "14",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "4-16",
id1: "4",
id2: "16",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "4-18",
id1: "4",
id2: "18",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "4-20",
id1: "4",
id2: "20",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "4-22",
id1: "4",
id2: "22",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "6-26",
id1: "6",
id2: "26",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "link",
id: "6-28",
id1: "6",
id2: "28",
c: "#b09fc9",
w: 4,
off: 0,
},
{
type: "node",
id: "2",
c: "#6E6ED0",
},
{
type: "node",
id: "3",
c: "#ff8d00",
},
{
type: "node",
id: "4",
c: "#ff8d00",
},
{
type: "node",
id: "5",
c: "#6E6ED0",
},
{
type: "node",
id: "6",
c: "#ff8d00",
},
{
type: "node",
id: "7",
c: "#64BC64",
},
{
type: "node",
id: "8",
c: "#ff8d00",
},
{
type: "node",
id: "9",
c: "#64BC64",
},
{
type: "node",
id: "10",
c: "#ff8d00",
},
{
type: "node",
id: "11",
c: "#64BC64",
},
{
type: "node",
id: "12",
c: "#ff8d00",
},
{
type: "node",
id: "13",
c: "#64BC64",
},
{
type: "node",
id: "14",
c: "#ff8d00",
},
{
type: "node",
id: "15",
c: "#ff8d00",
},
{
type: "node",
id: "16",
c: "#64BC64",
},
{
type: "node",
id: "17",
c: "#64BC64",
},
{
type: "node",
id: "18",
c: "#64BC64",
},
{
type: "node",
id: "19",
c: "#64BC64",
},
{
type: "node",
id: "20",
c: "#64BC64",
},
{
type: "node",
id: "21",
c: "#64BC64",
},
{
type: "node",
id: "22",
c: "#64BC64",
},
{
type: "node",
id: "23",
c: "#ff8d00",
},
{
type: "node",
id: "25",
c: "#64BC64",
},
{
type: "node",
id: "26",
c: "#64BC64",
},
{
type: "node",
id: "27",
c: "#64BC64",
},
{
type: "node",
id: "28",
c: "#64BC64",
},
{
type: "node",
id: "29",
c: "#ff8d00",
},
{
type: "node",
id: "31",
c: "#64BC64",
},
{
type: "node",
id: "33",
c: "#64BC64",
},
{
type: "node",
id: "35",
c: "#64BC64",
},
{
type: "node",
id: "37",
c: "#64BC64",
},
{
type: "node",
id: "39",
c: "#64BC64",
},
],
}; <!doctype html>
<html lang="en" style="background-color: #2d383f">
<head>
<meta charset="utf-8" />
<title>Layouts</title>
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/keylines.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/minimalsdk.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/sdk-layout.css" />
<link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/demo.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div id="klchart" class="klchart"></div>
<script type="module" src="./code.js"></script>
</body>
</html> input[type="range"] {
width: 100%;
margin-bottom: 10px;
}
.label-alpha,
.label-beta {
margin-left: 12px;
}
#layoutfieldset {
margin-left: 10px;
}
fieldset {
width: 90%;
margin-top: 5px;
}
fieldset .radio {
display: block;
padding-left: 0px;
}