避免D3js圆在多个群集中重叠并避免在D3 v5中增加节点半径

时间:2019-01-26 06:43:51

标签: d3.js

我有一个包含多个聚类的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;
        };
     }

1 个答案:

答案 0 :(得分:0)

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

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