(function() { const dom = document.getElementById('chart-force'); const width = dom.clientWidth || 800; const height = 500; const nodes = [ { id: 'A', group: 1 }, { id: 'B', group: 1 }, { id: 'C', group: 2 }, { id: 'D', group: 2 }, { id: 'E', group: 3 }, { id: 'F', group: 3 }, { id: 'G', group: 1 }, { id: 'H', group: 2 } ]; const links = [ { source: 'A', target: 'B', value: 5 }, { source: 'A', target: 'C', value: 3 }, { source: 'B', target: 'D', value: 8 }, { source: 'C', target: 'E', value: 2 }, { source: 'D', target: 'F', value: 6 }, { source: 'E', target: 'F', value: 4 }, { source: 'A', target: 'G', value: 7 }, { source: 'G', target: 'H', value: 3 }, { source: 'H', target: 'D', value: 5 } ]; const color = d3.scaleOrdinal(d3.schemeCategory10); const svg = d3.select(dom).append('svg').attr('width', width).attr('height', height); const simulation = d3.forceSimulation(nodes) .force('link', d3.forceLink(links).id(d => d.id).distance(100)) .force('charge', d3.forceManyBody().strength(-300)) .force('center', d3.forceCenter(width / 2, height / 2)) .force('collision', d3.forceCollide(30)); const link = svg.append('g').selectAll('line') .data(links).join('line') .attr('stroke', '#94a3b8') .attr('stroke-width', d => Math.sqrt(d.value) * 1.5); const node = svg.append('g').selectAll('circle') .data(nodes).join('circle') .attr('r', 12) .attr('fill', d => color(d.group)) .call(d3.drag() .on('start', (e, d) => { if (!e.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; }) .on('drag', (e, d) => { d.fx = e.x; d.fy = e.y; }) .on('end', (e, d) => { if (!e.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; })); const label = svg.append('g').selectAll('text') .data(nodes).join('text') .text(d => d.id) .attr('font-size', 11) .attr('text-anchor', 'middle') .attr('dy', -16); simulation.on('tick', () => { link.attr('x1', d => d.source.x).attr('y1', d => d.source.y) .attr('x2', d => d.target.x).attr('y2', d => d.target.y); node.attr('cx', d => d.x).attr('cy', d => d.y); label.attr('x', d => d.x).attr('y', d => d.y); }); window.addEventListener('resize', () => { const w = dom.clientWidth || 800; svg.attr('width', w); simulation.force('center', d3.forceCenter(w / 2, height / 2)).alpha(0.3).restart(); }); })();