D3.js: pass an anonymous function as a parameter for centering?

I am making an interactive bubble chart, and I am working on functionality to divide the data into two groups that move to opposite sides of the screen. I use centering force for modeling, because I think it gives a much nicer and more consistent display of data than using forceX and forceY. However, I am having problems splitting my data.

I had the idea that since you can pass an anonymous function as a forceX parameter to determine if the node moves left or right, theoretically you can do the same for the value of x in the centering force. My central power code looks like this:

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

For comparison, here is the code for forceX that does the same thing:

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

Unfortunately, the console says "Unexpected NaN value for parsing the cx attribute." when I start the centering force and push all the data to cx = 0 (default value).

Did I miss something basic here? Can you pass an anonymous function as a parameter of the centering force? If not, is there a better way to do this?

Thank!

Start state

After the split

// 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;
            }
        };

enter image description here

+4
source share
1 answer

Unfortunately, the answer seems no .

Due to nature itself d3.forceCenter, that ("passing an anonymous function as a parameter") is impossible. API says:

, ( , ) ⟨x, y⟩. ( )

, . forceX forceY, ...

. ( )

... .

+2

Source: https://habr.com/ru/post/1667719/


All Articles