Category hierarchy layout mode
The 'categoryHierarchy' layout mode differs from 'hierarchy' by sorting nodes based on 'hierarchyCategory' strings, instead of their relationship hierarchy. This way, you can display nodes at the same level regardless of their actual relationships - useful for flow charts, scheduling or resource management.
HTML
HTML
<script src="https://cdn.zoomcharts-cloud.com/1/nightly/zoomcharts.js"></script>
<div id="demo"></div>
CSS
CSS
//No CSS for this example
JavaScript
JavaScript
var data = {
"nodes": [
{ "id": "a1", "loaded": true, "style": { "label": "Node Label A1", "hierarchyCategory": "Category Applesauce", "fillColor": "red" } },
{ "id": "a2", "loaded": true, "style": { "label": "Node Label A2", "hierarchyCategory": "Category Applesauce", "fillColor": "red" } },
{ "id": "a3", "loaded": true, "style": { "label": "Node Label A3", "hierarchyCategory": "Category Applesauce", "fillColor": "red" } },
{ "id": "a4", "loaded": true, "style": { "label": "Node Label A4", "hierarchyCategory": "Category Applesauce", "fillColor": "red" } },
{ "id": "a5", "loaded": true, "style": { "label": "Node Label A5", "hierarchyCategory": "Category Applesauce", "fillColor": "red" } },
{ "id": "b1", "loaded": true, "style": { "label": "Node Label B1", "hierarchyCategory": "Category Biscuit", "fillColor": "green" } },
{ "id": "b2", "loaded": true, "style": { "label": "Node Label B2", "hierarchyCategory": "Category Biscuit", "fillColor": "green" } },
{ "id": "b3", "loaded": true, "style": { "label": "Node Label B3", "hierarchyCategory": "Category Biscuit", "fillColor": "green" } },
{ "id": "b4", "loaded": true, "style": { "label": "Node Label B4", "hierarchyCategory": "Category Biscuit", "fillColor": "green" } },
{ "id": "c1", "loaded": true, "style": { "label": "Node Label C1", "hierarchyCategory": "Category Cucumber", "fillColor": "blue" } },
{ "id": "c2", "loaded": true, "style": { "label": "Node Label C2", "hierarchyCategory": "Category Cucumber", "fillColor": "blue" } },
{ "id": "c3", "loaded": true, "style": { "label": "Node Label C3", "hierarchyCategory": "Category Cucumber", "fillColor": "blue" } },
{ "id": "c4", "loaded": true, "style": { "label": "Node Label C4", "hierarchyCategory": "Category Cucumber", "fillColor": "blue" } },
{ "id": "c5", "loaded": true, "style": { "label": "Node Label C5", "hierarchyCategory": "Category Cucumber", "fillColor": "blue" } },
{ "id": "d2", "loaded": true, "style": { "label": "Node Label D2", "hierarchyCategory": "Category Dessert", "fillColor": "yellow" } },
{ "id": "d3", "loaded": true, "style": { "label": "Node Label D3", "hierarchyCategory": "Category Dessert", "fillColor": "yellow" } },
{ "id": "d4", "loaded": true, "style": { "label": "Node Label D4", "hierarchyCategory": "Category Dessert", "fillColor": "yellow" } },
{ "id": "d5", "loaded": true, "style": { "label": "Node Label D5", "hierarchyCategory": "Category Dessert", "fillColor": "yellow" } },
{ "id": "d6", "loaded": true, "style": { "label": "Node Label D6", "hierarchyCategory": "Category Dessert", "fillColor": "yellow" } },
{ "id": "e4", "loaded": true, "style": { "label": "Node Label E4", "hierarchyCategory": "Category Egg", "fillColor": "orange" } },
{ "id": "e5", "loaded": true, "style": { "label": "Node Label E5", "hierarchyCategory": "Category Egg", "fillColor": "orange" } },
{ "id": "e6", "loaded": true, "style": { "label": "Node Label E6", "hierarchyCategory": "Category Egg", "fillColor": "orange" } },
],
"links": [
{ "id": "l1", "from": "a1", "to": "a2" },
{ "id": "l2", "from": "a2", "to": "a3" },
{ "id": "l3", "from": "a3", "to": "a4" },
{ "id": "l4", "from": "a4", "to": "a5" },
{ "id": "l5", "from": "a1", "to": "b1" },
{ "id": "l6", "from": "b1", "to": "a2" },
{ "id": "l7", "from": "b2", "to": "b3" },
{ "id": "l8", "from": "b3", "to": "b4" },
{ "id": "l9", "from": "a3", "to": "b2" },
{ "id": "l10", "from": "b3", "to": "a5" },
{ "id": "l11", "from": "b1", "to": "b2" },
{ "id": "l12", "from": "c2", "to": "b2" },
{ "id": "l13", "from": "b2", "to": "d6" },
{ "id": "l14", "from": "a5", "to": "e6" },
{ "id": "l15", "from": "e6", "to": "b4" },
{ "id": "l16", "from": "c1", "to": "c2" },
{ "id": "l17", "from": "c2", "to": "c3" },
{ "id": "l18", "from": "c3", "to": "c4" },
{ "id": "l19", "from": "c4", "to": "c5" },
{ "id": "l20", "from": "d3", "to": "c3" },
{ "id": "l21", "from": "c3", "to": "d4" },
{ "id": "l22", "from": "d4", "to": "c4" },
{ "id": "l23", "from": "c5", "to": "d6" },
{ "id": "l24", "from": "d2", "to": "d3" },
{ "id": "l25", "from": "d3", "to": "d4" },
{ "id": "l26", "from": "d4", "to": "d5" },
{ "id": "l27", "from": "d5", "to": "d6" },
{ "id": "l28", "from": "a2", "to": "d3" },
{ "id": "l29", "from": "e4", "to": "e5" },
{ "id": "l30", "from": "e5", "to": "e6" },
{ "id": "l31", "from": "d3", "to": "e4" },
{ "id": "l32", "from": "e4", "to": "d4" },
{ "id": "l33", "from": "d5", "to": "e5" },
{ "id": "l34", "from": "e5", "to": "d6" },
{ "id": "l35", "from": "d6", "to": "e6" },
{ "id": "l36", "from": "d6", "to": "a1" },
{ "id": "l37", "from": "d6", "to": "c4" },
]
};
const cycleColors = ["red", "orange", "yellow", "green", "blue", "magenta"];
const cycleIDColorMap = {};
let nextCycleIndex = 0;
var chart = new NetChart({
container: document.getElementById("demo"),
data: { preloaded: data },
layout: {
mode: "categoryHierarchy",
rotation: -90,
scaleY: -1,
// Nodes can be spaced to avoid overlap using these settings
nodeSpacing: 30,
rowSpacing: 60,
categoryLabelStyle: {
// Labels respect alignment settings
align: "left",
side: "right",
positionX: "left",
textStyle: {
font: "12px Arial"
},
backgroundStyle: {
fillColor: "white"
}
},
onCycleDetect: (backlink, cycle) => {
// This is naively marking every link involved in every cycle
// detected. Can also e.g. only mark the backlinks or have
// some method of handling overlapping cycles, or have special
// additional styling for backlinks, etc. etc.
const cycleID = backlink.id;
for(let i = 0; i < cycle.length; i++) {
let link = cycle[i];
if(!link.extra) {
link.extra = {};
}
link.extra.cycleID = cycleID;
}
if(!backlink.extra) {
backlink.extra = {};
}
backlink.extra.isBacklink = true;
if(!cycleIDColorMap.hasOwnProperty(cycleID)) {
cycleIDColorMap[cycleID] = cycleColors[nextCycleIndex % cycleColors.length];
nextCycleIndex++;
}
}
},
style:{
multilinkAutoCurve: 1.0,
multilinkSpacing: 10,
node: {
// Label should be inside the node with roundtext setting
display: "roundtext",
},
link: { toDecoration: "arrow" },
linkStyleFunction: (link) => {
link.radius = 1;
// Simple example of styling links that are part of a cycle
if(link.extra && link.extra.cycleID) {
link.fillColor = cycleIDColorMap[link.extra.cycleID];
link.radius = 2;
}
if(link.extra && link.extra.isBacklink) {
link.radius = 5;
}
},
nodeStyleFunction: (node) => {
// Example of applying styles to the node labels
node.labelStyle.textStyle.fillColor = "black"
node.labelStyle.textStyle.font = "12px Arial"
}
}
});
Data
Data
//No separate data for this example