如何修改D3.js脚本正确渲染SAP CDS Views的JSON网络数据?
我帮你分析下为啥改了ticked函数里的字段还是没法正常显示,核心问题不在ticked函数本身,而是你没搞清楚D3力导向图里forceLink的匹配逻辑,还有你的JSON数据结构和D3默认期望的结构不匹配。
问题核心分析
首先,D3的forceLink默认会从你的links数据里找source和target这两个字段,用来匹配nodes里的节点ID。但你的links里用的是SourceViewName和TargetViewName,而且你之前改ticked函数里的d.source.x为d.SourceViewName.x是完全错误的——因为d.SourceViewName是字符串(比如"srcvw1"),根本没有x/y属性,自然没法渲染链接。
另外,你当前的forceLink配置只指定了节点的ID是SourceViewName,但没告诉它从links里的哪个字段取源和目标的ID,所以forceLink根本不知道怎么把链接和节点关联起来。
具体解决步骤
1. 修正forceLink的配置(最关键)
你需要显式告诉forceLink,从links的SourceViewName取源节点ID,从TargetViewName取目标节点ID。修改这部分代码:
var simulation = d3.forceSimulation() .force("link", d3.forceLink() .id(function(d) { return d.SourceViewName; }) // 节点的唯一标识是SourceViewName .source(function(d) { return d.SourceViewName; }) // 链接的源节点ID是links里的SourceViewName .target(function(d) { return d.TargetViewName; }) // 链接的目标节点ID是links里的TargetViewName ) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2));
2. 恢复ticked函数的原始写法
把你改的d.SourceViewName.x/d.TargetViewName.y改回d.source.x/d.target.y——因为forceLink处理后,会自动把links里的source和target字段替换成对应的节点对象(包含x/y坐标),所以原始写法是对的:
function ticked() { link .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); }
3. 验证数据匹配性
确保你的links里的每一个SourceViewName和TargetViewName,都能在nodes数组中找到对应的节点(即nodes里存在SourceViewName等于该值的项)。比如如果links里有"SourceViewName": "srcvw1",那nodes里必须有一个节点的SourceViewName也是"srcvw1",否则链接找不到对应的节点,就不会显示。
4. 检查JSON语法正确性
你提供的nodes和linksJSON片段有语法错误(比如nodes里的__metadata对象没闭合,nodes数组也没闭合),确保你的data/summarized.json是完整合法的JSON格式,否则D3加载数据时会报错。
额外优化建议
- 节点的tooltip你现在用的是
d.SourceViewName,这个没问题,但可以考虑加上CDSViewPackage等信息,让tooltip更有用:node.append("title") .text(function(d) { return `${d.SourceViewName}\nPackage: ${d.CDSViewPackage}`; });
内容的提问来源于stack exchange,提问作者Matthew K.

