【问题标题】:Avoid D3js circles overlap within multiple clusters and increasing node radius in D3 v5避免 D3js 圆圈在多个集群中重叠并在 D3 v5 中增加节点半径
【发布时间】:2019-01-26 06:43:50
【问题描述】:

我有一个包含多个集群的 D3 可视化,我使用重力函数将所有圆圈都移到焦点的中心。然而,有了这个,圆圈是重叠的。

我尝试将这个块 https://bl.ocks.org/mbostock/3231298 转换为 V5,但我无法让它工作。

我使用负电荷来排斥节点,显然当我在tick中调用重力函数时,它会将代码带到集群焦点的中心

force = d3.forceSimulation(nodes)
            .force('charge', d3.forceManyBody(-100))
            .force('collision', d3.forceCollide().radius(function (d) {
                return 1.1*d.radius;
            }))
            .on('tick', tick);
        force.alpha(0.01);
        force.alphaDecay = 0.1;
        force.alphaTarget(.001);


        force.force('x', d3.forceX().x(function (d) {
            return foci[d.choice].x;
        }))


        force.force('y', d3.forceY().y(function (d) {
            return foci[d.choice].y;
        }))

        console.log(JSON.stringify(foci));

        // Draw circle for each node.
        circle = svg.selectAll("circle")
            .data(nodes)
            .enter().append("circle")
            .attr("id", function (d) {
                return d.id;
            })
            .attr("class", "node")
            .style("stroke", "black");
            ;


        // For smoother initial transition to settling spots.
        // Need to research more on this
        circle.transition()
            .duration(100)
            .delay(function (d, i) {
                return i * 5;
            })
            .attrTween("r", function (d) {
                var i = d3.interpolate(0, d.radius);
                return function (t) {
                    return d.radius = i(t);
                };
            });
function tick(e) {
        circle
            .each(collide(0.5))
            .each(gravity(.051 * .8))
            .style("fill", function (d) {
                //category is either 0 or 1
                //so it's either 0+the choice or 6+the choice
                //d.choice is between 0 and 5
                multiplier = d.category

                return colors[foci_count * multiplier + d.choice];
            })
            .attr("cx", function (d) {
                return d.x;
            })
            .attr("cy", function (d) {
                return d.y;
            })
            .attr("r", function(d) {
                return d.radius;
            })

            ;
    }

function collide(alpha) {
            var quadtree = d3.quadtree().addAll(nodes);

            return function (d) {
                // var r = d.radius + maxNodeRadius + Math.max(padding, clusterPadding),
                var r = d.radius + 10,
                    nx1 = d.x - r,
                    nx2 = d.x + r,
                    ny1 = d.y - r,
                    ny2 = d.y + r;



                 quadtree.visit(function (quad, x1, y1, x2, y2) {
                    console.log("visit")
                    if (quad.point && (quad.point !== d)) {
                        var x = d.x - quad.point.x,
                            y = d.y - quad.point.y,
                            l = Math.sqrt(x * x + y * y),

                            r = d.radius + quad.point.radius + 10;

                        console.log(d.cluster);

                        if (l < r) {
                            l = (l - r) / l * alpha;
                            d.x -= x *= l;
                            d.y -= y *= l;
                            quad.point.x += x;
                            quad.point.y += y;
                        }
                    }
                    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
                });
            };
        }


      // Move nodes toward cluster focus.
     function gravity(alpha) {
        return function (d) {
            d.y += (foci[d.choice].y - d.y) * alpha;
            d.x += (foci[d.choice].x - d.x) * alpha;
        };
     }

【问题讨论】:

  • 为什么会有碰撞力,你叫碰撞在滴答声中? d3v5有重力。发挥力量的力量,如果重力大于碰撞,你就会重叠
  • 我之所以在tick中调用collision是因为tick函数会更新节点的半径。而且我不希望圆圈在那段时间重叠。
  • 然后用更新的节点重新初始化碰撞力
  • 啊,是的,我正在尝试让它与使用四叉树的现有示例(使用 d3 v3)一起工作。感谢您为我指明正确的方向!

标签: d3.js


【解决方案1】:

正如@rioV8 所提到的,我需要做的就是用更新的节点重新初始化碰撞力。所以我将我的刻度函数更新为以下

 function tick(e) {
        circle

            .each(gravity(.051 * .8))
            .style("fill", function (d) {
                //category is either 0 or 1
                //so it's either 0+the choice or 6+the choice
                //d.choice is between 0 and 5
                multiplier = d.category

                return colors[foci_count * multiplier + d.choice];
            })
            .attr("cx", function (d) {
                return d.x;
            })
            .attr("cy", function (d) {
                return d.y;
            })
            .attr("r", function(d) {
                return d.radius;
            });


            force.force('collision', d3.forceCollide().radius(function (d) {
                return 1.3 * d.radius;
            }));
    }

【讨论】:

  • 为什么还要为collidegravity打电话给each
  • 对不起,我忘了删除每个碰撞的调用。我需要重力,以便我可以强制节点集中在集群的中心
猜你喜欢
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-04
  • 2021-08-18
  • 1970-01-01
  • 2013-10-29
  • 1970-01-01
相关资源
最近更新 更多