在React中使用D3实现静态网络图的开发问题咨询
静态D3网络图实现(仅更新节点半径+props驱动链接变更)
核心调整说明
- 完全移除力导向模拟逻辑,避免动态布局抖动,适配每秒定时刷新的需求
- 补全D3数据绑定的完整更新逻辑,节点仅修改
r属性,链接仅更新端点坐标,其余属性初始化时仅设置一次 - 调整useEffect依赖项,保证props传入的节点、链接数据变更时都能触发更新
- 节点坐标默认从props.data每个节点的
x/y字段读取,若没有提前计算坐标,可替换代码里的坐标生成逻辑做固定布局(环形、网格排布均可)
修正后完整代码
import { useRef, useEffect } from 'react'; import * as d3 from 'd3'; const NetworkGraph = props => { const areaChart = useRef(); const dimensions = {width:400, height:200}; useEffect(() => { const svg = d3.select(areaChart.current) .attr('width', dimensions.width) .attr('height', dimensions.height) .style('background-color','white'); // 处理链接更新逻辑 const linkUpdate = svg.selectAll("line") .data(props.links, d => `${d.source.id}-${d.target.id}`); // 用唯一键绑定数据避免重复渲染 // 新增链接 const linkEnter = linkUpdate.enter() .append("line") .style("stroke", "#aaa"); // 移除过期链接 linkUpdate.exit().remove(); // 所有链接更新端点坐标 linkEnter.merge(linkUpdate) .attr("x1", d => d.source.x) .attr("y1", d => d.source.y) .attr("x2", d => d.target.x) .attr("y2", d => d.target.y); // 处理节点更新逻辑 const nodeUpdate = svg.selectAll("circle") .data(props.data, d => d.id); // 用节点id作为唯一绑定键 // 新增节点 const nodeEnter = nodeUpdate.enter() .append("circle") .style("fill", "#69b3a2") .attr("cx", d => d.x) // 节点x坐标从props读取,固定不变 .attr("cy", d => d.y); // 节点y坐标从props读取,固定不变 // 移除过期节点 nodeUpdate.exit().remove(); // 所有节点仅更新radius属性 nodeEnter.merge(nodeUpdate) .attr("r", d => d.valor); }, [props.data, props.links]); // 同时监听节点和链接数据变更 return <svg ref={areaChart}> </svg>; }; export default NetworkGraph;
无预设坐标适配方案
如果你的节点数据里没有提前计算好x/y坐标,可以在useEffect开头加一段简单的固定布局逻辑,比如把节点均匀分布在画布中线上:
// 仅首次或节点数量变更时计算一次坐标,平时刷新不改动 if(!svg.select("circle").size()) { props.data.forEach((d, i) => { d.x = 50 + (dimensions.width - 100) * i / (props.data.length - 1); d.y = dimensions.height / 2; }) }
目标效果参考

内容的提问来源于stack exchange,提问作者xzethxsz
相关产品推荐
相关产品推荐

