【问题标题】:D3js Force Layout barrier and fall inD3js强制布局障碍并落入
【发布时间】:2015-07-04 02:19:43
【问题描述】:

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

我正在尝试的方法是使用绝对位置将 SVG 覆盖在 div 的顶部,并尝试让节点在刻度函数中避开它。事实证明这是非常困难的。还有另一种方法吗?如果没有,我将非常感谢您指出正确的方向!

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

我已附上我的 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;
}

【问题讨论】:

    标签: javascript css d3.js svg


    【解决方案1】:

    边界

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

    落入

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

    【讨论】:

    • 这真的很有帮助。你有什么建议可以打破碰撞逻辑是最直接的吗?据我了解,您返回代表 x 或 y 变化的 dx 或 dy 值。就目前而言,它有点像链子,但添加一两个链子有点压倒性。我正在努力解决多种碰撞情况,并担心球最终可能会在边界之间弹跳
    • @willium,不确定您的意思:您还在谈论边界吗?通过链接,您的意思是边界案例与collide 案例有某种链接?是这个意思吗?
    • 我们可以在你的要点上聊一聊...我在那里添加了评论。
    猜你喜欢
    • 2019-05-06
    • 1970-01-01
    • 2017-10-01
    • 2019-09-02
    • 2018-12-26
    • 2014-02-15
    • 2016-11-13
    • 2019-01-08
    • 2015-12-04
    相关资源
    最近更新 更多