JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.4.4/d3.min.js"></script>
<script src="https://unpkg.com/[email protected]"></script>
<svg id="TargetContainer" style="width: 1000; height: 1500">
</svg>
JavaScript
const data = [
{
"id": "0",
"name": "node1",
"parentIds": []
},
{
"id": "1",
"name": "node2",
"parentIds": ["0"]
},
{
"id": "2",
"name": "node3",
"parentIds": ["1"]
},
{
"id": "3",
"name": "node4",
"parentIds": ["1"]
},
{
"id": "4",
"name": "node5",
"parentIds": ["1", "2", "3", "8"]
},
{
"id": "5",
"name": "node6",
"parentIds": ["4"]
},
{
"id": "6",
"name": "node7",
"parentIds": ["5"]
},
{
"id": "7",
"name": "node8",
"parentIds": []
},
{
"id": "8",
"name": "node9",
"parentIds": ["7"]
}
];
async function createGraph() {
const dag = d3.dagStratify()(data);
const layout = d3
.sugiyama() // base layout
.decross(d3.decrossOpt()) // minimize number of crossings
.nodeSize((node) => [200, 200]); // set node size instead of constraining to fit
layout(dag);
// This code only handles rendering
const svgSelection = d3.select("#TargetContainer");
svgSelection.append("defs"); // For gradients
addDefs(svgSelection);
// Initialize color map
const steps = dag.size();
const interp = d3.interpolateRainbow;
const colorMap = {};
for (const [i, node] of [...dag].entries()) {
colorMap[node.data.id] = interp(i / steps);
}
drawEdges(svgSelection, dag);
// Select nodes
const nodes = svgSelection
.append("g")
.selectAll("g")
.data(dag.descendants())
.enter()
.append("g")
.attr("transform", ({ x, y }) => `translate(${x - 70}, ${y})`);
nodes
.append("rect")
.attr("class", "node")
.attr("filter", "url(#nodeShadow)")
.attr("rx", "17")
.attr("fill", "#FFFFFF")
.attr("width", "150")
.attr("height", 30)
.each(function (p, j) {
...