首页 > 解决方案 > 如何通过半径大小将节点定位在中心?

问题描述

我想通过圆的大小使力导向图中的节点居中:我们希望最大的圆居中,下一个最大的圆围绕它。

这是 JSFiddle:https ://jsfiddle.net/5zrxgteh/1/

以下是模拟和刻度函数:

 var simulation = d3.forceSimulation()
            .force("center", d3.forceCenter().x(width / 2).y(height / 2))
            .force("charge", d3.forceManyBody().strength(5))
            .force("collide", d3.forceCollide().strength(1).radius(function (d) {
                return rScale(d.value * 1.2);
            }).iterations(3));

 simulation
            .nodes(data)
            .on("tick", function (d) {
                elemEnter.selectAll(".pulse")
                    .attr("cx", function (d) {
                        return d.x = Math.max(50, Math.min(width - 50, d.x));
                    })
                    .attr("cy", function (d) {
                        return d.y = Math.max(50, Math.min(height - 50, d.y));
                    });

                elemEnter.selectAll(".circle")
                    .attr("cx", function (d) {
                        return d.x = Math.max(50, Math.min(width - 50, d.x));
                    })
                    .attr("cy", function (d) {
                        return d.y = Math.max(50, Math.min(height - 50, d.y));
                    });

                elemEnter.selectAll("text")
                    .attr("x", function (d) {
                        return d.x = Math.max(50, Math.min(width - 50, d.x));
                    })
                    .attr("y", function (d) {
                        return d.y = Math.max(50, Math.min(height - 50, d.y));
                    });
            });

标签: javascriptd3.jsforce-layout

解决方案


如果你停下来认为你想要的东西在数学和视觉上都很复杂,因为如果最大的圆靠近中心并且到中心的距离与圆的直径成正比,那么接下来你会有很多空白到中心,模拟不会很好地处理它。

然而,只是为了尝试,这是一个可能的解决方案:放弃d3.forceCenter并使用forceXforceY而是根据圆圈的大小调整它们的强度。

为此,我们首先设置了一个规模:

var strengthScale = d3.scalePow()
    .exponent(2)
    .range([0, 1])
    .domain([0, d3.max(data, function(d) {
        return d.value;
    })]);

然后,我们改变模拟:

var simulation = d3.forceSimulation()
    .force("x", d3.forceX(width / 2).strength(function(d) {
      return strengthScale(d.value);
    }))
    .force("y", d3.forceY(height / 2).strength(function(d) {
      return strengthScale(d.value);
    }))
    .force("charge", d3.forceManyBody().strength(5))
    .force("collide", d3.forceCollide().strength(1).radius(function(d) {
      return rScale(d.value * 1.2);
    }).iterations(30));

这是生成的 JSFiddle:https ://jsfiddle.net/mea9nygb/2/


推荐阅读