d3.js: 将匿名函数作为参数传递给居中力?

d3.js: Pass anonymous function as parameter to centering force?

我正在制作一个交互式气泡图,我正在研究将数据分成两组的功能,这两组移动到屏幕的相对两侧。我在模拟中使用定心力,因为我认为它比使用 forceX 和 forceY 提供更好、更一致的数据显示。但是,我在拆分数据时遇到了问题。

我的想法是,由于您可以将匿名函数作为参数传递给 forceX 以确定节点是向左移动还是向右移动,因此理论上您可以对居中力中的 x 值执行相同的操作。我的中心力代码如下所示:

var forceCenterSplit = d3.forceCenter(function(d) {
            if (d[splitParameter] >= splitVal)
                return 3*width/4;
            else
                return width/4;
        }, height/2)

为了比较,这里是 forceX 的代码,它完成了同样的事情:

var forceXsplit = d3.forceX(function(d) {
                if (d[splitParameter] >= splitVal)
                    return 3*width/4;
                else
                    return width/4;
            }).strength(.05);    

不幸的是,当我 运行 居中力并将所有数据推送到 cx = 0(默认值)时,控制台显示 "Unexpected value NaN parsing cx attribute."。

我是不是漏掉了一些基本的东西?能不能不给定心力传一个匿名函数作为参数?如果没有,有更好的方法吗?

谢谢!

// nicer looking splitting forces that use forceCenter
        var forceCenterCombine = d3.forceCenter(width/2, height/2);

        var forceCenterSplit = d3.forceCenter(function(d) {
            if (d[splitParameter] >= splitVal)
                return 3*width/4;
            else
                return width/4;
        }, height/2);

        // simple splitting forces that only use forceX
        var forceXSplit = d3.forceX(function(d) {
            if (d[splitParameter] >= splitVal)
                return 3*width/4;
            else
                return width/4;
        }).strength(.05);

        var forceXCombine = d3.forceX(width/2).strength(.05);

        // collision force to stop the bubbles from hitting each other
        var forceCollide = d3.forceCollide(function(d){
            console.log("forceCollide");
            return radiusScale(d[radiusParam]) + 1;
        }).strength(.75)

        // This code is for the simulation that combines all the forces
        var simulation = d3.forceSimulation()
            .force("center", forceCenterCombine)
            .force("collide", forceCollide)
            .on('end', function(){console.log("Simulation ended!");});

        function ticked() {
            circles
                .attr("cx", function(d){
                    return d.x;
                })
                .attr("cy", function(d){
                    return d.y;
                })
        }

var splitFlag = false;

        // dynamically divide the bubbles into two (or probably more later on) groups
        $scope.split = function() {
            // split them apart
            if (!splitFlag){
                console.log("splitForce");
                simulation.force("center", forceXSplit)
                    .force("y", d3.forceY(height/2).strength(.05))
                    .alphaTarget(.25)
                    .restart();
                splitFlag = true;
            }
            // bring them back together
            else {
                console.log("combineForce");
                simulation.force("center", forceCenterCombine)
                    .alphaTarget(.25)
                    .restart();
                splitFlag = false;
            }
        };

很遗憾,答案似乎是

由于 d3.forceCenter 的本质,("pass an anonymous function as a parameter") 是不可能的。 API 表示:

The centering force translates nodes uniformly so that the mean position of all nodes (the center of mass if all nodes have equal weight) is at the given position ⟨x,y⟩. (emphasis mine)

因此,这里没有 space 访问函数。 forceXforceY,另一方面...

set the coordinate accessor to the specified number or function. (emphasis mine again)

...可能最适合您。