我想分别向节点的几个子部分施加多个力(forceX 和forceY)。
为了更具说明性,我将此 JSON 作为我的节点的数据:
[{
"word": "expression",
"theme": "Thème 6",
"radius": 3
}, {
"word": "théorie",
"theme": "Thème 4",
"radius": 27
}, {
"word": "relativité",
"theme": "Thème 5",
"radius": 27
}, {
"word": "renvoie",
"theme": "Thème 3",
"radius": 19
},
....
]
我想要的是将一些力量专门应用于具有“主题 1”作为主题属性的节点,或对“主题 2”值施加其他力量,等等......
我一直在查看源代码以检查我们是否可以将模拟节点的子部分分配给力,但我还没有找到。
我的结论是我必须实施一些辅助措施d3.simulation()
并且仅应用节点各自的子部分来处理我之前提到的力。
这是我想在 d3 伪代码中执行的操作:
mainSimulation = d3.forceSimulation()
.nodes(allNodes)
.force("force1", aD3Force() )
.force("force2", anotherD3Force() )
cluster1Simulation = d3.forceSimulation()
.nodes(allNodes.filter( d => d.theme === "Thème 1"))
.force("subForce1", forceX( .... ) )
cluster2Simulation = d3.forceSimulation()
.nodes(allNodes.filter( d => d.theme === "Thème 2"))
.force("subForce2", forceY( .... ) )
但我认为考虑到计算,这根本不是最佳的。
是否可以在模拟节点的子部分上施加力,而无需创建其他模拟?
实施高积云的第二个解决方案:
我尝试了这样的解决方案:
var forceInit;
Emi.nodes.centroids.forEach( (centroid,i) => {
let forceX = d3.forceX(centroid.fx);
let forceY = d3.forceY(centroid.fy);
if (!forceInit) forceInit = forceX.initialize;
let newInit = nodes => {
forceInit(nodes.filter(n => n.theme === centroid.label));
};
forceX.initialize = newInit;
forceY.initialize = newInit;
Emi.simulation.force("X" + i, forceX);
Emi.simulation.force("Y" + i, forceY);
});
我的质心数组可能会改变,这就是为什么我必须采用动态方式来实现我的子力。
不过,我最终在模拟滴答声中遇到了这个错误:
09:51:55,996 TypeError: nodes.length is undefined
- force() d3.v4.js:10819
- tick/<() d3.v4.js:10559
- map$1.prototype.each() d3.v4.js:483
- tick() d3.v4.js:10558
- step() d3.v4.js:10545
- timerFlush() d3.v4.js:4991
- wake() d3.v4.js:5001
我的结论是过滤后的数组没有分配给nodes,我不明白为什么。
PS:我检查了console.log:nodes.filter(...)确实返回了一个填充的数组,所以这不是问题的根源。