定位力(Positioning)
这个力可以将节点沿着指定的维度推向一个指定位置,比如通过设置 forceX 和 forceY 就可以在 X轴 和 Y轴 方向推或者拉所有的节点,forceRadial 则可以形成一个圆环把所有的节点都往这个圆环上相应的位置推。
回到这个需求上,其实可以把应用、所有的资源与调用信息都看成节点,资源之间通过一个较弱的弹簧力与调用信息连接起来,同时如果应用与资源间的调用有来有往,则在这两个调用信息之间加上一个较强的弹簧力。
ok说干就干
// 所有代码基于 typescript,省略部分代码 type INode = d3.SimulationNodeDatum & { id: string label: string; isAppNode?: boolean; }; type ILink = d3.SimulationLinkDatum<INode> & { strength: number; }; const nodes: INode[] = [...]; const links: ILink[] = [...]; const container = d3.select('container'); const svg = container.select('svg') .attr('width', width) .attr('height', height); const html = container.append('div') .attr('class', styles.HtmlContainer); // 创建一个弹簧力,根据 link 的 strength 值决定强度 const linkForce = d3.forceLink<INode, ILink>(links) .id(node => node.id) // 资源节点与信息节点间的 strength 小一点,信息节点间的 strength 大一点 .strength(link => link.strength); const simulation = d3.forceSimulation<INode, ILink>(nodes) .force('link', linkForce) // 在 y轴 方向上施加一个力把整个图形压扁一点 .force('yt', d3.forceY().strength(() => 0.025)) .force('yb', d3.forceY(height).strength(() => 0.025)) // 节点间相互排斥的电磁力 .force('charge', d3.forceManyBody<INode>().strength(-400)) // 避免节点相互覆盖 .force('collision', d3.forceCollide().radius(d => 4)) .force('center', d3.forceCenter(width / 2, height / 2)) .stop(); // 手动调用 tick 使布局达到稳定状态 for (let i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) { simulation.tick(); } const nodeElements = svg.append('g') .selectAll('circle') .data(nodes) .enter().append('circle') .attr('r', 10) .attr('fill', getNodeColor); const labelElements = svg.append('g') .selectAll('text') .data(nodes) .enter().append('text') .text(node => node.label) .attr('font-size', 15); const pathElements = svg.append('g') .selectAll('line') .data(links) .enter().append('line') .attr('stroke-width', 1) .attr('stroke', '#E5E5E5'); const render = () => { nodeElements .attr('cx', node => node.x!) .attr('cy', node => node.y!); labelElements .attr('x', node => node.x!) .attr('y', node => node.y!); pathElements .attr('x1', link => link.source.x) .attr('y1', link => link.source.y) .attr('x2', link => link.target.x) .attr('y2', link => link.target.y); } render();
内容版权声明:除非注明,否则皆为本站原创文章。