代码之家  ›  专栏  ›  技术社区  ›  Nikhil Das Nomula

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

  •  0
  • Nikhil Das Nomula  · 技术社区  · 7 年前

    我有一个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 回复  |  直到 7 年前
        1
  •  0
  •   Nikhil Das Nomula    7 年前

    正如@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;
                }));
        }