UNPKG

force-graph

Version:

2D force-directed graph rendered on HTML5 canvas

84 lines (70 loc) 2.45 kB
<head> <style> body { margin: 0; } </style> <script src="//unpkg.com/d3-dsv"></script> <script src="//unpkg.com/d3-quadtree"></script> <script src="//unpkg.com/d3-force"></script> <script src="//unpkg.com/force-graph"></script> <!--<script src="../../dist/force-graph.js"></script>--> <style> .clickable { cursor: unset !important } </style> </head> <body> <div id="graph"></div> <script> fetch('../datasets/d3-dependencies.csv').then(r => r.text()).then(d3.csvParse).then(data => { const nodes = [], links = []; data.forEach(({ size, path }) => { const levels = path.split('/'), level = levels.length - 1, module = level > 0 ? levels[1] : null, leaf = levels.pop(), parent = levels.join('/'); const node = { id: path, leaf, module, collapsed: level > 0, childLinks: [] }; nodes.push(node); if (parent) { links.push({ source: parent, target: path }); } }); const rootId = 'd3'; // link parent/children const nodesById = Object.fromEntries(nodes.map(node => [node.id, node])); links.forEach(link => { nodesById[link.source].childLinks.push(link); }); const getPrunedTree = () => { const visibleNodes = []; const visibleLinks = []; (function traverseTree(node = nodesById[rootId]) { visibleNodes.push(node); if (node.collapsed) return; visibleLinks.push(...node.childLinks); node.childLinks .map(link => ((typeof link.target) === 'object') ? link.target : nodesById[link.target]) // get child node .forEach(traverseTree); })(); // IIFE return { nodes: visibleNodes, links: visibleLinks }; }; const elem = document.getElementById('graph'); const Graph = new ForceGraph(elem) .graphData(getPrunedTree()) .nodeLabel('id') .nodeColor(node => !node.childLinks.length ? 'green' : node.collapsed ? 'red' : 'yellow') .onNodeHover(node => elem.style.cursor = node && node.childLinks.length ? 'pointer' : null) .onNodeClick(node => { node.collapsed = !node.collapsed; // toggle collapse state Graph.graphData(getPrunedTree()); }) .dagMode('td') .dagLevelDistance(90) .d3Force('collision', d3.forceCollide(node => Graph.nodeRelSize())) .warmupTicks(250); }); </script> </body>