javascript - D3js Force Layout barrier 和 fall in

标签 javascript css d3.js svg

我正在做力布局。我已经在 svg 中实现了碰撞和边界(我不想使用重力)。但是,现在我想在中间放置一个 div 并让节点避开它。

我正在尝试的方法是使用绝对位置将 SVG 叠加在 div 之上,并尝试让节点在 tick 函数中避开它。这被证明是非常困难的。还有另一种方法吗?如果没有,我将不胜感激指出正确的方向!

作为次要问题,我希望节点从顶部落入。再一次,我没有引力,所以我不确定如何处理它。我希望他们保持间距,所以我认为焦点可能不起作用。

我附上了我的 Javascript 和 CSS 代码!

提前致谢。

    width = parseInt(d3.select('#canvas').style('width'), 10),
    height = parseInt(d3.select('#canvas').style('height'), 10),
    padding = 30, // separation between circles
    radius = 70;

    //Set up the force layout
    var force = d3.layout.force()
        .gravity(0)
        .charge(0)
        .size([width, height]);

    //Append a SVG to the body of the html page.
    //Assign this SVG as an object to svg
    var svg = d3.select("#canvas").append("svg")
        .attr("width", width)
        .attr("height", height);

    //Read the data
    d3.json("dots.json", function(error, graph) {
        if (error) throw error;

        //Creates the graph data structure out of the json data
        force.nodes(graph.nodes)
            .start();


        //Do the same with the circles for the nodes - no
        var node = svg.selectAll(".node")
            .data(graph.nodes)
        .enter().append("g")
            .attr("class", "node")
            .call(force.drag);

        node.append("circle")
          .attr("r", radius)
            .style("fill", "black")
          .call(force.drag);

        node.append("text")
          .attr("dx", 0)
          .attr("dy", 5)
          .attr("height", 10)
          .attr("text-anchor", "middle")
          .text(function(d) { return d.name })
          .style("fill", "white");


        //Now we are giving the SVGs co-ordinates - the force layout
        //is generating the co-ordinates which this code is using to
        //update the attributes of the SVG elements
        force.on("tick", function (e) {

            node.attr("cx", function(d) {
                return d.x =
                Math.max(
                    radius,
                    Math.min(
                        width - radius,
                        d.x
                    )
                );
            }).attr("cy", function(d) {
                return d.y = Math.max(radius, Math.min(height - radius, d.y));
            });

              node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });


            node.each(collide(0.5)); //Added
        });

        function collide(alpha) {
          var quadtree = d3.geom.quadtree(graph.nodes);
          return function(d) {
            var rb = 2*radius + padding,
                nx1 = d.x - rb,
                nx2 = d.x + rb,
                ny1 = d.y - rb,
                ny2 = d.y + rb;

            quadtree.visit(function(quad, x1, y1, x2, y2) {
              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);
                  if (l < rb) {
                  l = (l - rb) / 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;
            });
          };
        }

        node.on("mousedown", function(d1, i) {
            var $this = d3.select(this);
            if(node.active) {
                $this = $this.transition()
                    .duration(1000)
                    .attr("stroke-width", 0)
                    .attr("r", radius);

                node.active = false;
            } else {
                $this = $this.transition()
                    .duration(1000)
                    .attr("stroke-width", 20)
                    .attr("stroke", "4DD2B6")
                    .attr("fill", "white")
                    .attr("r", radius * 2)
            }
        });

    });



#canvas, #playground {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1;
    overflow: visible;
    display: block;
}

#playground {
    height: 100%;
}

header {
    width: 320px;
    margin: 100px auto 50px;
    display: block;
    z-index: 10;
    background-color: red;
}

screen

最佳答案

边界

碰撞检测的难点在于每个节点都可能与任何其他节点发生碰撞,这就是为什么使用四叉树来减少排列的原因。当你谈论边界时,它更直接,因为只有一个边界。在您的情况下,您需要做的就是扩展边界的几何形状以包括遮挡。

陷入困境

这完全取决于您的意思,但是您可以将初始 cx/cy 值设置为您希望它们从中发出的源,然后扩展您的边界行为以包括如果节点在 svg 之外时要做什么.因此,这将是某种自定义重力,可以根据当前位置和您希望它们落入的方向确定下一个 cx/cy。同时,碰撞例程不知道边界,因此它将负责保持节点当它们掉落时分开。

关于javascript - D3js Force Layout barrier 和 fall in,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31197742/

相关文章:

javascript - 使用 REST api 解析未经授权的注销 401

javascript - 正则表达式文本中包含超过 1 个大写字符的所有单词

javascript - 使用 mouseenter 水平翻译,mouseleave 功能不起作用

html - 当尝试在其下方放置一个 div 覆盖内容时,它不会覆盖,只是将内容向下推

javascript - 在多焦点 d3 力布局中重新定位节点

javascript - 如何将数组打印到屏幕上? SVG/D3/JS

javascript - Jquery 追加 div 到新的 div

javascript - 如何以美观的方式将 <select> 和 &lt;input&gt; 结合起来?

html - 将图像放在无序列表框中

javascript - 仅在轴的起点和终点刻度