Possible solution for hierarchical design
See original GitHub issueHi, after last update I would like to point out one possible solution for hierarchical design but I would need your help. I found really good tutorial here: https://www.alyne.com/en/blog/tech-talk/using-webcola-and-d3-js-to-create-hierarchical-layout/
Here are the steps I took: 1.Changed diagram.ts a) import * as _ from ‘lodash’; b)
initCola(): any { // eslint-disable-line @typescript-eslint/no-explicit-any return cola.d3adaptor() .avoidOverlaps(true) .handleDisconnected(false) .symmetricDiffLinkLengths(100) .linkDistance(100) .size([this.options.width, this.options.height]); }
c) inside render function I added this
`const levelGroups = _.groupBy(nodes, “level”);
console.log(levelGroups)
for (const level of Object.keys(levelGroups)) {
const nodeGroup = levelGroups[level];
const constraint = {
type: “alignment”,
axis: “y”,
offsets: [],
};
let prevNodeId = “none”;
for (const node of nodeGroup) {
constraint.offsets.push({
node: _.findIndex(nodes, (d) => d.name === node.name),
offset: 0,
});
if (prevNodeId !== "none") {
console.log(_.findIndex(nodes, (d) => d.name === prevNodeId));
console.log(_.findIndex(nodes, (d) => d.name === node.name));
constraints.push({
axis: "x",
left: _.findIndex(nodes, (d) => d.name === prevNodeId),
right:_.findIndex(nodes, (d) => d.name === node.name),
gap: 50,
});
}
prevNodeId = node.name;
console.log(prevNodeId);
}
constraints.push(constraint);
}
this.cola.nodes(nodes)
.links(links)
**.constraints(constraints)**
.groups(groups);
this.setDistance(this.cola);`
d) in node.ts I added level property in NodeDataType - level: number, in Node Class - public level: number; in constructor - this.level = data.level;
e) in package.json in dependencies I added “@types/lodash”: “^4.14.168”, “lodash”: “^4.17.20”,
JSON here - you can see I added level property:
{ "nodes": [ { "level":1, "name": "testPERMANENT-10.0.1.1", "meta": { "tenant-ip": "10.0.1.1" }, "icon": "/static/images/router.png" }, { "level":1, "name": "testPERMANENT-10.0.1.2", "meta": { "tenant-ip": "10.0.1.2" }, "icon": "/static/images/router.png" }, { "level":2, "name": "INTERNET", "icon": "/static/images/router.png" }, { "level":3, "name": "AZ1-testpermanent-123-muc-vpn1", "meta": { "name": "vpn1" }, "icon": "/static/images/router.png" }, { "level":3, "name": "AZ2-testpermanent-123-muc-vpn2", "meta": { "name": "vpn2" }, "icon": "/static/images/router.png" }, { "level":4, "name": "AZ1-testpermanent-muc-rs1", "meta": { "name": "rs1" }, "icon": "/static/images/router.png" }, { "level":4, "name": "AZ1-testpermanent-muc-rs2", "meta": { "name": "rs2" }, "icon": "/static/images/router.png" }, { "level":4, "name": "AZ2-testpermanent-muc-rs3", "meta": { "name": "rs3" }, "icon": "/static/images/router.png" }, { "level":4, "name": "AZ2-testpermanent-muc-rs4", "meta": { "name": "rs4" }, "icon": "/static/images/router.png" }, { "level":5, "name": "10.0.0.0/24" }, { "level":5, "name": "10.0.1.0/24" }, { "level":6, "name": "POD1-FCIPOCLEAF101", "meta": { "name": "FCIPOCLEAF101" }, "icon": "/static/images/router.png" }, { "level":7, "name": "POD1-FCIPOCLEAF102", "meta": { "name": "FCIPOCLEAF102" }, "icon": "/static/images/router.png" }, { "level":6, "name": "POD2-FCIPOCLEAF202", "meta": { "name": "FCIPOCLEAF202" }, "icon": "/static/images/router.png" }, { "level":7, "name": "POD2-FCIPOCLEAF201", "meta": { "name": "FCIPOCLEAF201" }, "icon": "/static/images/router.png" } ], "links": [ { "source": "10.0.0.0/24", "target": "AZ1-testpermanent-muc-rs1" }, { "source": "10.0.0.0/24", "target": "AZ1-testpermanent-muc-rs2" }, { "source": "10.0.0.0/24", "target": "POD1-FCIPOCLEAF102" }, { "source": "10.0.0.0/24", "target": "POD1-FCIPOCLEAF101" }, { "source": "10.0.0.0/24", "target": "POD2-FCIPOCLEAF201" }, { "source": "10.0.0.0/24", "target": "POD2-FCIPOCLEAF202" }, { "source": "10.0.1.0/24", "target": "AZ2-testpermanent-muc-rs3" }, { "source": "10.0.1.0/24", "target": "AZ2-testpermanent-muc-rs4" }, { "source": "10.0.1.0/24", "target": "POD1-FCIPOCLEAF102" }, { "source": "10.0.1.0/24", "target": "POD1-FCIPOCLEAF101" }, { "source": "10.0.1.0/24", "target": "POD2-FCIPOCLEAF201" }, { "source": "10.0.1.0/24", "target": "POD2-FCIPOCLEAF202" }, { "source": "INTERNET", "target": "AZ1-testpermanent-123-muc-vpn1" }, { "source": "INTERNET", "target": "AZ2-testpermanent-123-muc-vpn2" }, { "source": "INTERNET", "target": "testPERMANENT-10.0.1.1" }, { "source": "INTERNET", "target": "testPERMANENT-10.0.1.2" }, { "source": "10.0.0.0/24", "target": "AZ1-testpermanent-123-muc-vpn1" }, { "source": "10.0.1.0/24", "target": "AZ2-testpermanent-123-muc-vpn2" } ] }
I think it works but not 100% because in the link I provided the generated graph is topdown but for example here LEVEL 1 is displayed at the bottom. And for example if I have groups, one node is displayed at the same level even though its one level lower. So I think it has to do something with groups and constraints.
JSON to image below: vpns are level 1 internet is level 2 etc. but if you look at LEAFS which are aligned with RS this should not be like that because they have different levels but grouping is a problem maybe
you can see without groups it works better but still not great
Issue Analytics
- State:
- Created 3 years ago
- Comments:17 (6 by maintainers)
Hi, yes they overlap only because I used both grouping and inner groups. This could also be solvable by changing behavior slightly be adding margin so we can see header of groups
Yeah I did not test it with higher or lower numbers
Thanks! This is awesome 🎉
Yes, that’s the last thing we have to do. I’d like to introduce a switch to plug setCola stuff into the original inet-henge, so that users can choose expected behavior - note that injecting constraints will cause extra CPU load in each calculation tick.
Besides that, we need to examine the magic number
50, 50, 50
is reasonable for other layouts. Or we should make them configurable maybe.