定位力(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();
内容版权声明:除非注明,否则皆为本站原创文章。
