JSFiddle - React, Tailwind, and code Playground
by Rajesh Danabal
HTML
<svg id="svg" width="100%" height="100%"></svg>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/d3-flextree.min.js"></script>
JavaScript
// --- Sample data with items per node ---
const data = {
name: "Root",
w: 160, h: 120,
items: [
{ id: "root1", label: "Root-Task A" },
{ id: "root2", label: "Root-Task B" }
],
children: [
{
name: "Alpha", w: 160, h: 120,
items: [
{ id: "a1", label: "Alpha-1" },
{ id: "a2", label: "Alpha-2" }
],
children: [
{ name: "A-1", w: 140, h: 100, items: [{id:"a1-1", label:"Leaf"}] },
{ name: "A-2", w: 140, h: 100, items: [] },
]
},
{ name: "Beta", w: 160, h: 120, items: [] },
{ name: "Gamma", w: 160, h: 120, items: [{id:"g1", label:"Gamma Item"}] },
]
};
function setDefaults(node, defaultW = 160, defaultH = 120) {
if (node.w == null) node.w = defaultW;
if (node.h == null) node.h = defaultH;
if (!Array.isArray(node.items)) node.items = [];
if (node.children) node.children.forEach(c => setDefaults(c, defaultW, defaultH));
}
setDefaults(data);
// --- Layout setup ---
const hGap = 30, vGap = 30;
const flextree = d3.flextree()
.nodeSize(d => [getW(d) + hGap, getH(d) + vGap]);
const root = flextree.hierarchy(data);
flextree(root);
// --- SVG + groups ---
const svg = d3.select("#svg");
const gLinks = svg.append("g").attr("class", "links");
const gNodes = svg.append("g").attr("class", "nodes");
svg.call(d3.zoom().on("zoom", ev => {
gNodes.attr("transform", ev.transform);
gLinks.attr("transform", ev.transform);
})).call(d3.zoom().transform, d3.zoomIdentity.translate(80,80));
// --- Helpers ---
function getW(d){ return (d.data && typeof d.data.w==="number") ? d.data.w : 160; }
function getH(d){ return (d.data && typeof d.data.h==="number") ? d.data.h : 120; }
function clamp(v,a,b){ return Math.max(a, Math.min(b,v)); }
// --- Path generator ---
function elbow(d) {
const sx = d.source.x + getW(d.source) / 2;
const sy = d.source.y + getH(d.source);
const tx = d.target.x + getW(d.target) / 2;
const...